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 銷燬棧銷燬,最終應用退出。
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 進行資料的增刪改查。
完~
喜歡有幫助的話: 雙擊、評論、轉發,動一動你的小手讓更多的人知道!關注Android_YangKe