Processes and Threads
When the first of an application's components needs to be run, Android starts a Linux process for it with a single thread of execution. By default, all components of the application run in that process and thread.
However, you can arrange for components to run in other processes, and you can spawn additional threads for any process.
Application의 component들 중에 어느 하나가 처음에 시작 되야 할 때, android는 process(single thread)를 실행시킨다. 기본적으로 그 app의 모든 component는 그 process와 thread에서 동작한다. 그러나 component들이 다른 process에서 동작하게 할 수 있고, Thread를 추가 생성 할 수도 있다.
Processes
The process where a component runs is controlled by the manifest file. The component elements — <activity>, <service>, <receiver>, and <provider> — each have a process attribute that can specify a process where that component should run. These attributes can be set so that each component runs in its own process, or so that some components share a process while others do not. They can also be set so that components of different applications run in the same process — provided that the applications share the same Linux user ID and are signed by the same authorities. The <application> element also has a process attribute, for setting a default value that applies to all components.
Component가 실행되는 process는 manifest file에서 제어한다. 각각의 component들이 자신이 실행되야 하는 process를 기술 할 수 있다는 것이다. Manifest파일 안에 있는 <activity>, <service>, <receiver>, <provider> 는 각각 process라는 attribute가 있는데 이를 설정하면 된다. 각각의 component는 각자만의 process에서만 동작할 수도 있고, 어떤 component들은 하나의 process를 공유하고, 반면 다른 component들은 그렇게 하지 않을 수도 있다. 또한 다른 application의 component들이 동일한 process를 공유하게 설정할 수도 있다. 이렇게 하기 위해서는 서로 다른 application들이 동일한 linux user id를 갖고 똑같은 권한을 갖도록 서명되어져야 한다. 그리고 <application>이란 element안에 process라는 attribute가 있는데, 이는 모든 component에게 default value를 설정한다.
All components are instantiated in the main thread of the specified process, and system calls to the component are dispatched from that thread. Separate threads are not created for each instance. Consequently, methods that respond to those calls — methods like View.onKeyDown() that report user actions and the lifecycle notifications discussed later in the Component Lifecycles section — always run in the main thread of the process. This means that no component should perform long or blocking operations (such as networking operations or computation loops) when called by the system, since this will block any other components also in the process. You can spawn separate threads for long operations, as discussed under Threads, next.
Android may decide to shut down a process at some point, when memory is low and required by other processes that are more immediately serving the user. Application components running in the process are consequently destroyed. A process is restarted for those components when there's again work for them to do.
모든 component들은 지정된 process의 main thread에서 instance화 된다. Component에 대한 system call들은 main thread로 부터 dispatch된다. 각각의 thread들은 각각의 component instance가 생성 하는 게 아니다. 결론적으로 system call에 대한 응답 method(View.onKeyDown()같은)이나 lifecycle notification은 항상 지정된 process의 main thread안에서 동작한다. 이것은 system이 component를 호출할 때, component가 long operation 이나 blocking operation을 할 수 없다는 것이다. Long and block operation은 process안에 있는 다른 component를 block시키기 때문이다. Long operation의 경우는 thread를 별도로 만들어 수행 시킬 수 있다. Android는 메모리가 불충분 하거나, 다른 process를 즉시 처리해야 할 경우 process들을 shut down시킬 수 있다. Process가 shut down되면 그 안에 있는 component들은 결론적으로 없어진다. Component가 해야할 일이 있을 경우, process는 재시작 한다.
When deciding which processes to terminate, Android weighs their relative importance to the user. For example, it more readily shuts down a process with activities that are no longer visible on screen than a process with visible activities. The decision whether to terminate a process, therefore, depends on the state of the components running in that process. Those states are the subject of a later section, Component Lifecycles.
Android가 종료할 process를 결정하는것은 user에게 있어의 중요성을 생각한다. 예를 들면, 화면에 보여지는 activity를 가진 process보다 화면에 보이지 않는 activity를 종료하는 것이 훨씬 쉽다. 따라서 process의 종료 여부는 process내의 component들의 running status에 달려있다고 보면 된다. Component들의 state는 Component Lifecycle에서 살펴보겠다.
Threads
Even though you may confine your application to a single process, there will likely be times when you will need to spawn a thread to do some background work. Since the user interface must always be quick to respond to user actions, the thread that hosts an activity should not also host time-consuming operations like network downloads. Anything that may not be completed quickly should be assigned to a different thread.
Threads are created in code using standard Java Thread objects. Android provides a number of convenience classes for managing threads — Looper for running a message loop within a thread, Handler for processing messages, and HandlerThread for setting up a thread with a message loop.
너가 app를 single process로 제한을 했다 할지라도, background의 어떤 작업을 수행하기 위해서 thread를 생성할 필요가 있을것이다. 왜냐하면 user interface라는 것은 사용자의 반응에 즉시 응답해야 하기 때문에 activity를 가지고 있는 thread는 네트웍 다운로드와 같은 시간을 소비하는 작없을 하면 안되기 때문이다. 그래서 즉시 완료될 수 없는 작업들에게 thread를 할당 해야 한다. Thread는 standard java language를 사용해서 만든다. 이런 thread를 관리하기 위해 android는 많은 편리한 class들을 제공한다. Thread내에서 message loop를 동작하기위한 Looper라던지, message의 처리를 위한 handler, message loop를 갖는 thread를 세팅하는 HandlerThread가 있다.
Remote procedure calls
Android has a lightweight mechanism for remote procedure calls (RPCs) — where a method is called locally, but executed remotely (in another process), with any result returned back to the caller. This entails decomposing the method call and all its attendant data to a level the operating system can understand, transmitting it from the local process and address space to the remote process and address space, and reassembling and reenacting the call there. Return values have to be transmitted in the opposite direction. Android provides all the code to do that work, so that you can concentrate on defining and implementing the RPC interface itself.
Android는 RPC를 위해 lightweight mechanism을 가지고 있다. RPC는 내부에서 호출되지만 실행은 원격에서 되는 method이다. 원격은 다른 process라고 봐도 된다. 그리고 return값이 존재한다. RPC는 method call과 data를 운영체제가 이해하는 선에서 분석해야 하고 local process와 주소공간에 있는 call을 원격 process와 주소공간으로 보내야 하고, 원격에서 그 call을 조합하고 실행한다. Return 값은 반대편으로 전송 되야 한다. Android에서 이 모든 작업은 code로 이루어 진다. 따라서 RPC interface를 선언하고 구현하는 것을 집중해서 봐야 한다.
An RPC interface can include only methods. All methods are executed synchronously (the local method blocks until the remote method finishes), even if there is no return value.
한 개의 RPC interface는 단지 method들만 가지고 있을 수가 있다. 모든 method들은 동기적으로 수행된다. Remote method가 종료 될때 까지 local method는 block된다. 이건 return값이 없을지라도...그렇다.
In brief, the mechanism works as follows: You'd begin by declaring the RPC interface you want to implement using a simple IDL (interface definition language). From that declaration, the aidl tool generates a Java interface definition that must be made available to both the local and the remote process. It contains two inner class, as shown in the following diagram:
요약하면, 메커니즘은 다음과 같이 동작한다. RPC interface를 선언을 하고 그것을 IDL을 사용해서 구현한다. 선언은 AIDL툴을 local과 remote process에서 사용 가능한 java interface definition을 만들어 낸다. Java interface definition은 2개의 inner class를 가지고 있는데, 아래의 diagram과 같다.

The inner classes have all the code needed to administer remote procedure calls for the interface you declared with the IDL. Both inner classes implement the IBinder interface. One of them is used locally and internally by the system; the code you write can ignore it. The other, called Stub, extends the Binder class. In addition to internal code for effectuating the IPC calls, it contains declarations for the methods in the RPC interface you declared. You would subclass Stub to implement those methods, as indicated in the diagram.
IDL을 사용해서 interface를 작성할 수 있다고 했다. Interface라는 것은 선언만 되어있는 함수의 모임이라고 볼 수 있다. Inner class에는 그런 function을 관리하는 모든 code를 가지고 있다. 두 개의 inner class는 Ibinder라는 interface를 구현했다. 둘 중 하나는 내부적으로 system에 의해 사용된다. 그리고 다른 하나는 stub이라고 부르는데 binder라는 class를 extend했다. 이게 다른것은 RPC를 위한 interface의 함수 뿐만 아니라, IPC에 대한 code도 있기 때문이다. Stub inner class는 이 모든 함수를 구현해야 한다.
Typically, the remote process would be managed by a service (because a service can inform the system about the process and its connections to other processes). It would have both the interface file generated by the aidl tool and the Stub subclass implementing the RPC methods. Clients of the service would have only the interface file generated by the aidl tool.
일반적으로, remote process들은 service에 의해 관리 된다. (왜냐하면, service가 system에게 원격 process의 정보, 다른 process들의 연결 상태를 system에게 알려줄 수 있기 때문이다. Service는 두개의 interface file(aidl툴로 만들어진)과 stub sub class를 가져야한다. 즉 service가 server의 역할을 한다. Client는 단지 interface file만 가지고 있으면 된다.
Here's how a connection between a service and its clients is set up:
아래는 service와 client가 사이에 연결하는 방법이다.
- Clients of the service (on the local side) would implement onServiceConnected() and onServiceDisconnected() methods so they can be notified when a successful connection to the remote service is established, and when it goes away. They would then call bindService() to set up the connection.
Service의 client쪽에서는 onServiceConnect()와 onServiceDisconnected()를 구현해 놓아야 한다. 그래야 연결여부에 대한 notification을 받을 수 있다. 그리고 연결을 위해 client가 호출하는 함수는 bindService()이다.
- The service's onBind() method would be implemented to either accept or reject the connection, depending on the intent it receives (the intent passed to bindService()). If the connection is accepted, it returns an instance of the Stub subclass.
Service에는 onBind()가 있어서 연결을 받을지 말지를 결정을 구현해 놔야 한다. 이것에도 mechanism이 있다. Service를 요구하는 client에서 intent객체를 만들고 bindService()로 이 intent를 전달하면 server쪽에서 onBind()에서 그 intent를 처리하는 방식이다. 만일 연결이 되면 server service에서 stub객체를 return한다.
- If the service accepts the connection, Android calls the client's onServiceConnected() method and passes it an IBinder object, a proxy for the Stub subclass managed by the service. Through the proxy, the client can make calls on the remote service.
만일 service가 connection을 수락하면, android는 client의 onServiceConnected()를 호출하고 stub객체를 전달한다. 이 stub객체는 IBinder타입의 객체이며, 또한 client의 proxy가 된다. 따라서 client는 이 proxy를 사용해서 server의 function을 원격에서 호출 할 수 있다는 것이다. 원격 호출의 장점은 process와 process간의 간단한 data전달이 아니라...간단한 data의 전달은 socket을 이용한 채팅 처럼 data를 전송하는게 아니라..function을 호출한다는게 대단한 기술이다. 이 말은 원격의 cpu를 사용한다고 볼 수 있기 때문이다.
This brief description omits some details of the RPC mechanism. For more information, see Designing a Remote Interface Using AIDL and the IBinder class description.
여기서는 RPC 메커니즘에 대해 간략히 다루었다. Designing a Remote Interface Using AIDL과 Ibinder에서 더 자세히 설명하겠다.
Thread-safe methods
In a few contexts, the methods you implement may be called from more than one thread, and therefore must be written to be thread-safe.
This is primarily true for methods that can be called remotely — as in the RPC mechanism discussed in the previous section. When a call on a method implemented in an IBinder object originates in the same process as the IBinder, the method is executed in the caller's thread. However, when the call originates in another process, the method is executed in a thread chosen from a pool of threads that Android maintains in the same process as the IBinder; it's not executed in the main thread of the process. For example, whereas a service's onBind() method would be called from the main thread of the service's process, methods implemented in the object that onBind() returns (for example, a Stub subclass that implements RPC methods) would be called from threads in the pool. Since services can have more than one client, more than one pool thread can engage the same IBinder method at the same time. IBinder methods must, therefore, be implemented to be thread-safe.
어떤 context에서, method는 하나 이상의 thread로 부터 호출될 수 있다. 그래서 method는 thread-safe되어야 한다. 원격에서 호출될 수 있는 method는 특히 더 그러하다. Ibinder를 구현한 객체의 method가 동일한 process내에서 호출될 때 그 method는 caller의 thread에서 실행된다. 그러나, Ibinder를 구현한 객체의 method가 다른 process에서 호출되면, android가 관리하는 thread pool에서 선택된 thread에서 실행이 이루어진다. 즉 그 process의 main thread에서 실행되지 않는다는 것이다. 예를 들면, service의 onBind()는 service의 main thread에서 동작하는 반면, onBind()가 return하는 객체-> stub을 구현한 instance의 method는 pool안에 있는 thread에서 실행된다. Service들은 여러 개의 client를 가질 수 있다. 따라서 한 개 이상의 pool thread들이 Ibinder의 method를 동시에 호출이 가능하게 된다. 따라서 Ibinder의 method들은 thread-safe되야 하는 것이다.
Similarly, a content provider can receive data requests that originate in other processes. Although the ContentResolver and ContentProvider classes hide the details of how the interprocess communication is managed, ContentProvider methods that respond to those requests — the methods query(), insert(), delete(), update(), and getType() — are called from a pool of threads in the content provider's process, not the main thread of the process. Since these methods may be called from any number of threads at the same time, they too must be implemented to be thread-safe.
Content Provider 역시 다른 process에서 시작된 data요청을 받을 수 있다. Content Resolver와 Content Provider의 class는 process간의 communication이 어떻게 되는지에 대한 세부 사항들은 숨겨져 있음에도 불구하고, data 요청에 응답하는 contentResolver의 method들 예를 들면, query(), insert(), delete(), update() getType()은 Content Provider process의 pool thread에 의해 호출 된다. Main thread에서 호출 되지 않는 다는 것이다. 따라서 이 method들은 동시에 호출될 수 있기 때문에 thread-safe되야 한다.
Component Lifecycles
Application components have a lifecycle — a beginning when Android instantiates them to respond to intents through to an end when the instances are destroyed. In between, they may sometimes be active or inactive,or, in the case of activities, visible to the user or invisible. This section discusses the lifecycles of activities, services, and broadcast receivers — including the states that they can be in during their lifetimes, the methods that notify you of transitions between states, and the effect of those states on the possibility that the process hosting them might be terminated and the instances destroyed.
App의 component들은 lifecycle을 가지고 있다. Android가 intent의 응답으로 component를 instance화하면서 component는 태어나고 instance들이 파괴되면서 끝나게 된다. 생성과 종료 사이에도 많은 상태를 갖게 된다. Active하냐 inactive하냐..만약 active하다면, 사용자에게 visible한가 invisible한가..등등.. 이번 section에서는 activity와 service, broadcast receiver의 lifecycle에 대해 논의한다. 세부적으로는 component들이 lifetime동안의 존재하고 있는 상태, 이런 상태가 변경될 때 알려주는 method들, 그리고 그런 component를 소유하는 process가 종료 될때 미치는 상태들을 살펴본다.
Activity lifecycle
An activity has essentially three states:
Activity는 필수적으로 3가지 상태를 가진다.
- It is active or running when it is in the foreground of the screen (at the top of the activity stack for the current task). This is the activity that is the focus for the user's actions.
Active(running) : screen에 foreground에 있을 때(stack에서는 top) 이것은 activity가 user의 focus를 받고 있다고 보면 된다.
- It is paused if it has lost focus but is still visible to the user. That is, another activity lies on top of it and that activity either is transparent or doesn't cover the full screen, so some of the paused activity can show through. A paused activity is completely alive (it maintains all state and member information and remains attached to the window manager), but can be killed by the system in extreme low memory situations.
Paused : 사용자의 focus는 잃었으되 여전히 사용자에게 visible하다. Focus를 잃었는데 어떻게 사용자에게 보여지는가? 모순일거라고 생각할 수 있지만 가능하다. 사용자의 focus를 받는 activity가 transparent로 되어 있거나 완전히 아래 activity를 덮지 않을 경우, 아래 activity는 user에게 visible할 수 있지 않는가? Pause된 activity는 완전히 alive하다. 이말은 activity가 모든 상태와 member정보를 유지하고 window manager가 연결 되어 있다. 하지만 system이 메모리가 부족할 때 이 상태의 activity는 종료 시킬 수 있다.
- It is stopped if it is completely obscured by another activity. It still retains all state and member information. However, it is no longer visible to the user so its window is hidden and it will often be killed by the system when memory is needed elsewhere.
Stopped : activity가 완전히 다른 activity에 의해 가리워지면 stopped 된 상태다. Stopped된 상태에서도 여전히 모든 state를 가지며 member들의 정보도 가지고 있다. 그러나, 사용자에게 더 이상 보여지지 않는다. 그래서 window는 숨겨져 있고 종종 system에 메모리가 필요할 때 이 activity를 kill한다.
If an activity is paused or stopped, the system can drop it from memory either by asking it to finish (calling its finish() method), or simply killing its process. When it is displayed again to the user, it must be completely restarted and restored to its previous state.
System이 memory가 부족하면, pause나 stopped된 activity를 제거한다. 제거할 때는 finish()로 종료하겠다고 묻거나 간단히 process를 kill한다. Activity가 user에 의해 다시 보여질 때, activity는 완전히 다시 시작 해야하고 이전의 상태는 저장된다.
As an activity transitions from state to state, it is notified of the change by calls to the following protected methods:
Activity의 상태가 변화가 되면, 아래 protected method에 공지된다.
void onCreate(Bundle savedInstanceState)
void onStart()
void onRestart()
void onResume()
void onPause()
void onStop()
void onDestroy()
All of these methods are hooks that you can override to do appropriate work when the state changes. All activities must implement onCreate() to do the initial setup when the object is first instantiated. Many will also implement onPause() to commit data changes and otherwise prepare to stop interacting with the user.
State가 변할 때 이 method는 호출된다. 그리고 이 method들은 override할 수 있다. onCreate()는 반드시 구현해야하고 또한 onPause()도 구현하자.
Calling into the superclass
An implementation of any activity lifecycle method should always first call the superclass version. For example:
protected void onPause() {
super.onPause();
. . .
}
Taken together, these seven methods define the entire lifecycle of an activity. There are three nested loops that you can monitor by implementing them:
Activity lifecycle method들은 항상 제일 먼저 super class의 method를 먼저 수행하게 구현되어야 한다. 3개의 중첩loop가 있는데, super class의 method를 위와 같이 구현했을 때 monitoring이 가능하다.
The entire lifetime of an activity happens between the first call to onCreate() through to a single final call to onDestroy(). An activity does all its initial setup of "global" state in onCreate(), and releases all remaining resources in onDestroy(). For example, if it has a thread running in the background to download data from the network, it may create that thread in onCreate() and then stop the thread in onDestroy().
Activity의 전체 lifetime은 onCreate()로 시작해서 onDestroy()로 끝이 난다. OnCreate()에서 activity는 "global" state에서 모든 초기화를 수행한다. 그리고 onDestroy()에서 모든 resource를 반환한다. 예를 들어 activity가 thread를 가지고 있다면, activity는 onCreate()로 그 thread를 생성하고 onDestroy()로 그 thread를 stop할 수 있다. Activity가 thread를 가지고 있다는 것을 어떻게 해석 해야 하는가?
- The visible lifetime of an activity happens between a call to onStart() until a corresponding call to onStop(). During this time, the user can see the activity on-screen, though it may not be in the foreground and interacting with the user. Between these two methods, you can maintain resources that are needed to show the activity to the user. For example, you can register a BroadcastReceiver in onStart() to monitor for changes that impact your UI, and unregister it in onStop() when the user can no longer see what you are displaying. The onStart() and onStop() methods can be called multiple times, as the activity alternates between being visible and hidden to the user.
Visible lifetime은 activity가 onStart()로 시작해서 onStop()로 끝이 난다. 이 기간 동안 사용자는 activity를 화면으로 볼 수 있다. Activity가 foreground에 있지 않거나, user와 interaction이 없어도..activity는 화면에 볼 수 있는 상태라는 것인데…좀 이해가 안된다. 이 두 method사이에 있을 때는 activity는 user에게 보여줄 화면에 대해 resource를 유지하고 있다. 예를 들어, onStart()내에서 BroadcastReceiver를 등록할 수 있다. 이것은 activity의 UI를 monitor하기 위해서 이다. 그리고 onStop()내에 등록을 해지하는 코드를 넣을 수 있다. 이것은 사용자가 더 이상 activity의 화면을 보고 싶지 않을 때이다. onStart()와 onStop()는 여러 번 호출이 가능하다.
- The foreground lifetime of an activity happens between a call to onResume() until a corresponding call to onPause(). During this time, the activity is in front of all other activities on screen and is interacting with the user. An activity can frequently transition between the resumed and paused states — for example, onPause() is called when the device goes to sleep or when a new activity is started, onResume() is called when an activity result or a new intent is delivered. Therefore, the code in these two methods should be fairly lightweight.
The following diagram illustrates these loops and the paths an activity may take between states. The colored ovals are major states the activity can be in. The square rectangles represent the callback methods you can implement to perform operations when the activity transitions between states.
Activity의 foreground lifetime은 onResume()로 시작해서 onPause()로 끝날 때 까지 계속된다. 이 동안, activity는 화면상으로 다른 activity보다 앞에 위치하게 된다. Activity는 resume과 paused 상태 사이를 빈번히 이동한다. 예를 들면 onPause()는 device가 sleep으로 가거나 새로운 activity가 시작되면 onPause()가 호출된다. Activity result나 새로운 intent가 오면 onResume()가 재개된다. 따라서 이 method의 code들은 꽤 lightweight하다. 아래 diagram은 activity가 취하는 state의 loop와 경로를 그렸다. 색깔있는 타원은 major state를 나타내고 사각형은 call back method를 나타낸다.

The following table describes each of these methods in more detail and locates it within the activity's overall lifecycle:
아래의 table은 이 method들을 좀더 자세히 설명한다.
|
Method |
|
|
Description |
Killable? |
Next |
|
|
|
Called when the activity is first created. This is where you should do all of your normal static set up — create views, bind data to lists, and so on. This method is passed a Bundle object containing the activity's previous state, if that state was captured (see Saving Activity State, later). Always followed by onStart(). |
No |
onStart() | |
|
|
|
Called after the activity has been stopped, just prior to it being started again. Always followed by onStart() |
No |
onStart() | |
|
|
|
Called just before the activity becomes visible to the user. Followed by onResume() if the activity comes to the foreground, or onStop() if it becomes hidden. |
No |
onResume() or onStop() | |
|
|
|
Called just before the activity starts interacting with the user. At this point the activity is at the top of the activity stack, with user input going to it. Always followed by onPause(). |
No |
onPause() | |
|
|
|
Called when the system is about to start resuming another activity. This method is typically used to commit unsaved changes to persistent data, stop animations and other things that may be consuming CPU, and so on. It should do whatever it does very quickly, because the next activity will not be resumed until it returns. Followed either by onResume() if the activity returns back to the front, or by onStop() if it becomes invisible to the user. |
Yes |
onResume() or onStop() | |
|
|
|
Called when the activity is no longer visible to the user. This may happen because it is being destroyed, or because another activity (either an existing one or a new one) has been resumed and is covering it. Followed either by onRestart() if the activity is coming back to interact with the user, or by onDestroy() if this activity is going away. |
Yes |
onRestart() or onDestroy() | |
|
|
|
Called before the activity is destroyed. This is the final call that the activity will receive. It could be called either because the activity is finishing (someone called finish() on it), or because the system is temporarily destroying this instance of the activity to save space. You can distinguish between these two scenarios with the isFinishing() method. |
Yes |
nothing |
Note the Killable column in the table above. It indicates whether or not the system can kill the process hosting the activity at any time after the method returns, without executing another line of the activity's code. Three methods (onPause(), onStop(), and onDestroy()) are marked "Yes." Because onPause() is the first of the three, it's the only one that's guaranteed to be called before the process is killed — onStop() and onDestroy() may not be. Therefore, you should use onPause() to write any persistent data (such as user edits) to storage.
위에 killable이라는 column이 있다. 이 column은 system이 해당 method가 실행된 이후 그 activity를 소유한 process를 kill할 수 있는지 여부를 나타낸다. 3개의 method가 yes라고 표시되어 있다. onPause(), onStop(), onDestroy()이다. onPause()는 process가 죽기전에 호출이 보장된 함수이다. 하지만, onStop()과 onDestroy()는 그렇지 않다. 따라서 저장되야할 data가 있다면 onPause()를 사용해야 한다.
Methods that are marked "No" in the Killable column protect the process hosting the activity from being killed from the moment they are called. Thus an activity is in a killable state, for example, from the time onPause() returns to the time onResume() is called. It will not again be killable until onPause() again returns.
Killable이 no라고 지시된 method들은 그 method가 호출된 순간부터 자신이 속한 process가 killed되는 것을 막는다. 따라서 activity는 killable state에 있다. 예를 들자면, onPause()에서 onResume()가 호출될 때 까지. 그 activity는 다시 killable 되지 않는다, onPause()가 return될 때까지...
As noted in a later section, Processes and lifecycle, an activity that's not technically "killable" by this definition might still be killed by the system — but that would happen only in extreme and dire circumstances when there is no other recourse.
어떤 activity가 기술적용어로 killable이 아니더라도 여전히 system으로 부터 kill될 수 있다. 하지만 그것은 극한의 경우, resource가 없을 때 발생한다.
Saving activity state
When the system, rather than the user, shuts down an activity to conserve memory, the user may expect to return to the activity and find it in its previous state.
System이 memory 문제로 어떤 activity를 shutdown할 때, 사용자는 그 activity로 부터 어떤 return값을 기다리거나, 이전상태부터 return 값을 찾으로 할지 모른다.
To capture that state before the activity is killed, you can implement an onSaveInstanceState() method for the activity. Android calls this method before making the activity vulnerable to being destroyed — that is, before onPause() is called. It passes the method a Bundle object where you can record the dynamic state of the activity as name-value pairs. When the activity is again started, the Bundle is passed both to onCreate() and to a method that's called after onStart(), onRestoreInstanceState(), so that either or both of them can recreate the captured state.
Unlike onPause() and the other methods discussed earlier, onSaveInstanceState() and onRestoreInstanceState() are not lifecycle methods. They are not always called. For example, Android calls onSaveInstanceState() before the activity becomes vulnerable to being destroyed by the system, but does not bother calling it when the instance is actually being destroyed by a user action (such as pressing the BACK key). In that case, the user won't expect to return to the activity, so there's no reason to save its state.
Because onSaveInstanceState() is not always called, you should use it only to record the transient state of the activity, not to store persistent data. Use onPause() for that purpose instead.
Activity가 죽기전에 상태를 capture하기 위해 onSaveInstanceState()를 구현할 수 있다. Android는 activity가 파괴되기 전에 이 method를 호출할 수 있다. 즉 onPause()가 호출되기 전에 이 method를 호출한다. Android는 그 method에게 어떤 bundle객체를 전달한다. 이 bundle객체라는 것은 activity의 동적상태를 저장한 것인데, name value쌍으로 되어 있다. Activity가 다시 시작되면, 그 bundle객체는 onCreate()와 onStart()다음에 수행되는 onRestoreInstanceState()에 전달된다. 그래서 이 method 둘다, 혹은 하나가 이전의 capture된 그 activity의 상태를 복원시킨다. onSaveInstanceState()나 onRestoreInstanceState()는 onPause()와는 다르게 lifecycle method가 아니다. 그 method들은 항상 호출되는게 아니다. 예를들어 android는 activity가 system에 의해 destroy되기 쉬울 상태에 있을 때, onSaveInstanceState()를 호출한다. User가 그 activity를 destroy할 때는 그 method는 호출 되지 않는다. Activity를 destroy하는 것은 back 키를 누르는 행위가 예가 될 수 있다. 그런 경우 User는 그 activity로 다시 돌아갈 생각이 없기 때문이다. 그래서 그 activity의 state를 유지할 이유가 없다. OnSaveInstanceState()는 항상 호출되지 않기 때문에, 일시적인 data만을 저장하고 persistent한 data는 저장하지 않는다. 그 대신 onPause()를 사용해서 persistent한 data를 저장한다.
Coordinating activities
When one activity starts another, they both experience lifecycle transitions. One pauses and may stop, while the other starts up. On occasion, you may need to coordinate these activities, one with the other.
The order of lifecycle callbacks is well defined, particularly when the two activities are in the same process:
- The current activity's onPause() method is called.
- Next, the starting activity's onCreate(), onStart(), and onResume() methods are called in sequence.
- Then, if the starting activity is no longer visible on screen, its onStop() method is called.
어떤 activity가 다른 activity를 start하면, 둘다 lifecycle이 변한다. 하나가 start하게 되면, 다른 하나는 pause되거나 stop된다. 가끔은 이런 activity들의 lifecycle을 조정하고 싶을 때가 있다. 이런 상황에서 Lifecycle callback function의 순서는 두개의 activity가 동일한 process에 있다면, 제대로 정의가 되어있을 것이다. 즉 어떤 activity가 다른 activity를 시작할 때 lifecycle callback의 순서가 제대로 조정되어 있다는 것이다.
- 현재 activity의 onPause()가 호출된다.
- Start하는 activity의 onCreate(), onStart() 그리고 onResume()가 순서대로 호출된다.
- Starting activity가 더 이상 화면에 보여지지 않으면, onStop()가 호출된다.
Service lifecycle
A service can be used in two ways:
한 개의 service는 두 가지 방식으로 사용된다.
- It can be started and allowed to run until someone stops it or it stops itself. In this mode, it's started by calling Context.startService() and stopped by calling Context.stopService(). It can stop itself by calling Service.stopSelf() or Service.stopSelfResult(). Only one stopService() call is needed to stop the service, no matter how many times startService() was called.
누군가가 service를 종료하거나, service 스스로 종료할 때까지, service는 시작 되서 실행 된다. Service는 Context.startService()로 시작하고 Context.stopService()에 의해 종료한다. Service 자체는 Service.stopSelf()나 Service.stopSelfResult()로 종료된다. 아무리 많은 startService를 사용해서 service를 시작했더라도, stopService()를 한번만 호출하면 service는 멈춘다.
- It can be operated programmatically using an interface that it defines and exports. Clients establish a connection to the Service object and use that connection to call into the service. The connection is established by calling Context.bindService(), and is closed by calling Context.unbindService(). Multiple clients can bind to the same service. If the service has not already been launched, bindService() can optionally launch it.
The two modes are not entirely separate. You can bind to a service that was started with startService(). For example, a background music service could be started by calling startService() with an Intent object that identifies the music to play. Only later, possibly when the user wants to exercise some control over the player or get information about the current song, would an activity establish a connection to the service by calling bindService(). In cases like this, stopService() will not actually stop the service until the last binding is closed.
Like an activity, a service has lifecycle methods that you can implement to monitor changes in its state. But they are fewer than the activity methods — only three — and they are public, not protected:
void onCreate()
void onStart(Intent intent)
void onDestroy()
By implementing these methods, you can monitor two nested loops of the service's lifecycle:
Service는 service가 정의하고 exports하는 interface를 사용해서 service를 동작시키는 게 가능하다. Service를 동작 시킨다는 것은 service의 함수를 이용한다는 것이다. Client가 service객체와 connection한 다음 service의 함수를 호출한다. 그 connection은 Context.bindService()를 사용하는 것이고, Context.unbindService()로 그 service와의 연결을 종료한다. Bind는 connection을 맺는 것을 의미한다. 여러 개의 client들은 동일한 service와 bind할 수 있다. 만약 service가 시작되지 않았다면, bindService()에서 option으로 service를 시작할 수도 있다. 이 두 개의 mode가 완전히 독립적인 것은 아니다. 이미 startService()로 시작된 service와 bind하는 것도 가능하다. 예를 들어, background music service를 intent object를 가지고 startService()로 시작할 수 있다.그리고 나중에 필요할 때, 예를 들면, player를 control해야 하거나, 재생되는 음악정보를 알고 싶다면, bindService()를 호출해서 service와 bind하는 것이다. 이것과 비슷하게, stopService()도 bind가 close되기 전까지, 실제 service를 stop하지 않는다. Activity처럼 service도 lifecycle method(call back method)들을 갖는다. 이것은 자신들의 state에 대한 변화를 monitoring할 수 있다. 하지만 service component의 lifecycle method는 activity에 비해 그 수가 적다. 단지 3개다. 그리고 protected가 아닌 public이다.
Void onCreate()
Void onStart(Intent intent)
Void onDestroy()
이 method를 구현하면, 두개의 nested loop를 monitoring할 수 있다. Nested loop가 뭔지 모르겠음.
- The entire lifetime of a service happens between the time onCreate() is called and the time onDestroy() returns. Like an activity, a service does its initial setup in onCreate(), and releases all remaining resources in onDestroy(). For example, a music playback service could create the thread where the music will be played in onCreate(), and then stop the thread in onDestroy().
Service의 전체 life time은 onCreate()로 시작해서 onDestroy()로 끝이 난다. Activity처럼 service는 onCreate()에서 초기 setup을 한다. 그리고 onDestroy()에서 resource를 release한다. 예를 들어 음악 재생 service는 onCreate()내에서 음악을 재생하는 thread를 만들 수 있다. 그리고 onDestroy()에서 그 thread를 종료한다.
- The active lifetime of a service begins with a call to onStart(). This method is handed the Intent object that was passed to startService(). The music service would open the Intent to discover which music to play, and begin the playback.
There's no equivalent callback for when the service stops — no onStop() method.
The onCreate() and onDestroy() methods are called for all services, whether they're started by Context.startService() or Context.bindService(). However, onStart() is called only for services started by startService().
If a service permits others to bind to it, there are additional callback methods for it to implement:
IBinder onBind(Intent intent)
boolean onUnbind(Intent intent)
void onRebind(Intent intent)
Service의 active한 life time은 onStart()를 호출하면 시작된다. onStart()는 intent객체를 전달 받는다. 이 intent객체는 startService()에서 넘어온 그 intent객체이다. Music service는 어떤 음악이 재생되어야 하는지 그리고 재생을 시작하기 위해 그 intent객체를 open한다. 하지만 onStop()라는 call back method는 존재하지 않는다. Service가 startService나 bindService로 시작되던, onCreate()와 onDestroy()만이 service를 위해 호출된다. onStart()는 반드시 startService()로 시작된 service에서만 호출될 수 있는 method이다. Service객체는 여러 client하고 bind될 수 있다고 했다. 만일 여러 개의 client가 bind하는것을 허용하려면 추가적인 call back method를 구현해야 한다.
Ibinder onBind(Intent intent)
Boolean onUnbind(Intent intent)
Void onRebind(Intent intent)
The onBind() callback is passed the Intent object that was passed to bindService and onUnbind() is handed the intent that was passed to unbindService(). If the service permits the binding, onBind() returns the communications channel that clients use to interact with the service. The onUnbind() method can ask for onRebind() to be called if a new client connects to the service.
bindService()로 부터 전달된 intent를 onBind()에서 전달 받고, unbindService()에서 전달된 intent를 onUnbind()에서 처리한다. 여러 개의 bind를 허용하기 위해서, onBind()에서는 client가 service와 interact할 수 있는 communication channel을 return해야 한다. 만일 새로운 client가 service와 연결을 한다면, onUnbind()에서 onRebind()를 요청 할 수 있다.
The following diagram illustrates the callback methods for a service. Although, it separates services that are created via startService from those created by bindService(), keep in mind that any service, no matter how it's started, can potentially allow clients to bind to it, so any service may receive onBind() and onUnbind() calls.
아래는 service의 callback method의 diagram이다. 이 diagram은 startService()로 bind했는냐, 혹은 bindService로 시작했느냐에 따라 달라진다. Service가 어떤 방식으로 시작되었던 간에 service는 client가 bind할 수 있게 해주고, service는 onBind()나 onUnbind()를 호출을 받을 수 있다는 것이다.

Broadcast receiver lifecycle
A broadcast receiver has single callback method:
void onReceive(Context curContext, Intent broadcastMsg)
When a broadcast message arrives for the receiver, Android calls its onReceive() method and passes it the Intent object containing the message. The broadcast receiver is considered to be active only while it is executing this method. When onReceive() returns, it is inactive.
A process with an active broadcast receiver is protected from being killed. But a process with only inactive components can be killed by the system at any time, when the memory it consumes is needed by other processes.
Broadcast receiver component는 한 개의 callback method를 가질 수 있다. Void onReceive(Context curContext, Intent broadcastMsg)이다. Broadcast message가 receiver에 도착하면, android는 onReceive()를 호출한다. 그리고 android는 message가 담긴 intent object를 전달한다. Broadcast receiver는 onReceive()를 실행할 때 그것이 active되었다고 간주한다. onReceive()가 return하면 그 component는 inactive되는 것이다. Process에 있는 broadcast component가 active되어 있다면, killed될 수 없다. 하지만, inactive되어 있다면, system에 의해 언제라도 kill될 수 있다.
This presents a problem when the response to a broadcast message is time consuming and, therefore, something that should be done in a separate thread, away from the main thread where other components of the user interface run. If onReceive() spawns the thread and then returns, the entire process, including the new thread, is judged to be inactive (unless other application components are active in the process), putting it in jeopardy of being killed. The solution to this problem is for onReceive() to start a service and let the service do the job, so the system knows that there is still active work being done in the process.
이것이 문제가 될 수 있는데, 왜냐하면, broadcast message처리에 시간을 오래 사용할 경우 이 process는 kill할 수도 없기 때문이다. 따라서, user interface가 사용하는 main thread와는 별개의 thread로 처리 되어야 한다. 만약 onReceive()내에서 다른 thread를 생성하고 return한다면 어떻게 되는가? 전체 process는 inactive되었다고 판단한다. 이말은 onReceive()가 처리되는 동안은 이 process는 active이기 때문에 kill될 수 없는데, onReceive()에서 thread를 생성할 경우, 이것이 onReceive()가 수행되는 상태인가 하는 논란이다. 결론은 onReceive()가 thread를 만들고 자기 자신은 return을 했기 때문에 이 경우는 inactive라고 판단 하는 것이다. 이렇게 inactive된 process를 kill하는데 있어서 그럼 생성한 thread는 어떻게 되는가? 하는 문제가 남는다. 이 문제에 대한 해결책은 onReceive()에서 thread를 생성하지 않고 service를 실행하는 것이다. Service로 하여금 thread가 하는 job을 하게 한다. 그래야 system이 process가 active라고 판단한다.
The next section has more on the vulnerability of processes to being killed.
다음은 process를 kill하는데 있어서 취약성을 살펴보겠다.
Processes and lifecycles
The Android system tries to maintain an application process for as long as possible, but eventually it will need to remove old processes when memory runs low. To determine which processes to keep and which to kill, Android places each process into an "importance hierarchy" based on the components running in it and the state of those components. Processes with the lowest importance are eliminated first, then those with the next lowest, and so on. There are five levels in the hierarchy. The following list presents them in order of importance:
Android system은 process를 가능한 오래 유지하려고 하지만, memory가 부족하면 어쩔 수 없이 오래된 process를 제거해야 한다. Process를 유지할 건지 아니면 제거할 건지를 결정하기 위해서, android는 각각의 process의 "importance hierarchy " 를 적용 한다. Important hierarchy는 android에서 동작하는 component들과 그들의 status를 기반으로 한것이다. 낮은 importance를 갖는 process는 가장먼저 제거되고 그 다음 낮은 순서로 제거가 될 것이다.
이 hiearchy의 importance는 5가지의 level을 갖는다. 다음은 이 importance에 따라 5개를 나열한다.
- A foreground process is one that is required for what the user is currently doing. A process is considered to be in the foreground if any of the following conditions hold:
- It is running an activity that the user is interacting with (the Activity object's onResume() method has been called).
- It hosts a service that's bound to the activity that the user is interacting with.
- It has a Service object that's executing one of its lifecycle callbacks (onCreate(), onStart(), or onDestroy()).
- It has a BroadcastReceiver object that's executing its onReceive() method.
Only a few foreground processes will exist at any given time. They are killed only as a last resort — if memory is so low that they cannot all continue to run. Generally, at that point, the device has reached a memory paging state, so killing some foreground processes is required to keep the user interface responsive.
Foreground process라는 것은 사용자가 작업하는데 필요한 process라는 것이다. 그럼 어떤게 foreground process인가?
. 사용자와 반응하는 activity를 가지고 있는 process
. 사용자와 반응하는 activtiy와 연결된 service를 가지는 process
. 실행중인 service 객체를 가진 process.
. onReceive()를 수행중인 receiver를 가지고 있는 process.
이 process는 마지막 순간에 제거될 것이다.
- A visible process is one that doesn't have any foreground components, but still can affect what the user sees on screen. A process is considered to be visible if either of the following conditions holds:
- It hosts an activity that is not in the foreground, but is still visible to the user (its onPause() method has been called). This may occur, for example, if the foreground activity is a dialog that allows the previous activity to be seen behind it.
- It hosts a service that's bound to a visible activity.
A visible process is considered extremely important and will not be killed unless doing so is required to keep all foreground processes running.
Visible process는 foreground된 component가 없다 하지만 여전히 사용자가 screen에서 볼 수 있을 경우, 이 process를 visible하다고 한다. Visible process의 기준은 다음과 같다.
. Foregroun된 activity는 아니지만 사용자가 볼 수 있는 activity를 가진 process. 이것은 foreground activity가 이전의 activity가 사용자에게 보여질 수 있도록 허용했다면 가능한 시나리오이다.
. 이런 visible한 activity가 연결된 service를 가지고 있는 process 또한 visible process이다.
- A service process is one that is running a service that has been started with the startService() method and that does not fall into either of the two higher categories. Although service processes are not directly tied to anything the user sees, they are generally doing things that the user cares about (such as playing an mp3 in the background or downloading data on the network), so the system keeps them running unless there's not enough memory to retain them along with all foreground and visible processes.
startService()로 시작된 service를 가지고 있는 process. 이것은 위의 두개에 해당되지 않는 process이다. 이 process는 사용자가 볼 수 있는 어떤것과도 직접적인 연결이 없다. 하지만 사용자가 신경 써서 하는 일련의 작업들..예를들면 background에서 음악 재생, network download의 경우 사용자가 볼 수 없지만, 사용자 입장에서 중요한 작업들이다.
- A background process is one holding an activity that's not currently visible to the user (the Activity object's onStop() method has been called). These processes have no direct impact on the user experience, and can be killed at any time to reclaim memory for a foreground, visible, or service process. Usually there are many background processes running, so they are kept in an LRU (least recently used) list to ensure that the process with the activity that was most recently seen by the user is the last to be killed. If an activity implements its lifecycle methods correctly, and captures its current state, killing its process will not have a deleterious effect on the user experience.
Background process는 그 pocess의 activity가 onStop()가 호출된 상태이다. 이 process들은 언제라도 kill될 수 있다. Background process들은 매우 많이 존재하기 때문에, LRU를 유지하고 있다. 즉 가장 최근에 사용된 process가 나중에 kill될 수 있게 만든 것이다.
- An empty process is one that doesn't hold any active application components. The only reason to keep such a process around is as a cache to improve startup time the next time a component needs to run in it. The system often kills these processes in order to balance overall system resources between process caches and the underlying kernel caches.
Empty process는 active한 component가 하나도 없는 경우. 다음에 실행될 때 더 빠른 속도로 실행하기 위해서 cash처럼 단지 process만 유지하고 있는 경우이다. System 은 program caches들과 kernel cach들 사이의 resource의 균형을 유지하기 위해 이 process들을 kill한다.
Android ranks a process at the highest level it can, based upon the importance of the components currently active in the process. For example, if a process hosts a service and a visible activity, the process will be ranked as a visible process, not a service process.
Android는 현재 active한 component의 기준으로 순위를 매긴다. 예를 들어 어떤 하나의 service와 visible한 activity를 가지고 있는 process가 있다면, 더 높은 순위에 그 process를 올려 놓는다는 말이다. Service process가 아닌 visible한 process로 판단을 한다.
In addition, a process's ranking may be increased because other processes are dependent on it. A process that is serving another process can never be ranked lower than the process it is serving. For example, if a content provider in process A is serving a client in process B, or if a service in process A is bound to a component in process B, process A will always be considered at least as important as process B.
게다가 어떤 process의 순서는 증가될 수 있는데, 다른 process들이 그 process에 의존적일 때 그 process의 순위가 증가 될 수 있다. 다른 process를 serving하는 process는 serving을 받는 process보다 ranking이 내려갈 수 없다. 예를 들어, process A의 content provider가 B process에게 serving하고 있거나, A의 어떤 service가 B process의 component와 묶여 있다면, process A의 ranking은 적어도 process B 이상이다.
Because a process running a service is ranked higher than one with background activities, an activity that initiates a long-running operation might do well to start a service for that operation, rather than simply spawn a thread — particularly if the operation will likely outlast the activity. Examples of this are playing music in the background and uploading a picture taken by the camera to a web site. Using a service guarantees that the operation will have at least "service process" priority, regardless of what happens to the activity. As noted in the Broadcast receiver lifecycle section earlier, this is the same reason that broadcast receivers should employ services rather than simply put time-consuming operations in a thread.
Service가 실행되는 process는 background activity를 가진 process보다 순위가 높아야 하기 때문에, 오래 동작되어야 하는 activity는 thread를 생성해서 실행 하기 보다 service를 만들어 실행하는게 더 낫다. 예를 들어 background 음악 재생이나, 사진을 웹에 올리는 작업들의 경우, service로 시작하는게 좋다. 왜냐하면 그 해당 activity에 어떤 일이 생기더라도 service로 실행하면, service process라는 rank를 보장 받기 때문에 동작에 지장이 덜 간다는 것이다. Broadcast에서 오랜 시간이 걸리는 작업의 경우, 그 연속성을 보장하기 위해, thread가 아닌 service로 실행하라고 이전에 말한 것과 문맥상 같다.