03.Service詳解
1. 怎麼在Service中建立Dialog對話方塊?
1.在我們取得Dialog物件後,需給它設定型別,即:
dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT)
<span class="copy-code-btn">复制代码</span>
2.在Manifest中加上許可權:
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINOW"> <span class="copy-code-btn">复制代码</span></uses-permission>
2. 為什麼bindService可以跟Activity生命週期聯動?
1、bindService 方法執行時,LoadedApk 會記錄 ServiceConnection 資訊。
2、Activity 執行 finish 方法時,會通過 LoadedApk 檢查 Activity 是否存在未登出/解綁的 BroadcastReceiver 和 ServiceConnection,如果有,那麼會通知 AMS 登出/解綁對應的 BroadcastReceiver 和 Service,並列印異常資訊,告訴使用者應該主動執行登出/解綁的操作。
3. 服務啟動一般有幾種,服務和activty之間怎麼通訊,服務和服務之間怎麼通訊
方式:
1、startService:
onCreate()--->onStartCommand() ---> onDestory()
如果服務已經開啟,不會重複的執行onCreate(), 而是會呼叫onStartCommand()。一旦服務開啟跟呼叫者(開啟者)就沒有任何關係了。 開啟者退出了,開啟者掛了,服務還在後臺長期的執行。 開啟者不能呼叫服務裡面的方法。
2、bindService:
onCreate() --->onBind()--->onunbind()--->onDestory()
bind的方式開啟服務,繫結服務,呼叫者掛了,服務也會跟著掛掉。 繫結者可以呼叫服務裡面的方法。
通訊:
1、通過Binder物件。
2、通過broadcast(廣播)。
4. 如何保證Service不被殺死?
Android 程序不死從3個層面入手:
A.提供程序優先順序,降低程序被殺死的概率
方法一:監控手機鎖屏解鎖事件,在螢幕鎖屏時啟動1個畫素的 Activity,在使用者解鎖時將 Activity 銷燬掉。
方法二:啟動前臺service。
方法三:提升service優先順序:
在AndroidManifest.xml檔案中對於intent-filter可以通過android:priority = "1000"這個屬性設定最高優先順序,1000是最高值,如果數字越小則優先順序越低,同時適用於廣播。
B. 在程序被殺死後,進行拉活
方法一:註冊高頻率廣播接收器,喚起程序。如網路變化,解鎖螢幕,開機等
方法二:雙程序相互喚起。
方法三:依靠系統喚起。
方法四:onDestroy方法裡重啟service:service + broadcast 方式,就是當service走ondestory的時候,傳送一個自定義的廣播,當收到廣播的時候,重新啟動service;
C. 依靠第三方
根據終端不同,在小米手機(包括 MIUI)接入小米推送、華為手機接入華為推送;其他手機可以考慮接入騰訊信鴿或極光推送與小米推送做 A/B Test。
5. IntentService
IntentService是一種特殊的Service,它繼承了Service並且它是一個抽象類,因此必須建立它的子類才能使用IntentService。
原理
在實現上,IntentService封裝了HandlerThread和Handler。當IntentService被第一次啟動時,它的onCreate()方法會被呼叫,onCreat()方法會建立一個HandlerThread,然後使用它的Looper來構造一個Handler物件mServiceHandler,這樣通過mServiceHandler傳送的訊息最終都會在HandlerThread中執行。
生成一個預設的且與主執行緒互相獨立的工作者執行緒來執行所有傳送至onStartCommand()方法的Intetnt。
生成一個工作佇列來傳送Intent物件給onHandleIntent()方法,同一時刻只傳送一個Intent物件,這樣一來,你就不必擔心多執行緒的問題。在所有的請求(Intent)都被執行完以後會自動停止服務,所以,你不需要自己去呼叫stopSelf()方法來停止。
該服務提供了一個onBind()方法的預設實現,它返回null。
提供了一個onStartCommand()方法的預設實現,它將Intent先傳送至工作佇列,然後從工作佇列中每次取出一個傳送至onHandleIntent()方法,在該方法中對Intent做相應的處理。
6. 為什麼在mServiceHandler的handleMessage()回撥方法中執行完onHandlerIntent()方法後要使用帶引數的stopSelf()方法?
因為stopSel()方法會立即停止服務,而stopSelf(int startId)會等待所有的訊息都處理完畢後才終止服務,一般來說,stopSelf(int startId)在嘗試停止服務之前會判斷最近啟動服務的次數是否和startId相等,如果相等就立刻停止服務,不相等則不停止服務。
7. Service的兩種啟動方法,有什麼區別
1.在Context中通過public boolean bindService(Intent service,ServiceConnection conn,int flags)
方法來進行Service與Context的關聯並啟動,並且Service的生命週期依附於Context(不求同時同分同秒生!但求同時同分同秒屎!!)。
2.通過 public ComponentName startService(Intent service)
方法去啟動一個Service,此時Service的生命週期與啟動它的Context無關。
3.要注意的是,whatever,都需要在xml裡註冊你的Service,就像這樣:
<service
android:name=".packnameName.youServiceName"
android:enabled="true" />
8. onStartCommand 的幾種模式
-
START_NOT_STICKY
如果返回 START_NOT_STICKY,表示當 Service 執行的程序被 Android 系統強制殺掉之後,
不會重新建立該 Service。當然如果在其被殺掉之後一段時間又呼叫了 startService,那麼該
Service 又將被例項化。那什麼情境下返回該值比較恰當呢?
如果我們某個 Service 執行的工作被中斷幾次無關緊要或者對 Android 記憶體緊張的情況下需
要被殺掉且不會立即重新建立這種行為也可接受,那麼我們便可將 onStartCommand 的返
回值設定為 START_NOT_STICKY。
舉個例子,某個 Service 需要定時從伺服器獲取最新資料:通過一個定時器每隔指定的 N 分
鍾讓定時器啟動 Service 去獲取服務端的最新資料。當執行到 Service 的 onStartCommand
時,在該方法內再規劃一個 N 分鐘後的定時器用於再次啟動該 Service 並開闢一個新的執行緒
去執行網路操作。假設Service在從伺服器獲取最新資料的過程中被Android系統強制殺掉,
Service 不會再重新建立,這也沒關係,因為再過 N 分鐘定時器就會再次啟動該 Service 並重
新獲取資料。
-
START_STICKY
如果返回 START_STICKY,表示 Service 執行的程序被 Android 系統強制殺掉之後,Android
系統會將該 Service 依然設定為 started 狀態(即執行狀態),但是不再儲存 onStartCommand
方法傳入的 intent 物件,然後 Android 系統會嘗試再次重新建立該 Service,並執行
onStartCommand 回撥方法,但是 onStartCommand 回撥方法的 Intent 引數為 null,也就是
onStartCommand 方法雖然會執行但是獲取不到 intent 資訊。如果你的 Service 可以在任意
時刻執行或結束都沒什麼問題,而且不需要 intent 資訊,那麼就可以在 onStartCommand 方
法中返回 START_STICKY,比如一個用來播放背景音樂功能的 Service 就適合返回該值。
-
START_REDELIVER_INTENT
如果返回 START_REDELIVER_INTENT,表示 Service 執行的程序被 Android 系統強制殺掉之
後,與返回 START_STICKY 的情況類似,Android 系統會將再次重新建立該 Service,並執行
onStartCommand 回撥方法,但是不同的是,Android 系統會再次將 Service 在被殺掉之前
最後一次傳入 onStartCommand 方法中的 Intent 再次保留下來並再次傳入到重新建立後的
Service 的 onStartCommand 方法中,這樣我們就能讀取到 intent 引數。只要返回
START_REDELIVER_INTENT,那麼 onStartCommand 重的 intent 一定不是 null。如果我們的
Service 需要依賴具體的 Intent 才能執行(需要從 Intent 中讀取相關資料資訊等),並且在強
制銷燬後有必要重新建立執行,那麼這樣的 Service 就適合返回 START_REDELIVER_INTENT
9. Service 和 IntentService 的區別?
【參考】:
-
1、IntentService 是繼承並處理非同步請求的一個類,在 IntentService 內有一個工作執行緒來處理耗時操作,啟動 IntentService 的方式和啟動傳統的 Service 一樣,同時,當任務執行完後,IntentService 會自動停止,而不需要我們手動去控制或 stopSelf()。另外,可以啟動 IntentService 多次 ,而 每 一個 耗時 操作 會以工 作 佇列 的方 式 在 IntentService 的onHandleIntent 回撥方法中執行,並且,每次只會執行一個工作執行緒,執行完第一個再執行第二個,以此類推。
-
2、子類需繼承 IntentService 並且實現裡面的 onHandlerIntent 抽象方法來處理 intent 型別
的任務請求。 -
3、子類需要重寫預設的構造方法,且在構造方法中呼叫父類帶引數的構造方法。
-
4、IntentService 類內部利用 HandlerThread+Handler 構建了一個帶有訊息迴圈處理機制的後臺工作執行緒,客戶端只需呼叫 Content#startService(Intent)將 Intent 任務請求放入後臺工作佇列中,且客戶端無需關注服務是否結束,非常適合一次性的後臺任務。比如瀏覽器下載檔案,退出當前瀏覽器之後,下載任務依然存在後臺,直到下載檔案結束,服務自動銷燬。只要當前 IntentService 服務沒有被銷燬,客戶端就可以同時投放多個 Intent 非同步任務請求,IntentService 服務端這邊是順序執行當前後臺工作佇列中的 Intent 請求的,也就是每一時刻只能執行一個 Intent 請求,直到該 Intent 處理結束才處理下一個 Intent。因為 IntentService類內部利用 HandlerThread+Handler 構建的是一個單執行緒來處理非同步任務。
10 .Service 和 Activity 通訊
【參考】
Activity 呼叫 bindService (Intent service, ServiceConnection conn, int flags)方法,得到 Service物件的一個引用,這樣 Activity 可以直接呼叫到 Service 中的方法,如果要主動通知 Activity,我們可以利用回撥方法Service 向 Activity 傳送訊息,可以使用廣播,當然 Activity 要註冊相應的接收器。比如 Service要向多個 Activity 傳送同樣的訊息的話,用這種方法就更好