Android 組件篇-[Android_YangKe]

Activity

Activity Android 四大組件之一,代表着頁面。它是整個視圖的承載,從下層往上看分別貼附着 Window、ViewGroup、View。同時 Activity 接收用戶的各種手勢、觸屏事件並進行派發。順序從 Activity 開始到 View 結束:Activity->Window->ViewGroup->View。默認 Activity 的啓動模式爲標準模式,我們可以通過 launchMode 標籤在清單配置文件中對此進行修改。

下面我們看 Activity 的生命週期,以及項目中經常出現的幾個場景。

目錄

  • Activity 生命週期

  • 場景一

  • 場景二

  • 場景三

  • 場景四

Activity 生命週期

1> onCreate() 
2> onStart()
3> onResume() 
4> onPause() 
5> onStop() 
6> onRestart()
7> onDestory()

場景一
正在展現的 Activity 點擊 Home 按鍵會那些生命週期函數?
會執行 onPause、onSaveInstanceState(非生命週期函數)、onStop。當重新點擊應用圖標時會執行 onRestart、onStart、onResume。點擊Back按鍵會執行 onPause、onStop、onDestory,當重新點擊應用圖標時會執行 onCreate、onStart、onResume。

場景二
現有兩個 Activity 分別爲 a,b。現在啓動 a?a 啓動 b?最後點擊 back 鍵生命週期會如何調用?

1> Activity a 會調用 onCreate、onStart、onResume。
2> Activity a 啓動 Activity b 兩者的生命週期調用順序如下:
   onPause(a)、onCreate、onStart、onResume、onSaveInstanceState(a)、
   onStop(a) 。
3> 點擊 back 鍵 後會調用 onPause(b)、onRestart、onStart、onResume、
   onStop(b)、onDestroy (b)。
//注:onSaveInstanceState 函數在 onPause 之後執行(不一定都會執行),例點擊 back 按鍵。

場景三
現有三個 Activity 分別爲 a1、a2、a3,其中 a2 爲 singleInstance 模式,現在 a1 啓動 a2,a2 啓動 a3,此時呈現的頁面爲 a3,然後點擊 back 按鍵頁面會如何展示?
頁面會回到 a1,如果再次點擊 back 鍵,頁面會回到 a2,再次點擊應用會退出。
原因: Activity 由棧維護,棧的特點是先進後出,默認情況下 Activity 的啓動模式爲標準模式,所以 a1 和 a3 存放在同一個任務棧中,由於 a2 的啓動模式爲 singleInstance 所以 a2 會獨佔一個任務棧,也就是說當前應用現在有兩個任務棧。第一當我們點擊 back 鍵時 a3 所處的棧進行出棧操作,a3 銷燬,a1 展示;再次點擊 a1 銷燬,當前棧銷燬;再次點擊 a2 銷燬棧銷燬,最終應用退出。

場景四
Activity 中 commit 一個 Fragment,兩者分別會執行哪些生命週期函數。
1> 首先 Activity 會執行 onCreate 函數,隨後 Fragment 會執行 onAttach、onCreate、onCreateView、onActivityCreated、onStart,隨後 Activity 執行 onStart、隨後 Activity 執行 onResume,隨後 Fragment 執行 onResume,此時頁面真正呈現同時可以進行操作。
2> 點擊 Back 按鍵。首先 Fragment 執行 onPause、其次 Activity 執行 onPause;隨後 Fragment 執行 onStop、Activity 執行 onStop;最後 Fragment 執行 onDestoryView、onDestory、onDetach,Activity 執行 onDestory 函數。
3> 點擊 Home 按鍵。Fragment 執行 onPause,Activity 執行 onPause,Fragment 執行 onStop,Activity 執行 onStop 函數。

SingleTask 與 SingleInstance 區別?
Activity 由棧進行維護。SingleTask 模式的 Activity 可以與非 SingleInstance 模式的 Activity 在一個任務棧共存。 而 SingleInstance 模式的 Activity 則是獨佔一個 Activity 任務棧。同時使用場景不同:SingleTask 對應的 Activity 一般用於做應用主頁面,SingleInstance 對應的 Activity 一般用於做廣告頁面。

如何啓動其他應用的 Activity?

1> 創建 Intent 對象
   Intent intent = new Intent();
2> 配置 Intent
   //包名,包名+類名(全路徑)
   intent.setClassName("com.linxcool", "com.linxcool.PlaneActivity"));
3> 調用 startActivity 函數

Activity 的啓動過程?
首先 Activity 的啓動分爲兩種方式:

  • 通過 launcher 進程啓動

  • 通過 startActivity 啓動

前者:launcher 應用與 ActivityManagerServer(AMS)通信,告知 AMS 我要啓動一個 Activity,系統 fork 出進程,執行 Java main 函數,創建 ActivityThread,實例化 Application,開啓消息循環,創建 Activity,效驗 Activity 合法性,啓動 Activity,加載 xml 佈局,執行 View 的 onMeasure、onLayout、onDraw 函數,最終視圖呈現。

後者:由 Instrumentation 對象效驗 Activity 的合法性,視情況創建 Activity 實例,回調 Activity 的 onCreate 函數,加載 xml 佈局文件,執行 View 的 onMeasure、onLayout、onDraw 函數,最終視圖呈現。

onNewIntent 調用時機?
一般常見於非標準啓動模式的 Activity 中。舉個例子:當 Activity 的啓動模式爲 SingleTask 時,同時任務棧中有此 Activity 的實例我們再次啓動此 Activity 時,此 Activity 的實例不會重新創建,只會執行 onNewIntent 函數,然後執行 onRestart、onStart、onResume 函數。注:一般情況下 onNewIntent 函數是不會被觸發的。。
總結:onNewIntent 在 onRestart 函數之前執行,大多數情況下並不會被觸發,只有 Activity 的啓動模式被我們主動修改了纔會主動調用,同時此 Activity 實例必須在任務棧中已經存在。


Service

談談 Service 的生命週期?
Service 啓動分爲兩種方式,分別爲:

  • startService

  • bindService
    前者生命週期:
    onCreate->onStartCommand->onDestory
    後者生命週期:
    onCreate->onBind->onUnbind->onDestory

下面我們看兩個場景:
場景一
一個 Service 通過 startService 啓動後,調用 bindService 只會觸發 onBind 函數,當被綁定的 Activity 銷燬時只會調用 onUnbind 函數。我們也可以通過調用 unbindService 與此 Service 解除綁定。注:onDestory 函數並沒有被調用,如果想要銷燬此 Service 我們必須主動調用 stopService。

場景二
一個 Service 通過 bindService 啓動後,再次調用 startService 只會調用 onStartCommand 函數,我們調用 stopService 函數並不會觸發任何 Service 的生命週期函數,我們可以主動調用 unbindService 函數進行解綁,需要注意的是 onDestory 函數並不會執行。我們 Activity 被銷燬只會觸發 Unbind 函數,onDestory 函數同樣不會被觸發。如果想要真正的停止掉這個 Service 我們可以通過主動調用 stopService 函數。

Service 兩種啓動方式及區別

  • startService

  • bindService

前者:
生命週期函數執行順序:onCreate->onStartCommand->onDestory

startService 函數調用兩次 Service 並不會重新創建,只會執行 onStartCommand 函數,如果所在的 Activity 銷燬並不會影響 Service 的正常運行,我們可以通過 stopService 函數來主動停止此 Service,一般用於 Activity 與 Service 通信較少的情況。

後者:
生命週期函數執行順序:onCreate->onBind->onUnbind->onDestory

bindService 函數調用只會執行 onCreate、onBind 函數,當我們再次調用不會觸發 Service 的任何生命週期函數。Service 的存亡與 Activity 綁定,換個說法就是當 Activity 銷燬時 Service 會一併停止,我們也可以通過 unbindService 函數來主動停止此 Service,一般用於 Activity 與 Service 與 Activity 通信頻繁場景。

一個 Activty 先 start 一個 Service 後,再 bind 時會回調什麼方法?此時如何做才能回調 Service 的 onDestory 方法?
startService 會執行 onCreate、onStartCommand,此時如果調用 bindService 函數會調用 onBind 函數。我們先 unBindService 接着調用 stopService 就可以觸發 Service 的 onDestory 函數,或者先調用 stopService 函數然後接着調用 unBindService 函數。

Service 與 Activity 如何通信?
1> 使用 bindService 的形式,bindService 函數中傳入要 ServiceConnection 對象,從此對象的 onServiceConnected 函數中獲取 Service 中的 IBinder 對象,進行通信。
2> 廣播。
3>其他第三方庫。

IntentService?
IntentService 繼承自 Service 並處理異步請求的一個類,在 IntentService 內部有一個工作線程來處理耗時操作,當任務執行結束後 IntentService 會自動停止服務。如果 IntentService 啓動多次,每一個耗時任務會以工作隊列的形式在其 onHandleIntent 函數中回調執行,依次執行直到執行結束。

如何將 Service 改爲前臺服務?
前臺服務是一種特殊的服務,它的特點是優先級很高,當系統內存比較低時 Android 系統也不會回收此類型服務。

舉個例子:如果我們在 Service 中播放音樂,由於設備內存較低觸發了 gc 突然 Service 被系統殺掉,但我們通過某種技術又將 Service 拉起重新進行音樂,可想而知這種體驗是相對不好的。那麼如何解決此問題發生呢?答案是將 Service 修改爲前臺服務。

如何開啓?通過在 Service 的 onStartCommand 函數中調用 startForeground 函數。如何關閉?通過在 Service 的 onDestroy 函數中調用 stopForeground 函數。需要注意的是,如果我們將服務的優先級調整爲前臺,系統會強制在通知欄給用戶一個提示。我們來看下 startForeground。

   /**
     * @param id The identifier for this notification as per
     * {@link NotificationManager#notify(int, Notification)
     * NotificationManager.notify(int, Notification)}; must not be 0.
     * @param notification The Notification to be displayed.
     * 
     * @see #stopForeground(boolean)
     */
    public final void startForeground(int id, Notification notification) {
        try {
            mActivityManager.setServiceForeground(
                    new ComponentName(this, mClassName), mToken, id,
                    notification, 0);
        } catch (RemoteException ex) {
        }
    }

  • id 通知標識符

  • notification 要展示在通知欄的具體對象

通過上面我們可以發現此函數接受兩個參數一個是用於通知的對象(notification),一個是通知的一個標識。也就是說我們想要開啓前臺服務,就必須在通知欄強制彈出一個通知。


Broadcast

廣播有幾種形式?什麼特點?
廣播按照註冊方式可以分爲兩種類型:

  • 本地廣播

  • 系統廣播(全局廣播)

本地廣播
本地廣播的特點是廣播由應用本身發送,發送的廣播只能在應用內接受,其他應用無法收到本發出的廣播,安全性更強,性能更高。

系統廣播
系統廣播可以被任意應用接收,性能和安全性相對本地廣播而言較低。系統廣播註冊方式分爲兩種,分別爲動態註冊和靜態註冊。

廣播按照順序可以分爲:

  • 有序廣播

  • 無序廣播

有序廣播的特點是,廣播的接收是有優先級的,優先級高的廣播可以最先接受到廣播。如果優先級高的廣播接收器收到廣播後進行了截斷,則後續廣播接收器無法繼續收到廣播。例:現在有 br1、br2、br3 三個廣播接收器,其中 br1 優先級最高、br2 其次、br3 最低,如果此時 br1 接收到廣播後調用了 abortBroadcast 函數,後續 br2 和 br3 則無法收到應用發出的有序廣播。

其他種類的廣播都可以成爲無序廣播,這裏就不在做介紹。

廣播的註冊方式?

  • 動態註冊

  • 靜態註冊

動態註冊:
使用 Java 代碼進行註冊,一般在 onCreate 函數中進行註冊,onDestory 函數進行解除註冊。廣播接收器的生命週期常伴隨應用的生命週期,動態註冊的廣播可控性更強,優先級相對靜態註冊而言更高。

靜態註冊:
在 xml 中進行註冊的廣播,靜態註冊是常駐型 ,也就是說當應用程序關閉後,如果有信息廣播來,程序仍會被系統調用運行,生命週期更長。例:監測開機廣播。

總結:
廣播按照註冊方式可以分爲兩種分別爲:動態註冊,靜態註冊。按照廣播類型可以分爲:系統廣播,應用內廣播 or 普通廣播和有序廣播。動態註冊的廣播生命週期一般伴隨應用的生命週期,優先級比較高;靜態註冊的廣播反之。有序廣播和無序廣播的區別是有序廣播是同步進行的,有先後順序,無序廣播反之。


ContentProvider

ContentProvider 存在的意義及作用?
爲了在應用程序之間交換數據,Android 提供了ContentProvider,它是不同應用程序之間進行數據交換的標準 API。當一個應用程序需要把自己的數據暴露給其他應用程序使用時,該應用程序可以通過提供 ContentProvider 來實現。而其他應用程序需要使用這些數據時,不管提供數據的應用程序是否啓動,我們都可以通過 ContentResolver 來操作 ContentProvider 暴露的數據。其中包括增加數據 insert、刪除數據 delete、修改數據 update、查詢數據 query 等。雖然大部分使用 ContentProvider 操作的數據都來自於數據庫,但是也可以來自於文件,如:SharedPreferences、XML 或網絡等其他存儲方式。

簡而言之,ContentProvider 作爲 Android 四大組件之一,它的誕生主要是給不同應用提供內容訪問。ContentProvider 封裝了數據的跨進程傳輸,我們可以直接使用 getContentResolver() 拿到 ContentResolver 進行數據的增刪改查。

完~


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章