Activity
1.當指定的Activity在用戶可見後才進行廣播註冊,在用戶不可見後對廣播進行註銷,那麼應該在哪兩個回調中做這個處理?
可見——onStart();
不可見——onStop();
2.如果有一些數據在Activity跳轉(或者離開時)要保存到數據庫中,在onPause()中執行比較好;
理由:onPause()方法是進程被殺死之前保證會執行的最後一個方法,簡單來說,在執行了onPause()方法之後,直到執 行onResume()之前,該activity所在的進程都是有可能“突然死亡”的,onStop()和onDestroy()方法並不能保證一定會被執行。所以onPause()方法是持久化相關數據的最後的可靠時機。
3.ActivityA啓動ActivityB,它們的生命週期變化:
ActivityA:onCreate()---onStart()---onResume()---啓動ActivityB---onPause()---onStop()
ActivityB: onCreate()---onStart()---onResume()---Back---onPause()---ActivityA重新啓動---onStop()---onDestory()
ActivityA: onRestart()---onStart()---onResume()---Back---onPause()---onStop()---onDestory()
注:如果內存不夠,A可能執行onDestory(),建議在savedInstanceState中保存關鍵數據
4.ActivityA 通過intent顯示啓動了ActivityB ,當B處於可見時,A是否一定調用onStop()?
不一定,若B是dialog(對話框),當B處於可見時,A也可見(但不能與用戶交互,處於onPause()),不會調用onStop() .
5.不是所有的數據存儲要放在onPause()中
當要執行比較耗時 的操作時,不要在onPause()中執行,因爲會影響下一個活動的顯示,onPause()不執行完,下一個活動的onResume()無法執行,無法正常顯示。Service
開啓服務有兩種方式: StartService() 和 BindService().
starService 開啓一個服務,會執行onCreate()方法,和onStart()方法,如果服務已經開啓,只會執行onStart()方法。
服務開啓後,就會在後臺長期運行,可以在設置界面找到,我們可以在設置界面手動關閉它,服務就會停止運行。
startService開啓服務也叫做非綁定模式開啓服務 ,生命週期 第一次執行的方法有 onCreate().onstartCommand(),到service關閉的時候執行onDestroy()方法。
bindService開啓服務也叫做綁定模式開啓服務,生命週期 第一次執行的方法有 onCreate(), onBind()方法,
銷燬的時候執行onUnBind(),onDestroy()方法, bindService開啓服務有個特點,它在設置界面時找不到的,所以我們無法手動在設置界面銷燬它,不過它的生命週期依附於Activity,當Activity銷燬的時候,這個服務也就跟着銷燬。
上面兩種生命週期實在相對單純的模式下的情形,我們在開發的過程中還必須注意Service實例只會有一個,也就是說如果當前要啓動的Service已經存在了那麼就不會再次創建該Service當然也不會調用onCreate()方法;
一個Service可以被多個客戶進行綁定,只有所有綁定對象都執行了onBind()方法後該Service纔會銷燬,不過如果有一個用戶執行了onStart()方法,那麼這個時候如果其他所有的bind客戶都執行了unBind()。該Service也不會銷燬,很多應用都是用startService和bindService混合開啓服務,比如音樂播放器,第三方支付等
在前臺運行服務
我們之前定義的服務都是運行在後臺的,這樣的服務當系統內存不足時將會被殺死,而用戶卻毫不知情。如果想要一個服務的狀態可以被用戶一眼看到,那麼可以使用前臺服務。
將一個服務設置爲前臺服務,只需要在綁定時調用startForeground將自己設置爲前臺服務即可,其中第二個參數是Notification對象,表示在通知欄中顯示的通知。
@Override public void onCreate() { super.onCreate(); Log.d(TAG, "onCreate: "); Intent intent = new Intent(this,MainActivity.class); PendingIntent pi = PendingIntent.getActivity(this,0,intent,0); Notification notification = new NotificationCompat.Builder(this) .setContentTitle("this is content title") .setContentText("this is content text") .setWhen(System.currentTimeMillis()) .setSmallIcon(R.mipmap.ic_launcher) .setLargeIcon(BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher)) .setContentIntent(pi) .build(); /** * 參數一:通知id,參數二:通知的對象 */ startForeground(1,notification); }
服務是運行在主線程中,故不能執行耗時操作,具體實現是在服務具體方法內開啓一個子線程去執行,而且如果想要實現讓服務在執行完畢後自動停止的功能,需要調用stopSelf()方法。
@Override public int onStartCommand(Intent intent, int flags, int startId) { Log.d(TAG, "onStartCommand: "); //在服務具體方法中開啓線程執行耗時操作 new Thread(new Runnable() { @Override public void run() { //具體邏輯 //實現讓服務執行完畢後自動停止 stopSelf(); } }).start(); return super.onStartCommand(intent, flags, startId); }
而IntentService的出現實現了開啓線程和自動停止的功能
IntentService
服務和Activity一樣,都是Android的組件,生命週期中的各個方法也都運行在主線程中。所以雖然服務名爲“服務”,但是如果想要其中執行耗時任務,還是需要將任務放入到線程中。IntentService就是這樣一種服務,Android已經爲我們封裝了創建線程的過程,只需要我們直接實現耗時任務的邏輯即可。IntentService的使用有如下限制:
- 不可以直接和用戶交互。如果需要將結果與UI交互,需要將結果返回給Activity
- 工作請求遵循線性,FIFO
- IntentService中的操作不能被打斷
使用IntentService:
使用IntentService,只需要繼承自IntentService類,需要實現onHandleIntent方法,在這個方法中就可以編寫耗時任務。
public class MyIntentService extends IntentService { private static final String TAG = "MyIntentService"; public MyIntentService() { super("MyIntentService");//調用父類有參構造函數 } @Override protected void onHandleIntent(Intent intent) { Log.d(TAG, "Thread id is " + Thread.currentThread().getId()); } @Override public void onDestroy() { super.onDestroy(); Log.d(TAG, "onDestroy: "); } }
BroadCastReceiver
廣播分兩種: 有序廣播和無序廣播
無序廣播:sendBroadcast()方法發送的廣播爲無序廣播,無序廣播邏輯上可以被任何廣播接受者接收到,優點是效率高。缺點是一個接收者不能將處理結果傳遞給下一個接收者,傳遞的數據在傳輸過程中不能被修改,並無法終止廣播的傳播。
有序廣播:sendOrderedBroadcast()方法發送的廣播爲有序廣播,有序廣播依次傳播,列如有三個廣播接收者A,B,C, 優先級是A>B>C, 此時發送一條廣播,那這個消息先傳給A,再傳給B, 最後傳給C,每個接收者都有權終止廣播,比如B終止廣播,C就無法接受到, 此外A接收到廣播後可以對結果對象進行操作,當廣播傳給B時,B可以從結果對象中獲取A存入的數據。
在通過context.sendOrderedBroadcast(intent, receiverPermission, resultReceiver, scheduler,initialCode, initialData, initialExtras);時我們可以指定resultReceiver廣播接收者,這個接收者我們可以認爲是最終接收者,通常情況下如果比他優先級更高的接收者如果沒有終止廣播,那麼他的onReceive方法會被執行兩次,第一次是正常的按照優先級順序執行,第二次是作爲最終接收者接收,如果比他優先級高的接收者終止了廣播,那麼他依然能接收到廣播。
BroadcastReceiver有兩種註冊方法,
在Androidmainfest中註冊廣播接收者稱爲靜態註冊,
在代碼中註冊稱爲動態註冊。
靜態註冊的廣播接收者只要app在系統中註冊則可以一直接收到廣播消息,
動態註冊的廣播接收者當註冊的activity或Service銷燬了那麼就接收不到廣播了
注意:
1.BroadcastReceiver的生命週期是非常短暫的,在接收廣播的時候創建,onReceiver()方法結束之後銷燬
2. 廣播接收者中不要做一些耗時的工作,否則會彈出Application No Response(應用無響應anr)錯誤對話框,,一般耗時的較長的操作最好放在服務中完成。
3.最好也不要在廣播接收者中創建子線程做耗時操作,因爲廣播接收者被銷燬後進程就成爲空進程,而空進程很容易被系統殺掉。
相關問題:
1.動態廣播註冊與銷燬在Activity那兩個生命週期進行?
onCreate()---onDestory();
2.靜態廣播與動態廣播的區別?特點和應用場景
生存期:靜態廣播的生存期可以比動態廣播的長很多,因爲靜態廣播很多都是用來對系統時間進行監聽,比如我們可以監聽手機開機。而動態廣播會隨着context的終止而終止
優先級:動態廣播的優先級比靜態廣播高
使用方式:動態廣播無需在AndroidManifest.xml中聲明即可直接使用,也即動態;而靜態廣播則需要,有時候還要在AndroidManifest.xml中加上一些權限的聲明
3.有時候基於數據安全考慮,我們想發送廣播只有自己(本進程)能接收到,怎麼處理?
使用本地廣播
4.在 Android 中用廣播來更新 UI 界面好嗎?
大多數情況下可以採用廣播來更新UI,但是不能太過耗時,還有頻繁更新UI,使用廣播是不推薦的。
5.BroadcastReceiver 和 EventBus 有啥不同?
如果是和 Android 系統相關的通知,我們還得選擇本地廣播。廣播相對於其他實現方式,是很重量級的,它消耗的資源較多。它的優勢體現在和 SDK 的緊密聯繫,onReceive()
方法自帶了 Context 和 Intent 參數,所以在一定意義上實現了便捷性,但如果對 Context 和 Intent 應用很少或者說只做很少的交互的話,使用廣播真的就是一種浪費!!!
EventBus優點:
調度靈活,使用簡單,快速且輕量;
缺點:EventBus 最大的缺點在於其邏輯性
和Android的 BroadcastReceiver/Intent 不同,EventBus 用了標準java類的事件,提供了更方便的API。當你要用很多case去區分事件時,EventBus很一個很好的解決方案,你不需要大量設置intent、給intent添加extras、實現大量broadcast receivers、再獲得intent、從intent裏提取數據。而且,EventBus 的開銷低得多。
6.8.0之後廣播的變化
Android 8.0的平臺上,應用不能對大部分的廣播進行靜態註冊
ContextProvider
(1)android平臺提供了ContentProvider使一個應用程序的指定數據集提供給其他應用程序。其他應用可以通過ContentResolver類從該內容提供者中獲取或存入數據。
(2)只有需要在多個應用程序間共享數據是才需要內容提供者。例如,通訊錄數據被多個應用程序使用,且必須存儲在一個內容提供者中。它的好處是統一數據訪問方式。
(3)ContentProvider實現數據共享。ContentProvider用於保存和獲取數據,並使其對所有應用程序可見。這是不同應用程序間共享數據的唯一方式,因爲android沒有提供所有應用共同訪問的公共存儲區。
(4)開發人員不會直接使用ContentProvider類的對象,大多數是通過ContentResolver對象實現對ContentProvider的操作。
(5)ContentProvider使用URI來唯一標識其數據集,這裏的URI以content://作爲前綴,表示該數據由ContentProvider來管理。
重點理解和應用Content Provider 中API涉及到的相應參數:
利用這些參數和相應API完成數據的篩選。
/**
* @param uri 指定查詢應用程序下具體表
* @param projection 指定查詢的列名
* @param selection 指定where的約束條件
* @param selectionArgs 爲where中的佔位符提供具體的值
* @param sortOrder 指定查詢的排序方式
*/
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder)