Application Fundamentals
Android applications are written in the Java programming language. The compiled Java code — along with any data and resource files required by the application — is bundled by the aapt tool into an Android package, an archive file marked by an .apk suffix. This file is the vehicle for distributing the application and installing it on mobile devices; it's the file users download to their devices. All the code in a single .apk file is considered to be one application.
Android app는 java로 쓰여진다. 이 프로그램의 soure 코드를 compile을 하고 그 프로그램에 사용된 data나 resource들이 함께 묶여서 하나의 파일을 만든다. 이 파일은 .apk라는 확장자를 갖는다. 이파일은 application 배포나 설치의 하나의 단위이다. 즉 .apk파일 하나가 하나의 application을 나타낸다. 우리는 aapt tool로 이를 package화 할 수 있다.
In many ways, each Android application lives in its own world:
- By default, every application runs in its own Linux process. Android starts the process when any of the application's code needs to be executed, and shuts down the process when it's no longer needed and system resources are required by other applications.
- Each process has its own Java virtual machine (VM), so application code runs in isolation from the code of all other applications.
- By default, each application is assigned a unique Linux user ID. Permissions are set so that the application's files are visible only that user, only to the application itself — although there are ways to export them to other applications as well.
It's possible to arrange for two applications to share the same user ID, in which case they will be able to see each other's files. To conserve system resources, applications with the same ID can also arrange to run in the same Linux process, sharing the same VM.
각각의 app는 각각의 linux process를 갖는다. Android는 어떤 app의 code가 실행될 필요가 있으면 그 process를 실행키고 필요가 없거나 다른 app에서 system resource가 필요할 때 shut down된다. 예를 들어 A라는 app에서 B의 어떤 code가 필요하면 새로운 linux process가 실행되고 그 process가 B의 code를 실행한다는 거 같다. 그리고 각각의 process는 JVM을 갖는다. 그래서 하나의 app는 다른 app와 관계없이 격리 되서 실행된다. 그리고 app는 linux user id를 할당 받는다. 이 user id를 통해서 permission이 설정 된다. App의 files은 동일한 userid에 의해 보여진다. 이 말은 app의 files은 자신의 app에 의해서만 보여질 수 있다는 것이다. 물론 다른 app가 볼 수 있도록 export할 수 있는 여러 방법이 있다. 예를 들어 두 개의 app가 동일한 user id를 공유하게 할 수도 있다. 이렇게 되면 서로의 files를 볼 수 있다. 동일한 user id를 갖게 한 다음, app들이 하나의 process에서 동작하게 만들 수 도 있다. 이렇게 되면 system resource가 절약된다. 왜냐하면 하나의 VM을 사용하기 때문이다.
Application Components
A central feature of Android is that one application can make use of elements of other applications (provided those applications permit it). For example, if your application needs to display a scrolling list of images and another application has developed a suitable scroller and made it available to others, you can call upon that scroller to do the work, rather than develop your own. Your application doesn't incorporate the code of the other application or link to it. Rather, it simply starts up that piece of the other application when the need arises.
For this to work, the system must be able to start an application process when any part of it is needed, and instantiate the Java objects for that part. Therefore, unlike applications on most other systems, Android applications don't have a single entry point for everything in the application (no main() function, for example). Rather, they have essential components that the system can instantiate and run as needed. There are four types of components:
Android에서 가장 중요한 특징은 app들이 서로의 elements 즉 component를 사용할 수 있다는 것이다. 물론 이것은 각각의 app들이 허락을 한다고 가정했을 때 얘기다. 예를 들어 A가 scroller가 필요한데 B가 이를 가지고 있다. 그럼 B의 scroller를 call해서 쓰면 된다. 직접 개발할 필요 없이. 여기서 다른 시스템과 다른 차이가 있다. 다른 시스템처럼 B의 scroller코드를 통합한다거나 link로 연결 하는게 아니다. A에서 B의 scroller를 호출하면 B의 process가 동작하고 B의 jvm이 실행된다. 아..그럼 B의 함수가 호출되면 B의 scroller만 달랑 호출 되지 않을 거 아니냐? 이런 질문이 있을 수 있다. 왜냐하면 process가 실행되면 그 process의 main이라는 entry point가 실행되야 하기 때문에 하지만 android의 app들은 main이라는 단 한 개의 entry point를 갖지 않는다. Android app는 system이 필요에 따라 초기화 시키고 이를 실행시킬 수 있는 4개의 필수 component들을 갖고 있다. 즉 4개의 component들이 entry point라고 말할 수 있다는 것이다.
Activities
An activity presents a visual user interface for one focused endeavor the user can undertake. For example, an activity might present a list of menu items users can choose from or it might display photographs along with their captions. A text messaging application might have one activity that shows a list of contacts to send messages to, a second activity to write the message to the chosen contact, and other activities to review old messages or change settings. Though they work together to form a cohesive user interface, each activity is independent of the others. Each one is implemented as a subclass of the Activity base class.
하나의 activity라는 것은 하나의 visual user interface이다. 이 말은 하나의 activity는 화면을 갖는 user interface..같은 것이다. 예를 들면, 메뉴리스트, 사진을 보여주는 것처럼 사용자의 입력을 받거나 출력하는 기능을 하는게 activity이다. Sms app를 생각해보면, 연락처리스트를 선택하고 메시지를 작성하고 예전메시지를 보거나 환경설정을 하는거 이런게 모두 activity이다. 연락처 list가 화면에 보이고 글을 쓸수 있는 창이 보이고 환경설정 창이 보이고 이런것들이 모두 activity라는 것이다. 이 activity들이 하나의 app를 구성하기에 이들은 매우 밀접한 관련이 있지만, 또한 각각의 activity는 다른 activity와는 독립적이다. 각각의 activity는 Activity라는 base class의 subclass이다.
An application might consist of just one activity or, like the text messaging application just mentioned, it may contain several. What the activities are, and how many there are depends, of course, on the application and its design. Typically, one of the activities is marked as the first one that should be presented to the user when the application is launched. Moving from one activity to another is accomplished by having the current activity start the next one.
App는 단 한 개의 activity로 이루어질 수 있고, 위에 말한 SMS app처럼 여러 개로 구성될 수도 있다. APP가 어떤 activity를 포함할 것인가, 얼마나 많은 activity를 사용할 것인가는 설계를 어떻게 하느냐에 달려 있다. 우선 확실한 건 app가 처음 실행될 때 보여주어야 하는 activity는 반드시 존재한다는 점과 activity에서 다른 activity로의 이동은 이전 activity가 시작(실행)시킨다는 것이다.
Each activity is given a default window to draw in. Typically, the window fills the screen, but it might be smaller than the screen and float on top of other windows. An activity can also make use of additional windows — for example, a pop-up dialog that calls for a user response in the midst of the activity, or a window that presents users with vital information when they select a particular item on-screen.
각각의 activity마다 default window가 있다. Window는 화면을 채우는 건데, 이것이 실제 screen보다 작을 수도 있고 다른 window위에 떠 있을 수도 있다. 그리고 필요하다면 activity는 default window말고 다른 Window도 사용할 수 있다. 예를 들어 pop-up dialog가 있다. Pop-up dialog는 사용자에게 사용자에게 응답을 요청하는데, 이게 하나의 window에서 추가된 window라고 보면 된다. 또 사용자가 특정 item을 선택했을 때, 사용자에게 그 item에 대한 어떤 정보를 알려주려면 또 다른 Window를 보여줄 텐데, 그거 또한 추가된 window라고 보면 된다.
The visual content of the window is provided by a hierarchy of views — objects derived from the base View class. Each view controls a particular rectangular space within the window. Parent views contain and organize the layout of their children. Leaf views (those at the bottom of the hierarchy) draw in the rectangles they control and respond to user actions directed at that space. Thus, views are where the activity's interaction with the user takes place. For example, a view might display a small image and initiate an action when the user taps that image. Android has a number of ready-made views that you can use — including buttons, text fields, scroll bars, menu items, check boxes, and more.
A view hierarchy is placed within an activity's window by the Activity.setContentView() method. The content view is the View object at the root of the hierarchy. (See the separate User Interface document for more information on views and the hierarchy.)
각각의 activity는 default window를 갖는다고 했다. window안에 들어가는 visual content는 view의 hierarchy가 제공한다. 이 말은 view의 base클래스를 구현하는 object들만이 window의 화면상의 내용물이 될 수 있다는 말 같다. 또한 이 view들이라는 게 hierarchy한 구조로 되어 있다는 것이다. 각각의 view들은 window내의 특정한 사각영역을 제어한다. 또한 Parent view는 자식 view들을 가지고 있으며, 또한 그들의 layout을 조정할 수 있다. 말단에 있는 view들은 자기영역의 사각형을 그릴 수 있고 그 영역 안에서 사용자와 직접적으로 반응할 수도 제어도 가능하다는 것이다. 따라서 view라는 것은 activity가 사용자와 interaction이 발생하는 곳에 바로 view가 있다는 말이다. 예를 들면 어떤 view는 작은 이미지를 보여줄 수도 있고(이 말은 view가 자기영역의 사각형에서 이미지를 그린다는 뜻) 사용자가 그 이미지를 건들때 어떤 action을 초기화하기도 한다. Android는 이런 view들을 이미 여러 개 만들어 놓았다. 버튼, textfield, scrollbar, menu item 등등. Activity.setContentView메소드로 어떤 view hierarchy를 특정 activity의 window로 설정할 수가 있다. ContentView라는 것은 rootview를 의미한다. 따라서 setContentView로 설정하면 그 view가 root가 된다는 말.
Services
A service doesn't have a visual user interface, but rather runs in the background for an indefinite period of time. For example, a service might play background music as the user attends to other matters, or it might fetch data over the network or calculate something and provide the result to activities that need it. Each service extends the Service base class.
Service라는 것은 user interface가 없지만 정해지지 않은 시간동안 background에서 동작할 수 있다. 예를 들어, 어떤 서비스는 사용자가 다른 일을 하고 있는 동안 음악을 뒤에서 재생하기도 한다. 아니면 뒤에서 네트웍 data를 꺼낸다던지, 뭔가를 계산한다던지..등등..각각의 service는 Service라는 base클래스를 상속해서 사용한다.
attends to : 집중하다.
A prime example is a media player playing songs from a play list. The player application would probably have one or more activities that allow the user to choose songs and start playing them. However, the music playback itself would not be handled by an activity because users will expect the music to keep playing even after they leave the player and begin something different. To keep the music going, the media player activity could start a service to run in the background. The system would then keep the music playback service running even after the activity that started it leaves the screen.
It's possible to connect to (bind to) an ongoing service (and start the service if it's not already running). While connected, you can communicate with the service through an interface that the service exposes. For the music service, this interface might allow users to pause, rewind, stop, and restart the playback.
Like activities and the other components, services run in the main thread of the application process. So that they won't block other components or the user interface, they often spawn another thread for time-consuming tasks (like music playback). See Processes and Threads, later.
예를 들면, Media player의 음악 재생을 예로 들 수 있다. Media player app는 여러 개의 activity를 가질 수 있다. 사용자가 음악을 선택하는 activity와 음악을 start시키는 activity로..그러나 음악재생 자체는 activity에 의해 제어될 수 없다. 음악을 선택하거나, 음악을 단지 start시키는 것은 activity가 제어가 가능하지만, 일단 음악이 start되면 이것은 activity에서 제어가 불가능하다는 것 같다. 이것은 사용자가 media player app를 leave하거나, 다른 일을 시작하더라도 음악을 듣기를 원하기 때문이다. 그래서 media player activity는 음악 재생을 background에서 동작하는 service로 시작하게 한다. 음악을 재생시킨 activity가 screen상에서 사라지더라도 음악은 계속 재생된다. 이것은 ongoing service와 연결(bind)함으로써 가능하다. Ongoing service와 연결되어 있다면, 그 service가 공개하는 interface에 의해서 그 service와 communication이 가능하다. Music service에서 그 interface라는 것은 사용자가 음악을 중지하거나, rewind, stop, 재생..이런것을 가능하게 해준다. Activity나 다른 process와 마찬가지로 service는 app process의 main thread에서 동작한다. 그래서 service들은 다른 component나 user interface를 block 시키지 않는다. Service들은 종종 또 다른 thread를 만든다. 이것은 time consuming 작업이다. 이 부분은 이해가 가지 않는다. Service가 main thread에서 동작하기 때문에 다른 component와 interface를 block시키지 않는다는 것과 time consuming하는 task를 spawn한다는 말은 지금은 이해가 가지 않는다. Process와 Thread편에서 다시 다룬다고 한다.
Broadcast receivers
A broadcast receiver is a component that does nothing but receive and react to broadcast announcements. Many broadcasts originate in system code — for example, announcements that the timezone has changed, that the battery is low, that a picture has been taken, or that the user changed a language preference. Applications can also initiate broadcasts — for example, to let other applications know that some data has been downloaded to the device and is available for them to use.
An application can have any number of broadcast receivers to respond to any announcements it considers important. All receivers extend the BroadcastReceiver base class.
Broadcast receiver는 직접 무언가를 하진 않는 component이다. 단지 broadcast에 공지를 받거나 이에 반응하는 component이다. 많은 broadcast라는 것은 system code로 부터 기인한다. 예를 들면 timezone이 변경이 되었다, 배터리가 낮다, 그림을 다운받았다. 사용자가 언어설정을 바꾸었다라는 공지들이 broadcast되는 것이다. App들은 또한 broadcast를 날릴 수도 있다. 어떤 data가 다운받았으니 이 data는 사용가능하다라는 broadcast를 다른 app에게 알릴 수가 있는 것이다. App는 또한 여러 개의 broadcast receiver를 가질 수 있는데, 이것은 중요하다고 생각되는 공지에 대해 반응하기 위한 것이다. 모든 broadcast receiver는 BroadcastReceiver라는 base class를 상속받는다.
Broadcast receivers do not display a user interface. However, they may start an activity in response to the information they receive, or they may use the NotificationManager to alert the user. Notifications can get the user's attention in various ways — flashing the backlight, vibrating the device, playing a sound, and so on. They typically place a persistent icon in the status bar, which users can open to get the message.
Broadcast receiver들은 user interface를 보이지 않는다. 하지만 그들은 받은 정보에 따라, activity를 실행시킨다던가, NotificationManager를 통해 사용자에게 경고를 보낼 수는 있다. 이 경고는 여러 방식으로 사용자에게 관심을 불러 일으킬 수 있다. Backlight를 키고, 진동을 일으킨다거나 소리를 내는 방식으로 말이다. 이 경고는 status bar에 icon으로 있어서 사용자가 그 메시지를 open해서 볼 수 있다.
Content providers
A content provider makes a specific set of the application's data available to other applications. The data can be stored in the file system, in an SQLite database, or in any other manner that makes sense. The content provider extends the ContentProvider base class to implement a standard set of methods that enable other applications to retrieve and store data of the type it controls. However, applications do not call these methods directly. Rather they use a ContentResolver object and call its methods instead. A ContentResolver can talk to any content provider; it cooperates with the provider to manage any interprocess communication that's involved.
App가 가지고 있는 data를 다른 app가 사용하는 것을 가능하게 하는것은 Content Provider가 있기 때문입니다. Data는 file system 혹은 sqlite혹은 어떤 매체에도 저장될 수 있습니다. contentProvider는 ContentProvider란 base class가 있고 이를 구현한 class는 data에 대해 제어가 가능합니다. 이 말은 restore하거나 store가 가능하다는 말이죠. 하지만, ContentProvider의 method를 직접 호출 할 수 없습니다. ContentResolver라는 객체의 method를 통해서 이를 호출할 수가 있는데요. ContentResolver라는 객체는 어떤 content provider와도 통신이 됩니다.
See the separate Content Providers document for more information on using content providers.
Whenever there's a request that should be handled by a particular component, Android makes sure that the application process of the component is running, starting it if necessary, and that an appropriate instance of the component is available, creating the instance if necessary.
ContentProvider의 정보는 별도로 기술 했습니다.
어떤 component의 요청이 있는 경우, 그 요청이란 contentResolver라는 객체의 method를 통해 어떤 data를 쓰고자하는 요청이곗죠..그럼 andoid는 component는 동작이 계속되게 하면서 그 instance를 필요에 따라 생성하거나 실행시킵니다. 이 부분은 좀 모호함..
Activating components: intents
Content providers are activated when they're targeted by a request from a ContentResolver. The other three components — activities, services, and broadcast receivers — are activated by asynchronous messages called intents. An intent is an Intent object that holds the content of the message. For activities and services, it names the action being requested and specifies the URI of the data to act on, among other things. For example, it might convey a request for an activity to present an image to the user or let the user edit some text. For broadcast receivers, the Intent object names the action being announced. For example, it might announce to interested parties that the camera button has been pressed.
Component는 4가지 종류가 있는데요. Activity, service, broadcast receiver, content provider가 있죠.
각각의 component들이 어떨때 동작하는가에 대해 알아봅니다. Content Provider는 ContentResolver가 요청하면 activate되는데요. 즉 app가 어떤 content를 사용하고 싶다면 contentResolver를 통해 data(content)를 꺼내 오는 method를 호출하면 contentResolver가 해당 ContentProvider를 호출하겠죠. 이때 활성화 됩니다. 나머지 3개(activity, service, broadcast receiver)는 intents라는 비동기 메시지에 의해 활성화 됩니다. Intent는 메시지를 가지는 하나의 객체인데요, activities와 service의 경우 intent는 우선 요청할 action을 지정합니다. 그리고 action이 수행될 data의 URI를 기술하게 됩니다. 그런 intent를 activity와 service로 보내면 activate되겠죠. 예를들면 image를 사용자에게 보여 주라하는 요청이나, 사용자가 text를 수정하게 하라라는 명령을 activity에게 보낼 수 있는 것이죠. Broadcast receiver와 같은 component에서는 intent는 공지에 대한 action을 지정합니다. 예를 들면 카메라버튼이 눌렸다는 공지를 관심있는 그룹에게 공지할 수 있죠.
There are separate methods for activiating each type of component:
각각의 component를 활성화하는 독립된 method들이 있다.
- An activity is launched (or given something new to do) by passing an Intent object to Context.startActivity() or Activity.startActivityForResult(). The responding activity can look at the initial intent that caused it to be launched by calling its getIntent() method. Android calls the activity's onNewIntent() method to pass it any subsequent intents.
One activity often starts the next one. If it expects a result back from the activity it's starting, it calls startActivityForResult() instead of startActivity(). For example, if it starts an activity that lets the user pick a photo, it might expect to be returned the chosen photo. The result is returned in an Intent object that's passed to the calling activity's onActivityResult() method.
Activity Component를 시작하려면 Context.startActivity()나 Activity.startActivityForResult()를 호출하면 된다. 인자로 intent객체를 전달한다.
intent객체를 Context.startActivity() or Activity.startActivityForResult()에 전달하면 Activity가 시작된다. 이렇게 시작된 activity는 getIntent()를 통해 자신을 시작시킨 intent가 무엇인지 알 수 있다. Android는 activity의 onNewIntent()를 호출하면 나중에 오는 intents를 activity에게 건네준다. Activity는 보통 다른 activity를 실행시키는데 어떤 결과값을 return받고 싶으면 startActivityForResult()를 startActivity()대신 써야 한다. 예를 들면, 사진을 선택하는 activity를 실행했다면, 이전 activity는 user가 선택한 사진을 return 받고 싶을 것이다. 그 때 onActivityResult()를 호출하면 return값을 얻을 수 있다. Return값은 intent객체로 넘어 온다.
- A service is started (or new instructions are given to an ongoing service) by passing an Intent object to Context.startService(). Android calls the service's onStart() method and passes it the Intent object.
Similarly, an intent can be passed to Context.bindService() to establish an ongoing connection between the calling component and a target service. The service receives the Intent object in an onBind() call. (If the service is not already running, bindService() can optionally start it.) For example, an activity might establish a connection with the music playback service mentioned earlier so that it can provide the user with the means (a user interface) for controlling the playback. The activity would call bindService() to set up that connection, and then call methods defined by the service to affect the playback.
A later section, Remote procedure calls, has more details about binding to a service.
Service Component의 시작은 Context.startService()에 intent객체를 인자로 전달해서 호출하면 시작된다. 어떤 compoent에서 Context.startService()를 호출하면서 intent객체를 넘겨주면, service가 시작한다. Android는 그 service의 onStart()를 호출하고 service에 그 intent객체를 넘겨주면서 시작되는 것이다. 호출한 component와 service사이의 연결을 계속 유지하기 위해서 Context.bindService()를 사용해서 intent를 넘겨줄 수도 있다. Service는 onBind()로 그 intent를 받는다. (만일 service가 실행되지 않고 있다면, bindService()는 service를 실행할 수도 있다.). 예를 들어, 어떤 activity가 음악 재생 service를 controll하고 싶다면 bindService()로 연결을 시도하고 그 service가 제공하는 function을 activity가 사용할 수 있는 것이다. 예를 들어, 음악을 pause한다 거나, stop하는 일 들을 할 수 있는 것이다. 나중에 Remote procedure calls에서 service를 binding하는 것에 대해 자세히 알아 볼 것이다.
- An application can initiate a broadcast by passing an Intent object to methods like Context.sendBroadcast(), Context.sendOrderedBroadcast(), and Context.sendStickyBroadcast() in any of their variations. Android delivers the intent to all interested broadcast receivers by calling their onReceive() methods.
For more on intent messages, see the separate article, Intents and Intent Filters.
App가 broadcast를 초기화 하기 위해서 Context.sendBroadcast(), Context.sendOrderedBroadcast() 그리고 Context.sendStickyBroadcast()를 호출하면됩니다. 여기에 intent객체를 인자로 보내야 합니다. Android는 관심있는 broadcast Receiver의 onReceive()를 호출해서 이 intent를 전달합니다. 좀 더 intent message의 내용 intents and intent filters에 독립적으로 나와 있습니다.
Shutting down components
A content provider is active only while it's responding to a request from a ContentResolver. And a broadcast receiver is active only while it's responding to a broadcast message. So there's no need to explicitly shut down these components.
Activities, on the other hand, provide the user interface. They're in a long-running conversation with the user and may remain active, even when idle, as long as the conversation continues. Similarly, services may also remain running for a long time. So Android has methods to shut down activities and services in an orderly way:
Content Provider는 contentResolver의 요청에 대한 응답에 의해 활성화 됩니다. 또한 Broadcast receiver는 broadcast message에 대한 응답에 의해 혹은 응답을 할 때 활성화되죠. 그래서 이 component들은 명확하게 종료할 필요가 없게 됩니다. 요청이 없으면 활성화가 안되니까..즉 종료된 상태이니 까요. 하지만 activity와 service는 그렇지 않습니다. Activity들은 user interface를 갖는데요. 이말은 user와 끊임없이 conversation하기도 혹은 idle상태에 있더라도 그들은 running상태라는 것입니다. 유사하게 service도 마찬가지로 오랜시간 running상태를 유지하기도 하는데요.. 그래서 android는 이들을 shut down할 수 있는 method를 제공합니다.
- An activity can be shut down by calling its finish() method. One activity can shut down another activity (one it started with startActivityForResult()) by calling finishActivity().
Activity 자신을 종료하는 method는 finish()입니다. 다른 activity를 종료할 수 있는데요. 왜냐하면 activity는 다른 activity를 실행할 수 있는데(startActivityForResult()로 시작시킬 수 있다.) 이렇게 시작한 activity는 finishActivity()로 종료 시키면 됩니다.
- A service can be stopped by calling its stopSelf() method, or by calling Context.stopService().
Service는 stopSelf()로 종료가 되거나 Context.stopService()로 종료합니다.
Components might also be shut down by the system when they are no longer being used or when Android must reclaim memory for more active components. A later section, Component Lifecycles, discusses this possibility and its ramifications in more detail.
Component들은 system에 의해 종료 될 수도 있는데요. 이건 Android가 다른 component를 활성화 하기 위해 memory가 필요할 때 쓰지 않는 component가 있다면, 종료 시킵니다. 이것은 나중에 Component Lifecycles에서 다시 자세히 살펴 보기로 합시다.
The manifest file
Before Android can start an application component, it must learn that the component exists. Therefore, applications declare their components in a manifest file that's bundled into the Android package, the .apk file that also holds the application's code, files, and resources.
The manifest is a structured XML file and is always named AndroidManifest.xml for all applications. It does a number of things in addition to declaring the application's components, such as naming any libraries the application needs to be linked against (besides the default Android library) and identifying any permissions the application expects to be granted.
Android는 app의 component를 실행할 수 있습니다. 하지만 그전에 android는 app에 어떤 component들이 있는지 알아야 할 필요가 있습니다. 따라서 app는 manifest파일에 자신의 app에 포함된 component를 적습니다. 이 파일 app의 component의 목록이 들어있는 manifest파일은 apk파일에 포함되어 있습니다. 이 android package(apk)는 app의 code,file,resource를 가지고 있습니다. 이 manifest file은 xml로 되어 있고, 이는 모든 app들이 AndroidManifest.xml란 동일한 이름을 가지고 있습니다. 이 manifest란 file은 component의 이름을 나열하는 것 이외에 많은 일을 합니다. App가 필요로 하는 library의 이름도 나열하고 app가 접근하기 위한 permission도 적혀있습니다.
But the principal task of the manifest is to inform Android about the application's components. For example, an activity might be declared as follows:
하지만 manifest의 주된 역할은 android에게 app가 쓰고 있는 component를 알리는 겁니다. 예를 들어,
<?xml version="1.0" encoding="utf-8"?>
<manifest . . . >
<application . . . >
<activity android:name="com.example.project.FreneticActivity"
android:icon="@drawable/small_pic.png"
android:label="@string/freneticLabel"
. . . >
</activity>
. . .
</application>
</manifest>
위의 file에서는 activity라는 component를 android에게 알려주고 있는데요. Name은 Activity를 상속 구현한 class의 이름이구요. Icon과 label은 사용자에게 보여질 activity의 icon과 label입니다.
The name attribute of the <activity> element names the Activity subclass that implements the activity. The icon and label attributes point to resource files containing an icon and label that can be displayed to users to represent the activity.
The other components are declared in a similar way — <service> elements for services, <receiver> elements for broadcast receivers, and <provider> elements for content providers. Activities, services, and content providers that are not declared in the manifest are not visible to the system and are consequently never run. However, broadcast receivers can either be declared in the manifest, or they can be created dynamically in code (as BroadcastReceiver objects) and registered with the system by calling Context.registerReceiver().
For more on how to structure a manifest file for your application, see The AndroidManifest.xml File.
다른 component들도 유사합니다. Service는 <service>로 Broadcast receiver는 <receiver>로 content provider는 <provider>로 ..여기서 특징적인것은 Activity, service, provider의 경우 manifest file에 기술되지 않는다면 system에서 실행되지 않는 다는 것입니다. 하지만, Broadcast receiver의 경우 manifest 파일 안에 기술되지 않아도 동적으로 생성하고 이를 Context.registerReceiver()에 등록하면 실행시킬 수 있다는 점인데요. 자세한 내용은 The androidManifest.xml File이라는 장에서 설명합니다.
Intent filters
An Intent object can explicitly name a target component. If it does, Android finds that component (based on the declarations in the manifest file) and activates it. But if a target is not explicitly named, Android must locate the best component to respond to the intent. It does so by comparing the Intent object to the intent filters of potential targets. A component's intent filters inform Android of the kinds of intents the component is able to handle. Like other essential information about the component, they're declared in the manifest file. Here's an extension of the previous example that adds two intent filters to the activity:
하나의 intent객체는 하나의 target Component를 지정한다. 그렇다면 Android는 intent객체가 지정한 Component를 manifest file에서 찾고 그 Component를 활성화 할 것이다. 그러나 target Component가 명확히 지정이 안되어 있다면, android는 그 intent에 응답하기 위해 최적의 Component를 찾아야 한다. 어떻게 최적의 Component를 찾을 것인가? Intent객체와 intent filter를 비교해서 찾는다. 하나의 component의 intent filter는 자신(component)을 handle하는 intent의 list를 android에게 알려주기 때문이다. Component의 중요한 정보들이 manifest file에 기술된 것과 같이 intent filter들도 기술 되어 있다. 아래는 위에서 사용한 예제에 activity라는 component에 두 가지 intent filter를 추가한 내용이다.
해석이 어렵다. 왜냐면..내가 intent가 어떻게 쓰이는지 아직 hello world조차 해보지 않았기 때문이다.
<?xml version="1.0" encoding="utf-8"?>
<manifest . . . >
<application . . . >
<activity android:name="com.example.project.FreneticActivity"
android:icon="@drawable/small_pic.png"
android:label="@string/freneticLabel"
. . . >
<intent-filter . . . >
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter . . . >
<action android:name="com.example.project.BOUNCE" />
<data android:mimeType="image/jpeg" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
. . .
</application>
</manifest>
The first filter in the example — the combination of the action "android.intent.action.MAIN" and the category "android.intent.category.LAUNCHER" — is a common one. It marks the activity as one that should be represented in the application launcher, the screen listing applications users can launch on the device. In other words, the activity is the entry point for the application, the initial one users would see when they choose the application in the launcher.
The second filter declares an action that the activity can perform on a particular type of data.
첫 번째 filter는 action과 category로 이루어진 일반적인 filter이다. 이것은 그 activity가 application launcher에 표시된다는 것을 의미한다. Application launcher은 사용자가 실행할 수 있는 application의 list가 보여지는 화면을 의미한다.(주절이 끝난 다음 ,뒤에 명사가 나와 조금 당황했음 왜냐? In the application launcher and the screen으로 해석해야 하는가에 대해..하지만 which is 가 생략 되었다고 해석함) 다시 말해서, 이 activity가 application의 entry point를 의미한다는 것이다. 두 번째 filter는 activity가 하는 action을 정의한다.
A component can have any number of intent filters, each one declaring a different set of capabilities. If it doesn't have any filters, it can be activated only by intents that explicitly name the component as the target.
하나의 component는 여러 개의 intent filter를 가질 수 있고 그들 각각은 서로 다른 기능을 한다. 만일 filter가 없다면, 그 component는 intent가 명시적으로 target Component를 지정했어야 한다.
For a broadcast receiver that's created and registered in code, the intent filter is instantiated directly as an IntentFilter object. All other filters are set up in the manifest.
Broadcast receiver의 경우, intent filter는 code상으로 만들어지고 등록되어 진다. Intent filter를 manifest파일에서 설정하지 않고 IntentFilter라는 객체로 생성시킨다.
For more on intent filters, see a separate document, Intents and Intent Filters.
Intent filter에 대해서는 다음 문서를 봐라.
Activities and Tasks
As noted earlier, one activity can start another, including one defined in a different application. Suppose, for example, that you'd like to let users display a street map of some location. There's already an activity that can do that, so all your activity needs to do is put together an Intent object with the required information and pass it to startActivity(). The map viewer will display the map. When the user hits the BACK key, your activity will reappear on screen.
To the user, it will seem as if the map viewer is part of the same application as your activity, even though it's defined in another application and runs in that application's process. Android maintains this user experience by keeping both activities in the same task. Simply put, a task is what the user experiences as an "application." It's a group of related activities, arranged in a stack. The root activity in the stack is the one that began the task — typically, it's an activity the user selected in the application launcher. The activity at the top of the stack is one that's currently running — the one that is the focus for user actions. When one activity starts another, the new activity is pushed on the stack; it becomes the running activity. The previous activity remains in the stack. When the user presses the BACK key, the current activity is popped from the stack, and the previous one resumes as the running activity.
The stack contains objects, so if a task has more than one instance of the same Activity subclass open — multiple map viewers, for example — the stack has a separate entry for each instance. Activities in the stack are never rearranged, only pushed and popped.
A task is a stack of activities, not a class or an element in the manifest file. So there's no way to set values for a task independently of its activities. Values for the task as a whole are set in the root activity. For example, the next section will talk about the "affinity of a task"; that value is read from the affinity set for the task's root activity.
이전에 말했듯이 activity는 다른 activity를 실행한다. 이것은 다른 app의 activity도 실행할 수 있다는 것이다. user에게 어떤 지역의 street map을 보여주고 싶다고 가정하자. 근데 이런 일을 하는 activity가 이미 있다. 그럼 너가 해야 하는 것은 intent객체를 만들어서 startActivity()로 그 activity를 실행 시키면 되는 것이다. 이렇게 시작된 map viewer는 map을 보여줄 것이다. 사용자가 back키를 누르면 너의 activity가 다시 화면에 나타날 것이다. 사용자는 이 map viewer가 동일한 app에서 실행되는 것처럼 보일 것이다. 하지만 그 map viewer는 다른 app에서 정의된 activity일 수 있는 것이다. 하지만 android는 두 개의 activity를 동일한 task에 유지함으로써 user experience를 유지 시킨다. 즉 사용자가 하나의 app라고 생각되는 것은 하나의 task라는 것이다. 그 task는 관련한 activity의 group이고 stack에 쌓여져 있다. Stack의 root activity가 그 task를 시작하는 activity이다. 또한 user가 app launcher에서 선택하는 activity이기도 하다. Stack의 제일 위의 activity는 현재 실행되는 activity이다. Root activity와 top activity는 다르다. 조금 설명하자면 root acitivity는 시작 activity라고 볼 수 있다. App launcher에서 app를 실행하면 처음으로 보여지는 activity, 그것이 root activity이다. 그런데 activity는 다른 activity를 실행시킬 수 있다. 이렇게 다른 activity를 실행하면 그 activity가 stack의 top에 push되는데 이게 current activity라고 할 수 있는것이다. 예를 들어 A라는 activity가 다른 B라는 activity를 시작하면 B는 stack의 top에 삽입된다. 그렇다고 A라는 activity가 사라지지 않는다. 그대로 stack에 남겨져 있다. 하지만 사용자가 Back키를 누르면 top에 있던 B activity는 stack에서 pop된다. 그 대신 A activity가 running activity가 된다. Stack은 object를 저장한다. 만일 어떤 task가 동일한 activity의 instance를 여러 개 가지고 있을 경우 stack은 각각의 instance에 대해 독립적인 entry를 갖는다. Stack에 있는 각각의 activity들은 재배열 되지 않는다. 단지 push되고 pop될 뿐이다. 이 부분이 잘 이해가 안간다. Stack에 독립적인 entry를 갖는다? Stack은 재배열 되지 않는다? 이말이 왜 나오게 되는지...요약하면 하나의 task는 activity로 이루어 진 하나의 stack이다. Manifest파일에서 정의된 class라던가 element가 포함되지 않는다. 그래서 task의 activity에 값을 설정할 방법이 없다. Task의 모든 값들은 root activity안에서 설정된다. 이부분도 이해가 안감..task는 하나의 stack이라고 했고 그 stack에는 여러 개의 activity가 있다는거는 알겠다. 그 activity는 즉 stack에 있는 activity는 class가 아니라 instance이기 때문에 설정을 할 방법이 없다라고 했는데, 또 root activity에서 설정이 가능하다? 그리고 어떤걸 설정한다는 말인가?다음장에서 affinity of task관해 얘기한다고 하니..잘 들어보자.
- User experience 용어
User experience를 디자인 한다는 것이 무엇인지 알아보기 전에, 그 단어가 의미하는 것이 무엇인지 알아보는 것이 좋을 것 같다. :
User experience는 사용자가 어떤 상품이나 시스템을 사용할 때 하게 되는 경험과 만족도를 표현하는 단어이다. 그 단어는 '웹상에서 판매' 와 같이 주로 소프트웨어나 비즈니스 관련 주제를 혼합해서 사용하는데, 이것은 interaction design의 결과물로 나타난다. Wikipedia definition
이 정의에 따르면, user experience는 사용자가 어떤 상품을 사용할때 느끼는 감정적인 특징이라 할 수 있다. user experience는 자동차에서 모바일 폰아나 잡지 혹은 장난감에 이르기까지 그 영역이 확장된다. 일반적으로 user experience라는 단어는 특별히 소프트웨어나 웹 어플리케이션 그리고 디지털 장비에 주로 사용하고 더 일반적인 제품의 경우는 experience design이라 한다.
=> 여기서는 사용자가 기존에 알고 있던 상식이라고 해석하면 된다. 사용자의 상식상 app는 하나의 task가 아닌가..이걸 말한다.
All the activities in a task move together as a unit. The entire task (the entire activity stack) can be brought to the foreground or sent to the background. Suppose, for instance, that the current task has four activities in its stack — three under the current activity. The user presses the HOME key, goes to the application launcher, and selects a new application (actually, a new task). The current task goes into the background and the root activity for the new task is displayed. Then, after a short period, the user goes back to the home screen and again selects the previous application (the previous task). That task, with all four activities in the stack, comes forward. When the user presses the BACK key, the screen does not display the activity the user just left (the root activity of the previous task). Rather, the activity on the top of the stack is removed and the previous activity in the same task is displayed.
Task의 모든 activity들은 하나의 단위로 같이 움직인다. 전체 task를 foreground혹은 background로 가져다 놓을 수 있다. 즉 옮길 수 있다. 가정해 보자. 4개의 activity가 하나의 stack에 놓여져 있다. (task가 하나의 stack을 갖기 때문에, 하나의 task에 4개의 activity가 있다고 생각해도 될듯) . 간단히 이를 A task라고 하자. A task가 실행중이기 때문에 A task의 top activity는 current running activity가 될 것이다. 이 상태에서 사용자가 HOME키를 눌러 application launcher로 이동하고 거기서 다른 B라는 app를 실행한다. 그럼 A라는 task는 background로 가고 B task의 root activity가 화면에 보여진다. 잠시 후에 다시 사용자가 다시 뒤로 돌아가 A task를 선택하면 이전 background에서 돌던 A task가 다시 foreground로 돌아오는 것이다. 사용자가 BACK키를 누르면, 이전 task의 작업중이던 screen이 보이지 않는다. 대신, stack의 top에 있는 activity는 제거되고 동일한 task의 activity가 보여진다. 이말이 혼란 스럽다. 아직 개념을 잘 모르기 때문에...여튼 계속 진행한다.
The behavior just described is the default behavior for activities and tasks. But there are ways to modify almost all aspects of it. The association of activities with tasks, and the behavior of an activity within a task, is controlled by the interaction between flags set in the Intent object that started the activity and attributes set in the activity's <activity> element in the manifest. Both requester and respondent have a say in what happens.
In this regard, the principal Intent flags are:
설명한 이 동작들이 기본적인 task와 activity의 동작들이다. 하지만, 이 모든 것은 수정 가능하다. Task와 activity의 관계라던가, task내에서 activity의 동작은 intent객체를( 그 activity를 시작시키는 intent flag) 설정하고 또한 manifest file에서 <activity>의 속성을 setting해서 수정하는 것이다. 아래는 그 속성들이다.
FLAG_ACTIVITY_NEW_TASK
FLAG_ACTIVITY_CLEAR_TOP
FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
FLAG_ACTIVITY_SINGLE_TOP
The principal <activity> attributes are:
taskAffinity
launchMode
allowTaskReparenting
clearTaskOnLaunch
alwaysRetainTaskState
finishOnTaskLaunch
The following sections describe what some of these flags and attributes do, how they interact, and what considerations should govern their use.
Affinities and new tasks
By default, all the activities in an application have an affinity for each other — that is, there's a preference for them all to belong to the same task. However, an individual affinity can be set for each activity with the taskAffinity attribute of the <activity> element. Activities defined in different applications can share an affinity, or activities defined in the same application can be assigned different affinities. The affinity comes into play in two circumstances: When the Intent object that launches an activity contains the FLAG_ACTIVITY_NEW_TASK flag, and when an activity has its allowTaskReparenting attribute set to "true".
기본적으로, 모든 activity들은 affinity(선호도)라는 값을 갖는다. 즉 동일한 task에 있는 모든 activity들이 이 affinity를 갖고 있단 말이다. 이 값은 manifest에서 <activity>안의 taskaffinity속성에 값을 지정함으로써 각각의 activity들이 affinity값을 가질 수 있다. 말이 좀 복잡한다. 그냥 한마디로 manifest파일에서 각각의 activity의 어떤 속성을 설정할 수 있었는데, 그 속성중에 affinity가 있다는 말이다. 그래서 그 값을 설정할 수 있다는 말이다. 서로 다른 app에서 정의된 activity도 동일한 하나의 affinity를 가질 수 있고, 동일한 app의 activity들이라도 다른 affinity를 가질 수 있다. Affinity는 두개의 환경에서 등장한다. Intent객체에 FLAG_ACTIVITY_NEW_TASK를 설정해서 activity를 시작할 때, 그리고 activity의 설정사항을 담은 manifest 파일의 allowtaskReparenting attribute를 true로 설정하면 된다.
comes into play: 등장하다.
The FLAG_ACTIVITY_NEW_TASK flag
As described earlier, a new activity is, by default, launched into the task of the activity that called startActivity(). It's pushed onto the same stack as the caller. However, if the Intent object passed to startActivity() contains the FLAG_ACTIVITY_NEW_TASK flag, the system looks for a different task to house the new activity. Often, as the name of the flag implies, it's a new task. However, it doesn't have to be. If there's already an existing task with the same affinity as the new activity, the activity is launched into that task. If not, it begins a new task.
아..affinity라는 건 activity와 task와의 관계를 나타내는 거 같다. 우선 해석을 해보자. Activity를 실행 시킬 때 intent객체를 생성하고 이를 startActivity()의 인자로 실행 시키면 새로운 activity가 생성되는 것을 우리는 이미 알고 있다. 그 intent를 설정할 때 FLAG_ACTIVITY_NEW_TASK라고 설정을 하면 새로운 activity가 포함될 task가 이전 activity, 자신을 실행 시킨 activity가 포함된 task(즉 stack)가 아닌 다른 task(stack)에서 실행된다는 것이다. 물론 new task(새로운 stack)에서 그 activity가 실행 될 수 있겠지만, system은 먼저 그 activity가 가지고 있는 affinity와 동일한 값(affinity)를 가진 task가 있다면 그 task에 이 새로운 activity를 launch시킨다는 것이다. 없다면 말 그대로 새로운 task에서 그 activity를 실행 시키는 것이다.
The allowTaskReparenting attribute
If an activity has its allowTaskReparenting attribute set to "true", it can move from the task it starts in to the task it has an affinity for when that task comes to the fore. For example, suppose that an activity that reports weather conditions in selected cities is defined as part of a travel application. It has the same affinity as other activities in the same application (the default affinity) and it allows reparenting. One of your activities starts the weather reporter, so it initially belongs to the same task as your activity. However, when the travel application next comes forward, the weather reporter will be reassigned to and displayed with that task.
If an .apk file contains more than one "application" from the user's point of view, you will probably want to assign different affinities to the activities associated with each of them.
어떤 Activity가 allowTaskReparenting속성이 true라면 그 activity는 task사이를 이동할 수 있다는 말이다. 예를 들면, weather condition을 report하는 A라는 activitiy가 있다고 하자. 그 A는 원래 travel app에 속하는 activity이다. Travel app에 속하기 때문에 원래 A의 affinity는 travel app에 속한 다른 activitiy와 마찬가지로 동일한 affinity값을 가지고 있을것이다. 그런데 이 activity를 다른 app에서 실행을 시키면 어떻게 될까? 물론 실행은 app에서 시키는게 아니고 app에 포함된 activity가 시작하겠지..어쨌든 A라는 activity는 자신을 시작한 activity가 포함된 task에 포함되 있다는 것이다. 이 말은 A를 시작한 task(stack)에서 실행되고 있다는 것이지, 여기서 사용자가 갑자기 travel app를 실행시키면 어떻게 되는것인가? Travel app의 weather report라는 activity가 다시 하나 생성되는가? 아니다, 이미 사용된 weather report는 다시 이동된다. Travel app의 stack으로 재할당 되고 여기서 보여진다. 만일 apk가 여러 개의 application을 가지고 있다면, 아마도 다른 affinity를 그 activity들에 할당하지 않았을까? 참고로 apk파일은 manifest file이고 이 manifest file은 하나의 app당 한 개 밖에 없다.
Launch modes
There are four different launch modes that can be assigned to an <activity> element's launchMode attribute:
"standard" (the default mode)
"singleTop"
"singleTask"
"singleInstance"
The modes differ from each other on these four points:
Activity는 4개의 launch mode를 가지고 있는데, 이것은 apk파일에서 <activity>element에 설정되어 있다.
Standard(default)
Single top
Singtask
singleInstance
이 모드들의 차이점은 4가지가 있다.
- Which task will hold the activity that responds to the intent. For the "standard" and "singleTop" modes, it's the task that originated the intent (and called startActivity()) — unless the Intent object contains the FLAG_ACTIVITY_NEW_TASK flag. In that case, a different task is chosen as described in the previous section, Affinities and new tasks.
In contrast, the "singleTask" and "singleInstance" modes mark activities that are always at the root of a task. They define a task; they're never launched into another task.
어떤 task가 activity를 가질 것인가? Standard와 singleTop모드는 그 activity를 시작하는 activity가 시작한 task에서 실행된다는 걸 의미한다. 하지만 intent를 만들 때, 속성을 FLAG_ACTIVITY_NEW_TASK로 한다면 새 activity의 affinity가 같은 task를 찾거나, 같은게 없다면 새로운 task에서 실행이 된다. 정적으로 정의하는(manifest file)보다 동적으로 정의가(intent객체) 더 우세하다는 걸 보여준다. 그런데, singleTask와 singleInstance로 activity의 launch mode가 정의 된다면, 상황이 달라진다. 만일 어떤 activity가 singleTask 혹은 singleInstance로 정의 되어 있다면, 이 activity는 다른 activity에서 이 activity를 시작해서 이 activity를 시작한 activity의 task에 놓을 것인가 혹은 다른 task에 놓을 것인가 하는 문제가 아니다. Activity를 이렇게 singleTask나 singleInstance로 놓게 되면, activity가 root activity를 의미하고 이것은 application launcher에서 사용자가 선택하는 그 activity이기 때문에 당연히 다른 activity에서 실행되는 activity가 아니라는 말이다. 오직 application launcher에서 실행되는 activity라는 것을 알려준다.
- Whether there can be multiple instances of the activity. A "standard" or "singleTop" activity can be instantiated many times. They can belong to multiple tasks, and a given task can have multiple instances of the same activity.
In contrast, "singleTask" and "singleInstance" activities are limited to just one instance. Since these activities are at the root of a task, this limitation means that there is never more than a single instance of the task on the device at one time.
Activity가 standard나 singleTop으로 설정을 하면, 여러 번 instance화 될 수 있다. 이 말은...예를들어 A라는 activity가 B라는 activity를 시작(실행)했고 B라는 activity가 B라는 activity를 실행하면 어떻게 될까? B라는 activity가 2번 instance화 된다. 여러 번 instance화가 가능하다는 말이다.
반면 activity가 singleTask나 singleInstance로 설정이 되면, 이건 한번만 instance화 된다. 그것이 task의 root activity이기 때문이다.
- Whether the instance can have other activities in its task. A "singleInstance" activity stands alone as the only activity in its task. If it starts another activity, that activity will be launched into a different task regardless of its launch mode — as if FLAG_ACTIVITY_NEW_TASK was in the intent. In all other respects, the "singleInstance" mode is identical to "singleTask".
The other three modes permit multiple activities to belong to the task. A "singleTask" activity will always be the root activity of the task, but it can start other activities that will be assigned to its task. Instances of "standard" and "singleTop" activities can appear anywhere in a stack.
singleInstance로 정의된 activity가 다른 activity를 시작(실행)할 경우 시작된 activity는 자신과 동일한 task에 있을까? 정답은 아니다. singleInstance라고 정의되면, 그 task자체는 오직 하나의 activity만 갖는다. 즉 root activity로 이루어진 하나의 task만 갖는다고 선언하는 것이다. singleInstance로 정의된 activity도 물론 다른 activity를 시작(실행)할 수 있다. 다른 activity를 실행하면 그 실행되는 activity가 어떤 launch mode를 갖고 있던간에, 그거와 상관없이, 마치 intent에서 FLAG_ACTIVITY_NEW_TASK로 설정한 것처럼, 다른 task에서 시작(실행)된다. 이것외 모든 부분에 있어서, singleInstance는 singleTask와 동일하다. 그럼 singleTask로 정의된 activity에서 다른 activity를 실행 시키면 어떻게 되는가? singleTask로 정의된 activity는 root activity가 되고 자신이 실행 시킨 activity를 실행 시킬 때, intent에 별다른 FLAG설정을 하지 않았다면, 그 activity는 동일한 task를 사용한다. 다른 standard나 singleTop도 마찬가지로 동일한 stack(task)에서 실행 된다.
- Whether a new instance of the class will be launched to handle a new intent. For the default "standard" mode, a new instance is created to respond to every new intent. Each instance handles just one intent. For the "singleTop" mode, an existing instance of the class is re-used to handle a new intent if it resides at the top of the activity stack of the target task. If it does not reside at the top, it is not re-used. Instead, a new instance is created for the new intent and pushed on the stack.
- Standard모드에서는 모든 새로운 intent에 대해 새로운 activity가 만들어지고 이 새로운 activity가 단지 하나의 intent만을 관리한다. singleTop모드에서는 만약 그 activity가 task에서 top에 있을 경우 새로운 activity가 만들어지는게 아니고 재사용 된다. 그래서 새로 만들어진 intent를 관리하는 것은 top에 있는 activity가 관리한다. 만일 activity가 top에 있지 않을 경우, 새로운 intent에 대응되는 새로운 activity가 만들어지고 이 만들어진 activity는 task에 삽입된다.
For example, suppose a task's activity stack consists of root activity A with activities B, C, and D on top in that order, so the stack is A-B-C-D. An intent arrives for an activity of type D. If D has the default "standard" launch mode, a new instance of the class is launched and the stack becomes A-B-C-D-D. However, if D's launch mode is "singleTop", the existing instance is expected to handle the new intent (since it's at the top of the stack) and the stack remains A-B-C-D.
예를 들어, task의 stack이 root activity와 B,C,D가 있다면, stack의 순서는 A-B-C-D이다. Standard mode를 가진 D activity에서 새로운 activity를 생성하기위해 intent를 만들어 startActivity()를 호출했다고 하자. 물론 intent가 지시하는 activity는 D class라고 하면, 새로운 activity instance가 만들어져 stack에 삽입된다. 그래서 결과는 A-B-C-D-D가 된다. 하지만, D activity가 singleTop mode였다면, D type의 activity를 사용하려고 intent를 생성하여 전달해도 새로운 activity가 생기는게 아니고 자기자신이 그 intent를 처리한다.
If, on the other hand, the arriving intent is for an activity of type B, a new instance of B would be launched no matter whether B's mode is "standard" or "singleTop" (since B is not at the top of the stack), so the resulting stack would be A-B-C-D-B.
As noted above, there's never more than one instance of a "singleTask" or "singleInstance" activity, so that instance is expected to handle all new intents. A "singleInstance" activity is always at the top of the stack (since it is the only activity in the task), so it is always in position to handle the intent. However, a "singleTask" activity may or may not have other activities above it in the stack. If it does, it is not in position to handle the intent, and the intent is dropped. (Even though the intent is dropped, its arrival would have caused the task to come to the foreground, where it would remain.)
When an existing activity is asked to handle a new intent, the Intent object is passed to the activity in an onNewIntent() call. (The intent object that originally started the activity can be retrieved by calling getIntent().)
만일, arriving intent가 B type의 activity라면, B의 launch mode가 singleTop이건, standard이건 상관없다. 여기서 표현하는 arriving intent라는 표현이 어색하다. 어쨌든, 결과는 A-B-C-D-B가 된다. 위에 언급했듯이 singleTask나 singleInstance activity는 하나 이상이 될 수 없다. 그래서 singleTask나 singleInstance로 생성되는 activity는 늘 새로운 intent만을 다룬다. singleInstance는 오직 하나의 root activity만을 task에 갖는다. 따라서 늘 stack의 top에 위치에 있다. 이것은 singleInstance로 된 activity가 intent를 다루기에 적합하다. 하지만, singleTask는 위에 activity가 있을 수도 없을 수도 있다. 만일 위에 activity가 있다면, intent를 다루기에 적절치 않다. 그리고 intent가 dropped된다. Intent가 drop되더라도 task는 foreground로 간다. 이미 있는 activity에게 새로운 intent를 handle하도록 요청할 때, intent객체는 onNewIntent()로 전달된다. getIntent()는 이전 activity의 intent객체를 꺼낸다. 이 부분은 나중에 반드시 재해석이 필요하다. Intent가 arrive되고 onNewIntent()가 어떤 일을 하는지에 대해 재해석이 필요하다.
Note that when a new instance of an Activity is created to handle a new intent, the user can always press the BACK key to return to the previous state (to the previous activity). But when an existing instance of an Activity handles a new intent, the user cannot press the BACK key to return to what that instance was doing before the new intent arrived.
For more on launch modes, see the description of the <activity> element.
새로운 intent를 다루기 위해서 activity 객체가 생성되면, 사용자는 back키를 눌러서 이전의 activity로 돌아갈 수 있다. 하지만, 새로운 intent에 대해 새로운 activity가 생기는 게 아니고, 이전 activity가 그 새로운 intent를 받는 경우를 생각하자. 그런 경우, 사용자는 Back키를 눌러 새로운 intent가 도착하기 앞서 이전의 activity로 돌아 갈 수 없다. 좀 더 알기 위해서는 <activity> element를 참고해라.
Clearing the stack
If the user leaves a task for a long time, the system clears the task of all activities except the root activity. When the user returns to the task again, it's as the user left it, except that only the initial activity is present. The idea is that, after a time, users will likely have abandoned what they were doing before and are returning to the task to begin something new.
오랜 시간 동안 사용자가 task를 사용하지 않는다면, system이 root activity만 남겨두고 task에 있는 모든 activity를 clear한다. 사용자가 다시 그 task에 돌아가면 초기 activity(root activity)만 남아 있다. 이 생각은 사용자가 일정시간이 지나면 이전에 했던 모든 작업을 버리고 새롭게 그 task를 시작 한다는 생각이기 때문이다.
That's the default. There are some activity attributes that can be used to control this behavior and modify it:
물론 이것은 default다. 이런 동작을 수정하거나 제어하는 activity 속성이 있다.
The alwaysRetainTaskState attribute
If this attribute is set to "true" in the root activity of a task, the default behavior just described does not happen. The task retains all activities in its stack even after a long period.
Root activity에서 이 속성이 true이면 , task의 모든 activity가 일정 시간이 지나도 사라지지 않는다.
The clearTaskOnLaunch attribute
If this attribute is set to "true" in the root activity of a task, the stack is cleared down to the root activity whenever the user leaves the task and returns to it. In other words, it's the polar opposite of alwaysRetainTaskState. The user always returns to the task in its initial state, even after a momentary absence.
이 속성은 위의 alwaysRetainTaskState와 완전 반대다. 이건 사용자가 다른 task로 갔다가 돌아오면 root위의 activity가 모두 clear된다. 그 시간이 순간일지라도..
The finishOnTaskLaunch attribute
This attribute is like clearTaskOnLaunch, but it operates on a single activity, not an entire task. And it can cause any activity to go away, including the root activity. When it's set to "true", the activity remains part of the task only for the current session. If the user leaves and then returns to the task, it no longer is present.
이 속성은 clearTaskOnLaunch속성과 비슷하다. clearTaskOnLaunch속성이 task의 모든 activity를 통제하고 root activity에서 설저되는 것과는 달리 이속성은 root activity뿐 아니라 일반적인 activity들에게 모두 설정이 가능하다. 이 말은 activity각각에 대해 설정이 가능하다는 걸 의미한다. 만일 이게 어떤 activity에 true라고 설정이 되어 있다고 한다면, 사용자가 다른 task에서 이 task로 return하면 설정된 activity는 clear된다.
There's another way to force activities to be removed from the stack. If an Intent object includes the FLAG_ACTIVITY_CLEAR_TOP flag, and the target task already has an instance of the type of activity that should handle the intent in its stack, all activities above that instance are cleared away so that it stands at the top of the stack and can respond to the intent. If the launch mode of the designated activity is "standard", it too will be removed from the stack, and a new instance will be launched to handle the incoming intent. That's because a new instance is always created for a new intent when the launch mode is "standard".
Activity를 stack에서 제거하는 또다른 방식이 있다. Intent가 FLAG_ACTIVITY_CLEAR_TOP이란 flag를 설정하고 startActivity()를 호출했다고 하자. 해당 activity가 이미 stack에 있다면, 그 intent를 handle하는 instant위의 activity들은 모두 stack에서 사라진다. 만일 지정된 activity의 launch mode가 standard일 경우 자신도 그 stack에서 사라지고 intent를 받아들일 새로운 instance가 만들어진다. 이것은 새로운 intent를 handle할 새로운 instance가 생성되기 때문이다. 이 단락도 모호하다.
FLAG_ACTIVITY_CLEAR_TOP is most often used in conjunction with FLAG_ACTIVITY_NEW_TASK. When used together, these flags are a way of locating an existing activity in another task and putting it in a position where it can respond to the intent.
FLAG_ACTIVITY_CLEAR_TOP은 종종 FLAG_ACTIVITY_NEW_TASK와 연관되서 사용된다. 함께 사용될때, 이 flag들은 다른 task에 있는 이미 있는 activity를 찾게 하고 intent에 대응하는 위치에 이 activity를 삽입한다.
Starting tasks
An activity is set up as the entry point for a task by giving it an intent filter with "android.intent.action.MAIN" as the specified action and "android.intent.category.LAUNCHER" as the specified category. (There's an example of this type of filter in the earlier Intent Filters section.) A filter of this kind causes an icon and label for the activity to be displayed in the application launcher, giving users a way both to launch the task and to return to it at any time after it has been launched.
Activity를 entry point로 설정하려면 어떻게 해야 하는가? Intent filter에 action에는 android.intent.action.MAIN으로 category는 android.intent.category.LAUNCHER로 지정하면 이 activity는 entry point가 된다. 이렇게 filter를 설정하면 application launcher에서 이 activity를 식별할 수 있게 icon과 label이 생성이 된다. 이것은 사용자가 이 activity를 실행할 수 있고 그 시작된 activity로 다시 돌아갈 수 있는 것이다.
This second ability is important: Users must be able to leave a task and then come back to it later. For this reason, the two launch modes that mark activities as always initiating a task, "singleTask" and "singleInstance", should be used only when the activity has a MAIN and LAUNCHER filter. Imagine, for example, what could happen if the filter is missing: An intent launches a "singleTask" activity, initiating a new task, and the user spends some time working in that task. The user then presses the HOME key. The task is now ordered behind and obscured by the home screen. And, because it is not represented in the application launcher, the user has no way to return to it.
위의 filter를 설정하면 그 activity를 실행할 수 있고 다시 그 activity로 돌아갈 수 있다고 했다. 사용자에게 있어 두번째 특성은 중요하다. 이런 이유 때문에, 두 개의 launch mode는 singleTask와 singleInstance는 activity가 MAIN과 LAUNCHER filter를 가질 때만 사용될 수 있는 것이다. 만일 intent filter가 없다고 생각해보자. 어떤 intent가 새로운 task를 시작하기 위해 singleTask인 activity를 시작했다. 그리고 user가 그 task에서 작업을 하고 있다. 사용자가 HOME 키를 누르면, Home screen에 그 task가 application launcher에 보이지 않는다. 이러면 다시 돌아갈 방법이 없게 된다.
A similar difficulty attends the FLAG_ACTIVITY_NEW_TASK flag. If this flag causes an activity to begin a new task and the user presses the HOME key to leave it, there must be some way for the user to navigate back to it again. Some entities (such as the notification manager) always start activities in an external task, never as part of their own, so they always put FLAG_ACTIVITY_NEW_TASK in the intents they pass to startActivity(). If you have an activity that can be invoked by an external entity that might use this flag, take care that the user has a independent way to get back to the task that's started.
For those cases where you don't want the user to be able to return to an activity, set the <activity> element's finishOnTaskLaunch to "true". See Clearing the stack, earlier.
비슷한 어려움은 FLAG_ACTIVITY_NEW_TASK에도 있다. 만일 이 flag가 새로운 task를 시작하기 위해 activity를 시작하고 user가 그 task를 벗어나기 위해 HOME키를 눌렀다면, user가 이전의 task로 돌아갈 방법이 있어야 한다. 어떤 entity들은(예를 들면 notification manager) sctivity를 외부 task에서 실행한다. 즉 entity들은 intent에 FLAG_ACTIVITY_NEW_TASK를 설정하고 startActivity()를 호출하는 것이다. 만일 외부의 task에서 호출되는 activity가 있다면, 다시 말해 외부에서 이런 flag를 intent에서 설정해서 시작할 수 있는 activity를 너의 task가 가지고 있다면, user가 다시 이전 task로 돌아갈 수 있게 하는 방법이 있게 신경써야 한다. 이런경우는 보통 사용자가 이전 task로 돌아갈 필요가 없을 경우 인데 이럴경우 <activity>에 finishOnTaskLaunch를 true로 설정한다.
댓글 없음:
댓글 쓰기