Android開發基礎入門

Android基礎

一 什麼是android

     android是專爲移動設備定製的包括操作系統,中間件,和核心應用程序的軟件集。Android SDK提供了用Java語言開發android應用程序所需要的一些工具和API。

二 Feartures

    Application Frame 可被重用

    Dalvik virtual machine 特爲移動設備優化的java虛擬機

    Integrated browser 基於開源的webkit引擎

    Optimized graphics 2d圖形繪製庫;3D 圖形,基於OpenGL ES 1.0 (硬件加速)

    SQLite 用於數據存儲

    Media support 支持常見的音頻,視頻,圖形(MPEG4, H.264, MP3, AAC, AMR, JPG, PNG, GIF)

   GSM Telephony 需硬件支持

    Bluetooth, EDGE, 3G, and WiFi  需要硬件支持

   Camera, GPS, compass, and accelerometer (需要硬件支持)

   Rich development environment 包括設備虛擬器,調試工具,內存和外觀設置,eclipse開發插件。

  Android 架構圖

  Android System Architecture

 

應用程序

Android內置了一些核心的應用程序,包括emial客戶端,短信應用,日曆,地圖,瀏覽器,聯繫人等等。所有這些應用程序都由Java語言寫成。

應用程序框架

開發者們可以在android提供的APIS下進行任意的開發。應用程序一開始就是爲了重用而設計的;任何應用程序的功能都可以發佈給其他的應用程序使用(當然會受一些android爲了安全所做的限制)。用戶可以在同一設備下重寫或替換組件。 

    一組豐富和可擴展的用來構建應用程序的views集合。包括lists,grids,text boxes,buttons,甚至可嵌入web瀏覽器。
    Content Provider 能夠使應用程序操作數據(例如聯繫人),或者共享數據。
    A Rrsource Manager,提供訪問靜態資料,例如國際化資源,圖片,佈局文件。
    A Notification Manager 使應用程序顯示通知。
    An Activity Manager 管理應用程序的生命週期和提供Actitivy調度。
       更多細節,請查看記事本教程。

 Android包含一些供Android系統各種組件使用的C/C++庫。這些功能通過Android應用程序框架暴露給開發者。下面是一些核心庫:

 

  • System C library - 基於標準C實現的BSD-derived實現庫,嵌入式Linux-based設備載體
  • Media Libraries - 基於PacketVideops OpenCORE;支持回放,錄製多種流行的視頻,音頻格式文件,支持靜態圖片文件,包括 MPEG4,H.264,MP3,AAC,AMR,JPG和PNG。
  • Surface Manager 管理多應用無縫集成2D和3D圖形層。
  • LibWebCore-流行的瀏覽器引擎用於android瀏覽器和web瀏覽器
  • SGL - 底層的2d圖形引擎
  • 基於OpenGL ES 1.0APIS的實現。使用硬件加速(硬件支持)或者包括高度優化的軟件光柵。
  • FreeType - 位圖和矢量字體渲染
  • SQLite - 所有applications可用的強大和輕量級的關係數據庫引擎 

    Android基於Linux2.6版本提供系統服務例如安全,內存管理,進程管理,網絡和驅動管理。內核也扮演着一個硬件與軟件堆棧的抽象層角色。

    Android 運行環境

     

    Android 爲Java語言提供了一組核心庫,他提供大多數有用的功能。

    每一個Android應用程序運行在他的獨立進程中,並擁有他的Dalvik虛擬機實例。Dalvik被設計成能在單個設備中有效運行多VMs實例。Dalvik在Dalvik Executable(.dex)中執行經過優化的,佔用最小內存的footprint.VM註冊並運行經java編譯和通過內置的"dx"工具轉化成.dex格式的類文件。

    Dalvik虛擬機依靠Linux內核提供基礎功能,例如線程和底層級別的內存管理。

    Linux 內核

    Android基於Linux2.6版本提供系統服務例如安全,內存管理,進程管理,網絡和驅動管理。內核也扮演着一個硬件與軟件堆棧的抽象層角色。
  • 應用程序基礎

  • Application Components

     Android應用程序使用Java語言開發。被編譯的類——伴隨着應用程序需要的數據和資源文件——被包含在Android包中的aapt工具捆綁,並且打包壓成後綴名爲.apk的壓縮文件。.apk文件可以分發並在設備中安裝。它可以被用戶下載到設備中。所有包含在單個.apk文件中的代碼可以被認爲是一個應用程序。

    在許多方面,每一個Android應用程序活在她自己的世界中:

    • 默認情況下,每個應用程序運行在她獨享的進程中。當任何應用程序執行時,Android會爲他啓動一個進程,關閉進程,當應用程序不需要被使用時,以釋放資源供其他應用程序使用。
    • 每個進程擁有她的Java虛擬機實例,因此應用程序中的代碼數據對其他應用程序是隔離的。
    • 默認情況下,每個應用程序會被分配一個唯一的Linux user ID.文件僅對此用戶可見,僅僅是對應用程序本身——儘管有方法讓它可以被其他應用程序訪問。

    可以讓兩個應用程序共享一個user ID,這種情況下,它們可以訪問各自的文件。多個應用程序可以共享同一個user ID,運行在同一個進程,共享同一個虛擬機實例中。

     

    Android的一個主要特點就是一個應用程序可以使用其他應用程序的元素(提供應用程序許可)。例如:如果你的應用程序需要顯示一組滾動的圖片,其它應用程序已經開發出了一個合適的圖片滾動組件,並且已授權其他應用可用,你可以直接調用這個組件來工作,不必開發你自己的滾動組件。你的應用程序不是將它的代碼拷貝,納入或者鏈接它的代碼到你的代碼中。而是,當需要時,其他應用程序會啓動所需的部分以供調用。

     

    爲完成這工作,系統必須能夠啓動應用程序進程當它的任何部分被調用時,並且爲這些部分實例化Java對象。因此,不像大多數其他的系統,Android應用程序沒有單一的入口(例如 沒有main()方法)。取代的是,它們有一些基本的組件,以供系統需要時實例化並且運行。有四類組件: 

    Activities
        
          一個activity代表着一個虛擬的用戶接口用戶可以開展。例如:一個activity可能代表着一組用戶可選擇的菜單或者它可顯示圖片包括它們的標題。一個短信應用程序可能有一個activity用來顯示一組聯繫人供發消息,另一個activity來寫消息和選擇聯繫人,其他的activities來顯示舊消息或者改變設置。儘管它們協作在一起,它他們彼此之間是獨立的。每一個activity做爲一個Activity基類的實現類存在。
         一個應用程序可能只由一個activity組成,或者像文本消息應用程序,它可能包含多個activity.每個activity的作用,和需要定義多少個activity,當然取決於應用程序的實際設計。通常情況下,定義其中的一個activity作爲應程序啓動時提供用戶的第一個activity。通過當前的activity來啓動下一個activity。

    每個activity擁有一個默認的window窗口。通常,這個窗口會填充屏幕,但他可能比屏幕尺寸要小和懸浮在其他窗口的最頂層。一個activity也能夠利用其它的窗口——例如,一個顯示在activity中間的彈出窗口,提示用戶,或者一個窗口代表用戶的重要信息,當它們在屏幕上選擇特別項時。

    不同等級的視圖提供窗口的視覺效果——由基礎的View衍生出來的對象。每一個view在窗口中控制其特別的形狀。父views包括和組織它們的子類的佈局。葉子views在它們的矩形中繪製,它們直接在它們的空間中控制響應用戶事件。例如,一個view可能顯示一張小圖片並定義當用戶點擊圖片時的事件。Android有一系列的開發好的views供您使用——包括按鈕,文本框,滾動條,菜單項,單選框等等。

    View通過Activity.setContentView()顯示。Content view是在View層次中的根View對象。(查看單獨的User Interface文檔獲取更多細節)

  • Services

            服務沒有可視用戶接口,但在一定時間內,重複不斷的運行於後臺。例如,某服務可能在後臺播放音樂,而用於在執行其他的操作,或者它通過網絡抓取數據或者執行某些計算,將結果提供給activity。每一個服務繼承於Service基類。

            一個典型的例子就是從播放列表中播放音樂。用戶可能利用一個或多個activity選擇歌曲播放。然而,音樂在後臺播放而不被activity處理,因爲用戶希望他們退出播放器窗口進行其他操作時,音樂能持續的播放。爲完成這個操作,音樂播放activity可以啓動一個服務(service),運行於後臺。系統將會負責音樂的持續播放。

            可以訪問連接(綁定)正在運行的服務(或者當服務沒啓動時,可以啓動服務)。當連接服務時,你可以與通過服務提供的接口跟它通信。像音樂服務,它可能提供一個接口,允許用戶暫停,回放,停止,和重放。

             類似activities和其他的組件,服務運行於應用程序進程的主線程中。因爲它們不會中斷其它組件或者用戶接口,它們常常(像音樂)。稍候請查看Processes and Threads.

     

    Content providers

    Content provider將應用程序數據組織成特定的集合供其它應用程序使用。數據可以是存儲在文件系統中,或者在SQLite數據庫中,或者其它任何用戶可以操作數據的地方。content provider繼承於ContentProvider基類,並且實現一組標準的方法,使應用程序可以檢索和存儲它控制的數據。然而,應用程序不是直接調用這些實現方法。而是通過ContentResolver對像調用方法。ContentResolver能夠通知任何的content provider;它可以參與這些content provider進程間的管理合作。
    查看Content Providers文檔獲取更多細節。
    任何時候,當請求處理一個特別的組件時,Android這個應用程序的進程正在運行,如果有需要,啓動,且組件的適當的進程實例將被創建。

    Activating components: intents

    當Content provider接收到ContentResolver的請求時,它將被激活。其它三種組件——activities,services,和broadcast receivers,被稱爲intent的異步消息對象激活。Intent是Intent類的對象,持有消息數據。例如activity和service,它指派它們被請求的行爲和特別的URI標識的數據。如,intent爲actitivy轉達顯示圖片或讓用戶編輯文本的請求。對於broadercast receivers,intent對象指派它通知事件。例如,它可能指派broadcast receiver宣佈它對攝像頭按下的事件感興趣。

    以下是激活每類組件的個別方法:

    • activity通過Intent對象承載,用Context.startActivity()或者Actitivy.startActivityForResult()來啓動新項(開展新活動)。被響應的activity通過調用getIntent()可以查看指派它啓動的Intent對象。Android調用activity的onNewIntent()方法傳給隨後的intents。

          一個activity通常啓動下一個activity。當希望獲得下一activity啓動的返回值時,可以調用startActivityForResult()方法取代startActivity()方法。例如啓動一個能讓用戶選擇圖片的 activity ,可能希望獲得選擇的圖片對象。返回值保存在一個Intent對象中,通過調用activity的onActivityResult()獲得。

    • 啓動一個服務(或者給一個正在運行的服務發新指示),通過一個Intent對象傳遞,調用Content.startService()方法。Android調用service的onStart()方法並且傳給Intent對象。

    • 通常,一個intent通過Context.bindService()來建立調用組件和目標服務的連接。服務通過onBind()接收Intent對象。(如果服務未動行,bindService()方法會啓動它)。例如,一個activity很容易與後臺音樂服務建立連接,因此可以通過服務接口控制音樂服務。Activity利用bindService()方法建立連接,調用服務定義的方法。

           後面章節,Remote procedure calls,將描述更多綁定服務的細節。

    • 應用程序啓動廣播,可以通過Intent對象傳遞,如Context.sendBroadcast(),Context.sendOrderedBroadcast(),Context.sendStickyBroadcast()。Android調用onReceive()方法傳遞intent(意圖)給所有感興趣的接收者。

      • 對意圖做出反應的活動在哪個任務中運行 對於"standard"和" singleTop"模式,它就是發出意圖的任務(調用 startActivity()的任務) — 除非意圖對象中包含 FLAG_ACTIVITY_NEW_TASK標誌。這種情況下,象前一節 關係和新任務中講的一樣,會選擇不同的任務。

        對應的"singleTask "和" singleInstance"模式標記該活動總是作爲任務的根。它們定義的任務永遠不會在其它任務中運行。

      • 是否可以運行活動的多個實例。"standard"或" singleTop "模式的活動可以實例化多次。它們可以屬於多個任務,一個任務中也可以存在多個相同活動的實例。

        對應的"singleTask "和"singleInstance” 模式的活動被限制爲只能擁有一個實例。當這樣的活動是任務的根活動時,該限制意味着,在該設備上不會同時存在兩個以上的相同任務的實例。

      • 實例是否允許其任務中存在其它活動。"singleInstance "模式的活動作爲其任務中唯一的活動,如果它啓動其它活動,那麼被啓動的活動會被分配到其它任務中運行,忽略其運行模式 — 就象在意圖中指定了 FLAG_ACTIVITY_NEW_TASK標誌一樣。所有的其它方面,"singleInstance"模式與"singleTask"模式相同。

        另外三種模式允許一個任務中存在多個活動。" singleTask"活動總是作爲任務的根活動,但它可以在自己的任務中運行其它活動。" standard"和" singleTop"的活動可以在堆的任何位置上運行。

      • 爲了處理新意圖是否運行類的新實例。對於默認的" standard "模式,響應每個新意圖都會創建新的實例。每個實例只響應一個意圖。對於" singleTop"模式,如果它位於目標任務的活動堆的頂層,既存的類的實例將會重用,來處理新的意圖。如果它不在頂層,將不會被重用。而是創建一個新的實例,壓入堆中,來處理新的意圖。

        例如,假設一個任務的活動堆中包含根活動A、活動B、活動C、和頂層活動D,堆中的內容爲A-B-C-D。在收到一個活動D的意圖時。如果D是默認的"standard"運行模式,類的新實例將會運行,堆變成了A- B-C-D-D。可是,如果D的運行模式是" singleTop",既存實例會處理新意圖(因爲它在堆的頂部),堆保持爲A-B-C-D。

        另一種情況,如果到達的是B的意圖,無論B的模式是"standard"還是" singleTop ",一個B的新實例都會被創建 (因爲B不在堆的頂部),堆變成了A-B-C-D-B。

        如上所述,對於" singleTask"或" singleInstance"的活動,不會出現多於一個實例的情況。所以,該實例會處理新的意圖。" singleInstance"活動總是位於堆的頂層(因爲它是任務的唯一活動),因此它總是會響應意圖。在堆中,"singleTask "活動可能有也可能沒有其它活動在它的上面。如果有的話,它將不能處理意圖,意圖將被丟掉。(雖然意圖被丟掉了,但是該任務也會象正常處理意圖一樣被帶到前臺。)

      • 服務的客戶端(爲位於本地)應該實現onServiceConnected()onServiceDisconnected() 方法,這樣它們就可以在成功與遠程服務建立或斷開連接後收到消息。它們應該調用bindService() 來設置連接。
      • 服務的onBind() 方法應該被實現用作根據收到的意圖(傳入bindService()的意圖),決定接受或拒絕連接。
      • 如果連接被接受,它返回一個Stub的子類。如果服務接受了連接,Android調用客戶端的onServiceConnected() 方法並傳入一個IBinder對象,由服務管理的Stub子類的代理。通過該代理,客戶端可以調用遠程服務。
      • 激活狀態或者運行狀態,當它在屏幕的前臺顯示時(在當前活動堆的頂層)。就是具有用戶操作焦點的活動。
      • 暫停狀態,如果活動已經失去焦點、但是對用戶依然可見。就是說另外的活動在它上面,但是它是透明的或者沒有佔滿整個屏幕,通過它還可以看到暫停的活動。暫停的活動處於完全的生存狀態(它維護着所有的狀態和成員信息,保持着屬於它的窗口管理器)。但是當系統內存極低時會被殺調。

      • 停止狀態,如果它被其它活動完全遮擋。它仍然保持着所有的狀態和成員信息。然而它對用戶不可見,因此窗口被隱藏,當其它地方需要內存時,它將被系統殺掉。

      • 活動的整個生命週期從調用onCreate() 開始,直到最後調用onDestroy()爲止。活動在onCreate()中做所有“全局“狀態的設置,在onDestroy()中釋放所有剩餘的資源。例如,如果有一個線程在後臺從網絡上下載數據,它可能在onCreate()中創建該進程,在 onDestroy()中停止該進程。
      • 當調用onStart()方法時,對用戶可見的activity的生命週期開始,直到onStop()方法被調用而結束。在這期間,用戶可以在屏幕上看到這activity,儘管它可能不位於前臺與用戶交互。在這兩個方法間,你可以操作activity需要顯示的數據給用戶。如,你可以在onStart()方法中註冊一個BroadcastReceiver通知UI的變化情況,用戶不需要顯示時,在onStop()方法中卸載它。onStart()方法和onStop()方法可以被調用多次,activity可以選擇對用戶顯示或隱藏。
      • activity生命週期通過onResume()方法恢復到前臺,直至onPause()調用掛起至後臺。這期間,這個activity會在屏幕上置頂於所有其他的activity與用戶交互。一個activity可以在onResume()和onPause()方法中多次改變狀態,如,當設備處於休眠或一個新的activity啓動時,調用onPause(),當另一新的activity無效或新的intent傳遞時,調用onResume()方法。可見,這兩個方法都是相當輕量級的。
      • 下面的圖表舉例說明了actitivy生命週期間的循環轉換過程。橢圓框代表着activity所處的狀態。矩形矩代表着,當actitivy狀態轉換時,你可以實現的回調方法,進行一些操作。
    • 清單文件

      在Android可以啓動應用程序組件之前,它必須知道該組件的存在。因此,應用程序在清單文件中聲明它們的組件,該文件包含在Android包中, .apk 文件還包含應用程序代碼、文件和資源。

      清單文件是結構化的XML文件,對於所有應用程序,文件名均爲AndroidManifest.xml。它除了聲明應用程序組件外,還做一些額外工作,比如指出應用程序需要鏈接的庫(除了Android默認的庫)、標明應用程序被授予的權限。

      但是,清單文件的主要任務是報告Android應用程序的組成部分。例如,活動可以如下那樣聲明:

    <?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>

    <activity>元素的 name屬性命名實現了活動的 Activity子類。 iconlabel屬性,指出代表活動、呈現給用戶的包含圖標和標籤的資源文件。

    其它組件也許以類似的方式聲明— <service>元素用於服務, <receiver>元素用於廣播接收者, <provider>元素用於內容提供者。活動、服務和內容提供者如果不在清單文件中聲明的話,對系統是不可見的,因此永遠不會運行。廣播接收者可以在清單文件中聲明,也可以通過代碼(作爲 BroadcastReceiver對象)動態生成,並通過調用 Context.registerReceiver()註冊到系統中。

    關於如何組織你的應用程序的清單文件,參見 AndroidManifest.xml 文件

    意圖過濾器

    意圖對象可以精確的指定目標組件名。如果指定了,Android將會找到該組件(基於清單文件中的聲明),並激活它。但是,如果目標不是精確的名稱, Android就必須定位到最適合的組件來響應意圖。它將意圖對象與意圖過濾器的可能的目標作比較。組件的意圖過濾器,可以通知Android關於該組件可處理的多種意圖。象其它的組件的基本信息一樣,他們也在清單文件中聲明。這裏是對前一個例子的擴展,爲活動增加了兩個意圖過濾器:

    <?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:type="image/jpeg" />
                    <category android:name="android.intent.category.DEFAULT" />
                </intent-filter>
            </activity>
            . . .
        </application>
    </manifest>

    例子中的第一個過濾器 — 動作" android.intent.action.MAIN" 和分類" android.intent.category.LAUNCHER"的組合 — 這是一個普通的例子。它標記該活動可以顯示在應用程序啓動器(列出用戶可以在設備上啓動的應用程序的畫面)中。也就是說,該活動是應用程序的入口點,當用戶從啓動器運行應用程序時看到的第一個活動。

    第二個過濾器聲明瞭一個動作,該活動可以處理特殊類型的數據。

    組件可以有很多過濾器,每一個聲明一種不同的能力。如果它沒有任何過濾器,就只能通過提供了組件的精確名的意圖來啓動。

    對於通過代碼創建和註冊的廣播接收者,意圖過濾器直接作爲 IntentFilter 對象實例化。所有其它過濾器都通過清單文件設置。

    關於意圖過濾器的更多信息,參見文檔 意圖和意圖過濾器

    活動和任務

    前面提到過,一個活動可以啓動另一個活動,包括屬於其它應用程序的活動。例如,你可能想讓用戶顯示某個地方的地圖。已經有一個活動可以完成它,那麼你的應用程序要做的,只是傳遞包含必要信息的意圖對象到 startActivity()中。地圖查看器將會顯示它。當用戶按下回退鍵時,你的活動將再次出現在屏幕上。

    對於用戶來說,地圖查看器就象是該應用程序的一部分,即使它定義於其它應用程序,運行於那個應用程序的進程。 Android通過將兩個活動歸入同一個任務task來維護用戶體驗。簡單的說,任務就是用戶認爲的"應用程序"。它就是被安排在堆中的、有關聯的一組活動。根活動是堆中用於啓動任務的活動, — 一般來說,它是用戶在應用程序啓動器中選擇的活動。堆頂部的活動是當前運行的活動 — 具有焦點,並對用戶的動作作出反應。當啓動另一個活動時,新活動被壓入堆中;成爲當前活動。前面的活動保留在堆中。當用戶按下回退鍵時,當前活動彈出堆,前一個活動恢復爲當前活動。

    堆保存這些對象,如果一個任務包含兩個以上的同一個活動子類的實例 —比如多個地圖查看器— 每個實例在堆中有各自的入口。活動在堆中不會被重新排列,只是壓入和彈出。

    任務是活動的堆,不是一個類或清單文件的一個元素。因此,無法爲任務中的某個獨立的活動賦值。對於一個任務整體,值是賦給它的根活動的。比如下一節會談到的"任務中的關係";值是通過設到任務的根活動中的關係取得的。

    任務中的所有活動作爲一個整體移動。整個任務(整個活動堆)可以被帶到前臺或送到後臺。比如,當前任務的堆中有四個活動 —有三個在當前活動下面。用戶按下HOME鍵、打開應用程序啓動器、選擇一個新的應用程序(實際上就是一個任務)。當前任務轉爲後臺運行,新任務的根活動被顯示出來。過了一會兒,用戶返回了HOME,並選擇了之前的應用程序(前一個任務)。堆中包含四個活動的任務轉爲前臺。當用戶按下回退鍵時,並不顯示剛剛離開的活動(前一個任務的根活動)。而是堆頂部的活動被移除,顯示堆中的前一個活動。

    該行爲是活動和任務的缺省行爲。有辦法修改這些行爲。活動與任務結合、任務中活動的行爲,由啓動活動時設置到意圖對象中的標誌,和清單文件中活動對應的 <activity>元素的屬性來控制。請求方和應答方對該行爲都有發言權。

    主要的意圖標誌如下:

    FLAG_ACTIVITY_NEW_TASK
    FLAG_ACTIVITY_CLEAR_TOP
    FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
    FLAG_ACTIVITY_SINGLE_TOP

    主要的 <activity>屬性如下:

    taskAffinity
    launchMode
    allowTaskReparenting
    clearTaskOnLaunch
    alwaysRetainTaskState
    finishOnTaskLaunch

    下一節介紹這些標誌和屬性的用處、如何交互和它們應該如何使用。

    關係和新任務

    默認情況下,應用程序中的所有活動之間都有關係— 因爲它們有共同點,就是都屬於同一個任務。但是可以使用<activity> 元素的taskAffinity屬性來爲活動設置單獨的關係。屬於不同應用程序的活動可以共享相同的關係,同一應用程序中的活動也可以擁有不同的關係。關係在兩種情況下發揮作用:當意圖對象包含FLAG_ACTIVITY_NEW_TASK標誌來啓動活動時、和活動的 allowTaskReparenting屬性的值爲"true"時。

    FLAG_ACTIVITY_NEW_TASK標誌
    如前所述,新的活動默認運行於調用 startActivity()的活動的任務中。它被放入與調用者相同的堆中。如果傳遞給 startActivity()的意圖對象包含 FLAG_ACTIVITY_NEW_TASK標誌,系統將爲該新活動尋找不同的任務。看到該標誌就會想到它表示新任務。不過它有可能不是。如果有既存的任務與該新活動有相同的關係,該活動會被併入該任務。如果沒有這樣的任務,則開始一個新任務。
    allowTaskReparenting屬性
    如果一個活動的 allowTaskReparenting屬性被設成了" true",則它可以從啓動它的任務移動到與它具有相同關係的前臺任務中。例如,一個報告選定地點的天氣狀況的活動,屬於某個旅行應用程序的一部分。它與同一應用程序的其它活動具有相同的關係(默認關係),並且它允許重置從屬關係。你的一個活動啓動了天氣報告程序,那麼它與你的活動屬於同一個任務。當旅行應用程序接下來運行時,天氣報告程序會被重新指定爲在旅行應用程序的任務中顯示信息。

    如果一個.apk 文件包含兩個以上的"應用程序"(以用戶的角度),你應該爲每個活動集合準備不同的關係。

    運行模式

    <activity> 元素的 launchMode屬性可以接受四種運行模式:

    standard"(缺省模式)
    singleTop
    singleTask
    singleInstance

    各模式間的差別有如下四點:

    當既存的活動被要求處理新意圖時,意圖對象通過調用 onNewIntent()傳入活動。(被調用的活動可以通過調用 getIntent()取得。)

    注意,當創建一個新實例來處理活動時,用戶可以按回退鍵返回前一個狀態(前一個活動)。但是,當活動的一個既存的實例來處理新意圖時,用戶不能通過按回退鍵返回收到新意圖前的狀態。

    更多關於運行模式的信息,參見 <activity>元素。

    堆的清除

    如果用戶離開任務時間較長,系統會清除任務中根活動以外的所有活動。當用戶再次返回時,只能看到最初的活動。這樣做的原因是,一段時間之後用戶可能不關心之前做了什麼,而是返回該任務做一些新的事情。

    這是默認情況。有一些活動屬性可以用於控制和修改這些行爲:

    alwaysRetainTaskState屬性
    如果任務的根活動的該屬性被設爲" true",上述默認行爲不會發生。任務會保留堆中的所有活動,即使過了很長時間。
    clearTaskOnLaunch屬性
    如果任務的根活動的該屬性被設爲" true",當用戶離開任務再返回時,堆將清除到只剩任務的根活動。換句話說,它與 alwaysRetainTaskState完全相反。用戶總是返回到任務的初始狀態,即使離開一瞬間。
    finishOnTaskLaunch屬性
    該屬性與 clearTaskOnLaunch類似,但它的操作對象是單獨的活動、而不是整個任務。並且它可以應用與任何活動,包括根活動。當它被設爲"true "時,活動只保留當前狀態。如果用戶離開後再返回任務,它將不再存在。

    有其它辦法可以強制從堆中清除活動。如果意圖對象包含 FLAG_ACTIVITY_CLEAR_TOP標誌,並且目標任務中包含可以處理意圖的活動的實例,則該實例上層的活動都會被清除,以使它處於堆的頂層,來響應意圖。如果活動本身的運行模式是" standard",則它也會被從堆中清除,並運行新實例來處理收到的意圖。這是因爲運行模式爲" standard "的活動總是創建新實例來響應新的意圖。

    FLAG_ACTIVITY_CLEAR_TOP經常與 FLAG_ACTIVITY_NEW_TASK一起使用。當同時使用時,意味着在其它任務中找到既存活動,並使其可以響應意圖。

    任務的啓動

    通過爲活動指定一個動作爲“ android.intent.action.MAIN”、分類爲“ android.intent.category.LAUNCHER ”的意圖過濾器,可以將活動設爲任務的入口。(前面的意圖過濾器一節中有這種過濾器的例子。)這種過濾器會在應用程序啓動器中顯示一個圖標和標籤,讓用戶可以啓動一個任務或者返回已運行的任務。

    第二個能力比較重要:用戶必須能在離開任務後還可以回到該任務。正因爲如此,會導致初始化新任務的兩種運行模式,“singleTask” 和“singleInstance”,只有在活動具有 MAINLAUNCHER過濾器時纔可以使用。想象一下,如果沒有上述過濾器的話會是什麼情況:意圖啓動了一個“singleTask”的活動,初始化了一個新任務,用戶用戶在該任務上操作了一段時間。之後用戶按下了HOME鍵,這時該任務被擋在了主屏幕的後面。因爲它沒有出現在應用程序啓動器中,因此用戶無法返回該任務。

    它與啓動帶時帶有FLAG_ACTIVITY_NEW_TASK標誌有些許不同。如果該標誌導致啓動了新的任務,並且用戶按下了HOME鍵,離開了該任務。則必須有辦法使用戶通過某種途徑回到該任務。一些活動(比如提示管理器)總是在其它的任務中啓動活動,從不在自己的任務中啓動。因此,其總是將 FLAG_ACTIVITY_NEW_TASK標誌放入意圖,傳給startActivity()。如果你的活動可以由外部活動來調用,你可以使用該標誌。注意,一定要保證用戶可以返回其啓動的任務。則必須有辦法使用戶通過某種途徑回到該任務。

    在不想讓用戶返回活動時,可以將<activity>的元素finishOnTaskLaunch 設爲“true”。參見前面的堆的清除

    進程和線程

    當應用程序的第一個組件需要運行時,Android會爲其啓動一個包含一個線程的Linux進程。默認情況下,該應用程序的所有組件都會在該進程的該線程中運行。

    然而,你可以使組件運行於其它進程,或者爲任何進程啓動一個線程。

    進程

    進程是由清單文件控制的,組件運行的地方。組件元素 — <activity><service><receiver><provider> — 都有一個process屬性,用於指定組件在哪個進程中運行。這些屬性可以設爲每個組件有其獨立的進程,也可以設成一些組件共享一個進程,其它的獨佔一個進程。也可以設置成,不同應用程序的組件在同一進程中運行 — 只要這些應用程序是由同一個作者簽名並共享同一個Linux用戶ID。 <application> 也有一個process屬性用於設置應用到所有組件的默認值。

    所有的組件都在指定的進程的主線程中運行,系統調用該線程中的組件。不同的線程不會創建不同的實例。因此,響應用戶動作的方法比如View.onKeyDown() 以及後面的組件生命週期 中討論的生命週期消息,總是隻在進程的主線程中發生。這意味着,由系統調用的組件不應該長時間運行或阻斷其它操作(比如網絡操作、循環運算),因爲這將阻礙進程中其它組件的運行。象下面的 線程中討論的那樣,你可以爲耗時的操作分配單獨的線程。

    當更貼近用戶的進程需要內存,並且內存不足時,Android可以在某一時點停止某個進程的執行。進程中的應用程序組件也被消毀。當它們再次運行時,進程重新啓動這些組件。

    當決定哪個進程被終止時,Android評估它們對用戶的重要度。例如,與包含用戶可見的活動的進程相比,包含用戶不可見的活動的進程更容易被終止。因此,決定是否終止一個進程的執行,依賴於運行於該進程的組件的狀態。這些狀態作爲組件生命週期一節的主題。

    線程

    雖然你可以限制你的應用程序只在一個進程中執行,也會有需要其它線程來做一些後臺處理。因爲用戶界面應該總是能夠快速響應用戶的動作,因此運行活動的線程不能同時運行象網絡下載這樣的耗時的操作。任何不能立即完成的操作都應該在不用的線程中執行。

    線程是在代碼中,使用標準JavaThread 對象創建的。 Android提供了一些方便的工具來管理線程 —Looper 用於在線程中執行消息循環、 Handler 用於處理消息、HandlerThread 用於設置一個帶有消息循環的線程。

    遠程過程調用

    Android擁有輕量級的遠程調用機制 (RPC) — 方法在本地調用,在遠程執行(在其它進程中),結果返回給調用者。 這意味着將方法調用及其附帶的數據分解爲操作系統可以理解的形式,將其由本地進程和地址空間傳送到遠程進程和地址空間中,在遠程重新裝配並執行該調用。返回值沿着相反的方向傳遞。Android提供了實現該機制的所有代碼,因此你只需要關注於如何定義和實現該RPC接口本身。

    RPC接口只能包含方法。所有的方法都是同步執行的(本地方法被阻斷,直到遠程方法結束),即使沒有返回值。

    簡而言之,該機制的流程如下:你由使用簡單的IDL(接口定義語言)定義要實現的RPC接口。根據接口的定義, aidl 工具生成本地和遠程進程必要的Java接口的定義。它包含下圖所示的兩個內部類:

    內部類中包含管理你用IDL生成的遠程過程調用需要的所有代碼。兩個內部類都實現了IBinder 接口。其中一個在本地由系統內部使用,寫代碼時可以忽略它。另一個叫做 Stub,擴展自Binder 類。作爲對執行IPC調用的內部代碼補充,它包含你在RPC接口中聲明的方法。象圖中說明的那樣,你應該繼承Stub來實現這些方法。

    一般遠程過程由服務來管理(因爲服務可以通知系統關於進程和它連接的其它進程的信息)。它既有aidl。服務的客戶端只有由aidl生成的接口文件。

    接下來是服務和其客戶端是如何建立連接的:

    上述簡單的描述忽略了一些RPC機制的細節。更多信息參見用AIDL設計遠程接口IBinder 類的描述。

    線程安全方法

    一些情況下,你實現的方法可能被一個以上的線程調用,因此它必須是線程安全的。

    這對於可以遠程調用的方法,這是完全正確的—比如前一節討論的RPC機制。當從IBinder的同一進程調用IBinder中實現的方法時,該方法將在掉調用者的線程中執行。然而,當該調用來自另一個進程時,該方法執行的線程是從由Android維護與IBinder處於相同進程的進程池中選擇的;它不會在進程的主線程中執行。例如,服務的進程的主線程中的onBind() 方法被調用,onBind()返回的對象(比如實現了RPC方法的Stub子類)中實現的方法會在池中的線程中被調用。因爲服務可以有一個以上的客戶端,所以同時可以有一個以上的線程在執行同一個IBinder方法。因此,IBinder的方法必須是線程安全的。

    同樣,內容提供者可以接受來自其它進程的數據請求。雖然ContentResolver和ContentProvider類隱藏瞭如何管理進程間通信的細節,但是相應這些請求的ContentProvider方法— query()insert()delete()update()getType() —是從內容提供者進程的線程池中被調用的。因爲這些方法可以同時從多個線程中調用,所以它們也必須是線程安全的。

    組件生命週期

    應用程序組件具有生命週期—從Android生成它們用於響應一個意圖開始,到實例被銷燬爲止。在這期間,它們可能有時處於激活狀態,有時處於非激活狀態,以及活動對用戶是否可見。本節討論活動、服務和廣播接受器的生命週期—包括它們生存期間的狀態、通知狀態變化的方法、以及這些狀態對實例的銷燬和所在進程是否被中止的可能的影響。

    活動的生命週期

    活動有三種狀態:

    如果活動處於暫停或停止狀態,系統可以通知它結束運行(調用的它的 finish()方法),或者簡單的殺掉進程。當它再次呈現給用戶時,它必須重新啓動並恢復到之前的狀態。

    當活動的狀態發生變化時,系統通過調用如下保護方法來通知該變化:

    void onCreate(Bundle savedInstanceState)
    void onStart()
    void onRestart()
    void onResume()
    void onPause()
    void onStop()
    void onDestroy()

    這些方法都是鉤子,你可以重寫它們,在狀態變化時做一些適當的工作。所有的活動必須實現 onCreate() ,當對象首次實例化時做一些初始設置。很多活動會實現onPause() ,用於提交數據和準備結束與用戶的交互。

    這七個方法定義了活動的整個生命週期。實現它們,你可以監視三層嵌套的循環:

         

          下面的表格中的方法,顯示了activity生命週期中的更多細節。

Broadcast receivers 
        Broadcast receivers接收和響應通知。很多通知來源於系統——例如,發送時區變換的通知,電池電量不足,圖片被採樣,或者用戶改變語言設置。應用程序也可以發出廣播通知——如,通知其它應用程序,數據已經下載完畢,可供系統和應用使用。
        應用程序可以擁有任意數量的廣播接收機來接收任何它認爲重要的通知。所有接收機承繼於BroadcastReceiver基類。        Broadcast receivers不提供可視接口。但是,它可以啓動actitivy響應接收到的通知,或者利用NotificationManager來通知用戶。Notifications可以通過幾種方式提示用戶——閃動背光,振動設備,播放一段音樂等等。它們常常在狀態欄中以圖標顯示,讓用戶獲取通知。
  •  
    • 它啓動和運行,直到某東西停止或自己停止時。這種模式下,它被Context.startService()啓動,而被Context.stopService()停止。它可通過Service.stopSelf()或Service.stopSelfResult()停止自身。不管startService()被調用多少次,僅需一個stopService()方法來停止service。
    • 它可被提供給對外用戶的接口所操作。客戶端與服務對象建立連接並調用服務。連接被Context.bindService()方法建立,被Context.unbindService()關閉。多個客戶端可以綁定同一服務端。如果服務沒有準備好,bindService()可以啓動該服務。

    • 服務的完整的生命週期,在onCreate()被調用和onDestroy()返回間。類似actitivy,服務在onCreate()方法中進行全局初始化,在onDestroy()方法中釋放所有系統資源。如,音樂播放服務可能在onCreate()方法中創建音樂播放線程,在onDestroy()方法中停止線程。
    • 服務的活動生命週期,在調用onStart()後。該方法被Intent對象示意調用startService()方法。音樂服務將分析這個Intent來確定播放什麼音樂,並開始播放。

      當服務停止時,沒有回調方法調用。--on stop()方法。
  • 注意上面表格的Killable列。它表示在不執行其他actitivy's代碼的情況下,系統是否可以在方法調用返回的任何時間殺死activity進程。三個方法(onPause(),onStop()和onDestroy())標識爲"是"。因爲onPause()是三個方法中的第一個,它是唯一一個在進程被殺死前保證被調用的方法——(onStop()和onDestroy())不行。因此,你應該在onPause()方法內執行持久化操作(如用戶編輯數據)。

    在Killable列中被標識爲"No"的方法,保護寄存actitivy的進程,在方法調用期間不被殺死。

     稍候的摘要,Processes and lifecycle,將描述,一個actitivy在應用上定義爲不可被殺死,仍然有可能被系統殺死——但它僅僅發生在極端的和沒有其他資源可用的情況下。

     

    Saving activity state 保存actitivy狀態

    當系統,而不是用戶,在關閉一個actitivy時,用戶可能希望返回和找到它的上一個狀態。

    爲了在actitivy關閉之前捕獲狀態,你可以實現actitivy的onSaveInstanceState()方法。Android會在actitivy被銷燬前——在onPause()被調用前,調用這個方法。它會傳遞一個你可以記錄activity動態狀態的Bundle對象,使用name-value鍵值對。當actitivy再次啓動時,onCreate()和onStart()方法,都會通過Bundle調用onRestoreInstanceState(),因此兩個方法都可以重新創建之前被捕獲的狀態。

    不像之前討論的onPause和其他的方法,onSaveInstanceState()和onRestoreInstanceState()不是生命週期方法。它們常常不會調用。如,在actitivy變成易被系統銷燬的狀態時,Android調用onSaveInstanceState(),但它不會在這個actitivy實例,實際上是被用戶銷燬(如按下BACK)的情況下調用。那種情況下,用戶不希望返回activity,因爲不必保存狀態。

    因爲onSaveInstanceState()不常被調用,你應該僅僅用它來記錄過渡的actitivy狀態,不要用來記錄持久化數據,而應該用onPause()替代。

     

     Coordinating activities

    當一個actitivy啓動其他activity時,它們同樣的都會經歷生命週期過渡。當一個暫停和停止時,另一個開始。一些場合下,你可能需要這些狀態之間配合。

    生命週期的順序被良好的定義,特別是在兩個actitivy在同一個進程當中時:

     1.   當前的actitivy的onPause()方法被調用。

     2.   接下來,正在啓動的actitivy的onCreate(),onStart(),和onResume()方法會按順序被調用。

     3.   然後,如果已啓動的actitivy在屏幕上不可見時,它的onStop()方法被調用。

     void onCreate() 
         void onStart(Intent intent) 
         void onDestroy()

    Service lifecycle 服務的生命週期

    服務可以用兩種方式調用:

    兩種模式不是完全分開的。你可以綁定一個被startService()啓動的服務。如,一個後臺音樂服務可以被一個Intent對象定義音樂播放,通過調用startService()啓動。隨後,用戶想實行一些控制或獲取正在播放的音樂信息時,activity可通過bindService()建立連接。這種情況,stopService()不會停止服務,直到最後一個綁定的連接關閉時。

    類似actitivy,服務也有一些生命週期方法,你可以實現它們改變狀態。但它們比actitivy要少,僅僅三個方法,他們是public的,不是protected:
             

    實現這些方法,你可以操作兩種嵌套的服務生命週期循環:

    onCreate()和onDestroy()可被所有服務對象調用,不管是被Context.startService()還是Context.bindService()方法啓動。然而,onStart()僅被那些通過startService()啓動的服務調用。

    如果服務允許外界綁定它,有三個附加的回調方法可供實現:

    IBinder onBind(Intent intent) 
    boolean onUnbind(Intent intent) 
    void onRebind(Intent intent)

     

    onBind()回調方法通過被授意調用bindService的Intent對象傳遞,而onUnbind()通過被授意調用unbindService()傳遞。如果服務允許綁定,onBind()方法返回客戶端與服務聯繫統的通訊頻道。

    下面的圖表說明了服務的生命週期方法。儘管被startService()啓動的服務和bindService()啓動的服務是分開的,但請注意,不管服務是怎麼啓動的,客戶端都可以綁定它,因此任何服務可以接收到onBind()和onUnbind()請求。

     

     

     

    Processes and lifecycles 進程和生命週期

     

    Android系統試圖儘可能的長久維護應用程序進程,但最終,當內存很低時,它需要移除老的進程。爲了確定哪些進程維持,哪些進程要被殺,Android把每一個進程放入到一個"重要性層次"中,組件的運行和狀態是基於這個"重要性層次"的。最低重要性的進程首先被淘汰,然後是那些次重要的,依此類推。該層次分五層。下面的列表顯示重要性層次順序:

    1.  前臺進程是當前正在操作的進程。擁有以下幾個條件之一的進程,將被認爲是前臺進程:

    進程正在運行一個activity,用戶正在與它交互。(這個activity對象的onResume()方法已經被調用)
    進程是某服務的寄主,用戶正在交互的actitivy綁定了該服務
    進程中擁有某個正在執行它的其中一個生命週期回調方法(onCreate(),onStart()或onDestroy())的服務。
    進程中擁有某個正在執行onReceive()方法的廣播接收器。
    僅有一些前臺服務會在任何給定的時間退出。當他們作爲——如果內存空間不足以讓他們繼續運行時。通常,在那刻,設備已經到了內存分頁狀態,因此必須殺死一些前臺進程保持用戶接口能夠響應。

     
    2.      一個可視(顯示)進程,是沒有任何前臺組件,但仍然能影響用戶屏幕所見的進程。擁有以下兩條件其一的進程被認爲是可視進程:


    (1)進程寄存着一個沒有在前臺,但引然對用戶可見的actitivy(它的onPause()方法已經被調用)。它將發生在,例如,此activity是一個對話框,允許之前的activity在它下面顯示。

    (2)進程寄存着一個被可視actitivy綁定的服務。

    可視進程被認爲是非常的重要,除非殺死它可以保持所有的前臺進程運行,否則,他不會被殺死。

    3.      服務進程運行着某個已經被startService()方法啓動的服務and that does not fall into either of the two higher categories. 儘管服務進程沒有直接對用戶可見,但它們通常執行着用戶關心的任務(如後臺播放中的mp3或者正在網絡上下載數據),因此係統會保持它們的運行,除非沒有足夠的內存空間讓他們與前臺進程和可視進程一同運行時。

    4.      後臺進程是寄存着對當前對用戶不可見的activity(onStop()已經被調用)的進程。這些進程沒有直接影響用戶體驗,可能會在任何時間被暗殺來回收內存爲前臺,可視和服務進程使用。通常會有很多後臺進程運行,它們被保持在LRU(最近最少用戶使用)列表中,確保擁有最常被用戶使用的activity在它們中,最後被暗殺。如果一個actitivy正確的實現了它的生命週期方法,並且捕獲了它的當前狀態,殺死該進程,將不會危害用戶體驗。

    5.      閒置(空)進程是沒有寄存任何activity應用程序組件的進程。保持這類進程的唯一原因是作爲一個提高下次需要寄存在它們裏面運行的組件的啓動速度的緩存。系統常常會殺死這些進程,爲了保持進程緩存與底層的內核緩存的平衡。

     

    Android會基於寄存着當前activity的多個組件進程的重要性,儘量安排它的最高級別的組件。例如,如果某進程寄存一個服務和一個可視actitivy,該進程將被列爲可視進程,而不是服務進程。

    另外,一個進程的等級可能被提升,因爲其他的進程基於他。一個正服務於其他進程的進程,級別永遠不會比正被它服務的進程低。如,在進程A中的content provider正在服務於進程B中的一個客戶端,或者如果進程A中的服務被進程B的組件綁定,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.(譯者注:這段話好像有點矛盾,不太敢翻譯)

     

    因爲運行服務的線程比運行後臺actitivies的進程級別要高,一個activity需要開始執行一個長時間操作時,應該啓動一個服務,而不是通常的自己創建一個線程——特別是如果操作時間可能比activity的生命週期要長時。類似的例子如後臺播放音樂和上傳攝像頭拍下的照片到網站上時。用一個服務來保證操作至少是在"服務進程"優先級別,不管actitivy發生什麼。像在Broadcast receiver lifecycle摘要中的描述,同樣的原因,廣播接收者也應該僱用服務而不是將一個耗時的操作放到一個線程中處理。

     

    Broadcast receiver lifecycle 廣播接收器生命週期

    廣播接收器只有一個生命週期方法:

    void onReceive(Context curContext, Intent broadcastMsg)

    當廣播消息到達接收者時,Android調用他的onReceive()方法,並給他傳調保存着信息的Intent對象。僅當調用該方法時,廣播接收者被認爲是活動的。當onReceive()返回時,它就是不活動的。

     

    擁有活動的廣播接收者的進程,會被保護不被殺死。但是僅僅擁有不活動的廣播組件時,當系統認爲內存應該被其他進程使用時,可以在任何時間被系統殺死。

     

    當與廣播組件頻繁交互時,會有一些問題,因此,某任務應當在獨立的線程中做,與管理其他的用戶接口組件運行的主線程分開。如果onReceive()產生線程然後返回,這個完整的進程,包括新產生的線程,被判斷爲不活動的(),會被提交爲將被殺死的進程。解決這個問題的辦法是爲onReceive()啓動一個服務,讓服務做這工作,因此係統會認爲在進程中仍然活動的工作在做。

    下節有更多關於易被暗殺進程的描述。

     MethodDescriptionKillable?Next
    onCreate()

    當activity第一次啓動時調用。在這,你可以進行一些“全局”的初始工作--創建視圖,給list綁定數據等等。

    如果狀態被保存了,該方法通過Bundle對象捕獲activity之前的狀態。(稍候請查看 Saving Actitivy State)。

    它的下一個方法常常是onStart()。

    No onStart()
         onRestart()

    當activity停止時調用,僅僅指示它再次啓動。僅隨的下一方法通常是onStart()。

    No onStart()
    onStart()

    當activity對用戶可用時,調用。接下來調用onResume()方法,將activity顯示到前臺,或者onStop()方法

    將activity隱藏。

    No onResume()
    or
    onStop()
         onResume()

    僅當activity與用戶準備開始交互時。些時,這一activity位於activitiy的棧頂,讓用戶快速多次的使用。僅接着是通常是onPause()。

    No onPause()
    onPause()

    調用,當系統準備恢復其他activity時。該方法通常用在提交未保存的持久化數據,停止動畫和其他可能佔用CPU的資源等等的情況。該方法內應該儘快的完成操作,因爲下一個activity直到onPause()結束時,纔會恢復。

    使actitivy從後臺恢復,通過onResume(),通過onStop()使它對用戶不可見。

    Yes onResume()
    or
    onStop()
    onStop()

    當activity對用戶不可見時調用。可能會在actitivy被銷燬或者其它actitivy恢復和覆蓋時調用(無論是已存在或是新的activity)。接着,actitivy恢復與用戶交互時,調用onRestart(),銷燬時,調用onDestroy()。

    Yes onRestart()
    or
    onDestroy()
    onDestroy()

    在actitivy銷燬前調用。是actitivy對象銷燬前可調用的最後一個方法。它會在activity即將完成時(有些人在它上面調用finish()方法),或者系統臨時的銷燬此實例存放於硬盤空間時調用。你可以通過isFinishing()方法來識別這兩種方案。

    Yes nothing

 

 

注意上面表格的Killable列。它表示在不執行其他actitivy's代碼的情況下,系統是否可以在方法調用返回的任何時間殺死activity進程。三個方法(onPause(),onStop()和onDestroy())標識爲"是"。因爲onPause()是三個方法中的第一個,它是唯一一個在進程被殺死前保證被調用的方法——(onStop()和onDestroy())不行。因此,你應該在onPause()方法內執行持久化操作(如用戶編輯數據)。

在Killable列中被標識爲"No"的方法,保護寄存actitivy的進程,在方法調用期間不被殺死。

 稍候的摘要,Processes and lifecycle,將描述,一個actitivy在應用上定義爲不可被殺死,仍然有可能被系統殺死——但它僅僅發生在極端的和沒有其他資源可用的情況下。

 

Saving activity state 保存actitivy狀態

當系統,而不是用戶,在關閉一個actitivy時,用戶可能希望返回和找到它的上一個狀態。

爲了在actitivy關閉之前捕獲狀態,你可以實現actitivy的onSaveInstanceState()方法。Android會在actitivy被銷燬前——在onPause()被調用前,調用這個方法。它會傳遞一個你可以記錄activity動態狀態的Bundle對象,使用name-value鍵值對。當actitivy再次啓動時,onCreate()和onStart()方法,都會通過Bundle調用onRestoreInstanceState(),因此兩個方法都可以重新創建之前被捕獲的狀態。

不像之前討論的onPause和其他的方法,onSaveInstanceState()和onRestoreInstanceState()不是生命週期方法。它們常常不會調用。如,在actitivy變成易被系統銷燬的狀態時,Android調用onSaveInstanceState(),但它不會在這個actitivy實例,實際上是被用戶銷燬(如按下BACK)的情況下調用。那種情況下,用戶不希望返回activity,因爲不必保存狀態。

因爲onSaveInstanceState()不常被調用,你應該僅僅用它來記錄過渡的actitivy狀態,不要用來記錄持久化數據,而應該用onPause()替代。

 

 Coordinating activities

當一個actitivy啓動其他activity時,它們同樣的都會經歷生命週期過渡。當一個暫停和停止時,另一個開始。一些場合下,你可能需要這些狀態之間配合。

生命週期的順序被良好的定義,特別是在兩個actitivy在同一個進程當中時:

 1.   當前的actitivy的onPause()方法被調用。

 2.   接下來,正在啓動的actitivy的onCreate(),onStart(),和onResume()方法會按順序被調用。

 3.   然後,如果已啓動的actitivy在屏幕上不可見時,它的onStop()方法被調用。

 void onCreate() 
     void onStart(Intent intent) 
     void onDestroy()

Service lifecycle 服務的生命週期

服務可以用兩種方式調用:

  • 它啓動和運行,直到某東西停止或自己停止時。這種模式下,它被Context.startService()啓動,而被Context.stopService()停止。它可通過Service.stopSelf()或Service.stopSelfResult()停止自身。不管startService()被調用多少次,僅需一個stopService()方法來停止service。
  • 它可被提供給對外用戶的接口所操作。客戶端與服務對象建立連接並調用服務。連接被Context.bindService()方法建立,被Context.unbindService()關閉。多個客戶端可以綁定同一服務端。如果服務沒有準備好,bindService()可以啓動該服務。

兩種模式不是完全分開的。你可以綁定一個被startService()啓動的服務。如,一個後臺音樂服務可以被一個Intent對象定義音樂播放,通過調用startService()啓動。隨後,用戶想實行一些控制或獲取正在播放的音樂信息時,activity可通過bindService()建立連接。這種情況,stopService()不會停止服務,直到最後一個綁定的連接關閉時。

類似actitivy,服務也有一些生命週期方法,你可以實現它們改變狀態。但它們比actitivy要少,僅僅三個方法,他們是public的,不是protected:
         

實現這些方法,你可以操作兩種嵌套的服務生命週期循環:

  • 服務的完整的生命週期,在onCreate()被調用和onDestroy()返回間。類似actitivy,服務在onCreate()方法中進行全局初始化,在onDestroy()方法中釋放所有系統資源。如,音樂播放服務可能在onCreate()方法中創建音樂播放線程,在onDestroy()方法中停止線程。
  • 服務的活動生命週期,在調用onStart()後。該方法被Intent對象示意調用startService()方法。音樂服務將分析這個Intent來確定播放什麼音樂,並開始播放。

    當服務停止時,沒有回調方法調用。--on stop()方法。

onCreate()和onDestroy()可被所有服務對象調用,不管是被Context.startService()還是Context.bindService()方法啓動。然而,onStart()僅被那些通過startService()啓動的服務調用。

如果服務允許外界綁定它,有三個附加的回調方法可供實現:

IBinder onBind(Intent intent) 
boolean onUnbind(Intent intent) 
void onRebind(Intent intent)

 

onBind()回調方法通過被授意調用bindService的Intent對象傳遞,而onUnbind()通過被授意調用unbindService()傳遞。如果服務允許綁定,onBind()方法返回客戶端與服務聯繫統的通訊頻道。

下面的圖表說明了服務的生命週期方法。儘管被startService()啓動的服務和bindService()啓動的服務是分開的,但請注意,不管服務是怎麼啓動的,客戶端都可以綁定它,因此任何服務可以接收到onBind()和onUnbind()請求。

 

 

 

Processes and lifecycles 進程和生命週期

 

Android系統試圖儘可能的長久維護應用程序進程,但最終,當內存很低時,它需要移除老的進程。爲了確定哪些進程維持,哪些進程要被殺,Android把每一個進程放入到一個"重要性層次"中,組件的運行和狀態是基於這個"重要性層次"的。最低重要性的進程首先被淘汰,然後是那些次重要的,依此類推。該層次分五層。下面的列表顯示重要性層次順序:

1.  前臺進程是當前正在操作的進程。擁有以下幾個條件之一的進程,將被認爲是前臺進程:

進程正在運行一個activity,用戶正在與它交互。(這個activity對象的onResume()方法已經被調用)
進程是某服務的寄主,用戶正在交互的actitivy綁定了該服務
進程中擁有某個正在執行它的其中一個生命週期回調方法(onCreate(),onStart()或onDestroy())的服務。
進程中擁有某個正在執行onReceive()方法的廣播接收器。
僅有一些前臺服務會在任何給定的時間退出。當他們作爲——如果內存空間不足以讓他們繼續運行時。通常,在那刻,設備已經到了內存分頁狀態,因此必須殺死一些前臺進程保持用戶接口能夠響應。

 
2.      一個可視(顯示)進程,是沒有任何前臺組件,但仍然能影響用戶屏幕所見的進程。擁有以下兩條件其一的進程被認爲是可視進程:


(1)進程寄存着一個沒有在前臺,但引然對用戶可見的actitivy(它的onPause()方法已經被調用)。它將發生在,例如,此activity是一個對話框,允許之前的activity在它下面顯示。

(2)進程寄存着一個被可視actitivy綁定的服務。

可視進程被認爲是非常的重要,除非殺死它可以保持所有的前臺進程運行,否則,他不會被殺死。

3.      服務進程運行着某個已經被startService()方法啓動的服務and that does not fall into either of the two higher categories. 儘管服務進程沒有直接對用戶可見,但它們通常執行着用戶關心的任務(如後臺播放中的mp3或者正在網絡上下載數據),因此係統會保持它們的運行,除非沒有足夠的內存空間讓他們與前臺進程和可視進程一同運行時。

4.      後臺進程是寄存着對當前對用戶不可見的activity(onStop()已經被調用)的進程。這些進程沒有直接影響用戶體驗,可能會在任何時間被暗殺來回收內存爲前臺,可視和服務進程使用。通常會有很多後臺進程運行,它們被保持在LRU(最近最少用戶使用)列表中,確保擁有最常被用戶使用的activity在它們中,最後被暗殺。如果一個actitivy正確的實現了它的生命週期方法,並且捕獲了它的當前狀態,殺死該進程,將不會危害用戶體驗。

5.      閒置(空)進程是沒有寄存任何activity應用程序組件的進程。保持這類進程的唯一原因是作爲一個提高下次需要寄存在它們裏面運行的組件的啓動速度的緩存。系統常常會殺死這些進程,爲了保持進程緩存與底層的內核緩存的平衡。

 

Android會基於寄存着當前activity的多個組件進程的重要性,儘量安排它的最高級別的組件。例如,如果某進程寄存一個服務和一個可視actitivy,該進程將被列爲可視進程,而不是服務進程。

另外,一個進程的等級可能被提升,因爲其他的進程基於他。一個正服務於其他進程的進程,級別永遠不會比正被它服務的進程低。如,在進程A中的content provider正在服務於進程B中的一個客戶端,或者如果進程A中的服務被進程B的組件綁定,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.(譯者注:這段話好像有點矛盾,不太敢翻譯)

 

因爲運行服務的線程比運行後臺actitivies的進程級別要高,一個activity需要開始執行一個長時間操作時,應該啓動一個服務,而不是通常的自己創建一個線程——特別是如果操作時間可能比activity的生命週期要長時。類似的例子如後臺播放音樂和上傳攝像頭拍下的照片到網站上時。用一個服務來保證操作至少是在"服務進程"優先級別,不管actitivy發生什麼。像在Broadcast receiver lifecycle摘要中的描述,同樣的原因,廣播接收者也應該僱用服務而不是將一個耗時的操作放到一個線程中處理。

 

Broadcast receiver lifecycle 廣播接收器生命週期

廣播接收器只有一個生命週期方法:

void onReceive(Context curContext, Intent broadcastMsg)

當廣播消息到達接收者時,Android調用他的onReceive()方法,並給他傳調保存着信息的Intent對象。僅當調用該方法時,廣播接收者被認爲是活動的。當onReceive()返回時,它就是不活動的。

 

擁有活動的廣播接收者的進程,會被保護不被殺死。但是僅僅擁有不活動的廣播組件時,當系統認爲內存應該被其他進程使用時,可以在任何時間被系統殺死。

 

當與廣播組件頻繁交互時,會有一些問題,因此,某任務應當在獨立的線程中做,與管理其他的用戶接口組件運行的主線程分開。如果onReceive()產生線程然後返回,這個完整的進程,包括新產生的線程,被判斷爲不活動的(),會被提交爲將被殺死的進程。解決這個問題的辦法是爲onReceive()啓動一個服務,讓服務做這工作,因此係統會認爲在進程中仍然活動的工作在做。

下節有更多關於易被暗殺進程的描述。

發佈了64 篇原創文章 · 獲贊 102 · 訪問量 138萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章