2009년 7월 20일 월요일

Android-Application Fundamentals_2

 

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

onCreate()

 

 

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()

   

onRestart()

 

Called after the activity has been stopped, just prior to it being started again.

Always followed by onStart()

No

onStart()

 

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()

 

   

onResume()

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()

 

 

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()

 

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()

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:

  1. The current activity's onPause() method is called.
  2. Next, the starting activity's onCreate(), onStart(), and onResume() methods are called in sequence.
  3. 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 순서가 제대로 조정되어 있다는 것이다.

  1. 현재 activity onPause() 호출된다.
  2. Start하는 activity onCreate(), onStart() 그리고 onResume() 순서대로 호출된다.
  3. Starting activity가 더 이상 화면에 보여지지 않으면, onStop() 호출된다.

 

Service lifecycle

 

A service can be used in two ways:

개의 service 가지 방식으로 사용된다.

 

 

누군가가 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개를 나열한다.

 

  1. 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 마지막 순간에 제거될 것이다.

 

  1. 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이다.

 

  1. 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 경우 사용자가 없지만, 사용자 입장에서 중요한 작업들이다.

 

  1. 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 있게 만든 것이다.

 

  1. 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 실행하라고 이전에 말한 것과 문맥상 같다.

 

댓글 없음:

댓글 쓰기