IntentService 是繼承於 Service 並處理異步請求的一個類,在 IntentService 內有一個工作線程來處理耗時操作,
每一個安卓應用都會啓動一個進程,然後進程會啓動一個Dalvik虛擬機,即,每個Android應用進程對應着一個獨立的Dalvik虛擬機實例,然後啓動的應用程序再在虛擬機上被解釋執行(dalvik虛擬機,類似於jvm)。
Service使用
創建android服務的類需要繼承Service父類。
創建Service可以通過右鍵文件夾,new—service—service創建。
下面我們創建一個服務,新建後可以通過Ctrl+O重載重要的方法。
public class MyService extends Service { public MyService() { } /** * 綁定服務時纔會調用 * 必須要實現的方法 * @param intent * @return */ @Override public IBinder onBind(Intent intent) { //本服務不綁定組件 throw new UnsupportedOperationException("Not yet implemented"); } /** * 首次創建服務時,系統將調用此方法來執行一次性設置程序(在調用 onStartCommand() 或 onBind() 之前)。 * 如果服務已在運行,則不會調用此方法。該方法只被調用一次 */ @Override public void onCreate() { System.out.println("服務創建:onCreate被調用"); super.onCreate(); } /** * 每次通過startService()方法啓動Service時都會被回調。 * @param intent 啓動時,啓動組件傳遞過來的Intent, Activity可利用Intent封裝所需要的參數並傳遞給Service,intentUser.putExtra("KEY", "518"); * @param flags 表示啓動請求時是否有額外數據,可選值有 0,START_FLAG_REDELIVERY,START_FLAG_RETRY,0代表沒有,它們具體含義如下: * START_FLAG_REDELIVERY 這個值代表了onStartCommand方法的返回值爲 * START_REDELIVER_INTENT,而且在上一次服務被殺死前會去調用stopSelf方法停止服務。其中START_REDELIVER_INTENT意味着當Service因內存不足而被系統kill後,則會重建服務,並通過傳遞給服務的最後一個 Intent 調用 onStartCommand(),此時Intent時有值的。 * START_FLAG_RETRY 該flag代表當onStartCommand調用後一直沒有返回值時,會嘗試重新去調用onStartCommand()。 * @param startId 指明當前服務的唯一ID,與stopSelfResult (int startId)配合使用,stopSelfResult 可以更安全地根據ID停止服務。 * @return */ @Override public int onStartCommand(Intent intent, int flags, int startId) { System.out.println("服務啓動:onStartCommand被調用,flags:"+flags+" startId:"+startId); return super.onStartCommand(intent, flags, startId); } /** * 服務銷燬時的回調 */ @Override public void onDestroy() { System.out.println("服務銷燬:onDestroy被調用"); super.onDestroy(); } }
然後在AndroidManifest.xml裏增加service節點,用於註冊,如果是使用AS創建會自動在AndroidManifest.xml裏增加service節點,如果是創建類繼承service,則需手動添加。
<service android:name=".services.MyService" android:enabled="true" android:exported="true" />
服務創建後,對服務進行調試。
我們在androidTest下的com.kiba.framework.ExampleInstrumentedTest裏編寫單元測試。
單元測試的方法使用JUnit4的註解。
注:JUnit4的J指java,unit指單元,瞭解這個含義,我們在調試遇到問題時,方便精確百度。
PS:JUnit4有很多問題,比如調試斷點時會自動Disconnected斷開連接。
@RunWith(AndroidJUnit4.class) public class ExampleInstrumentedTest { @Test public void useAppContext() { // Context of the app under test. Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); assertEquals("com.kiba.framework", appContext.getPackageName()); } @Test public void servicesTest(){ //不同實例服務調用,先start,後stop Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); Intent it=new Intent(appContext, MyService.class); appContext.startService(it); appContext.stopService(it); Intent it2=new Intent(appContext, MyService.class); appContext.startService(it2); appContext.stopService(it2); assertEquals("com.kiba.framework", appContext.getPackageName()); } @Test public void servicesTest2(){ //同一實例服務調用,先start,後stop Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); Intent it=new Intent(appContext, MyService.class); appContext.startService(it); appContext.stopService(it); appContext.startService(it); appContext.stopService(it); assertEquals("com.kiba.framework", appContext.getPackageName()); } @Test public void servicesTest3(){ //不同實例,不調用銷燬服務方法,只調用start Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); Intent it=new Intent(appContext, MyService.class); appContext.startService(it); Intent it2=new Intent(appContext, MyService.class); appContext.startService(it2); assertEquals("com.kiba.framework", appContext.getPackageName()); } }
調試可以點擊綠色三角,然後debug。
也可以點擊調試項目的按鈕,鼠標放上去,會有提示,如下圖。
調試時,會彈出新界面,在界面裏找到Console,可以查看我們的輸出。
測試結果:
不同實例服務調用,先start,後stop,結果如下:
service重建創建了。
同一實例服務調用,先start,後stop,結果如下:
service重建創建了。
不同實例,不調用銷燬服務方法,只調用start,結果如下:
service未創建。
雖然定義了兩個實例,但onCreate沒有被重複調用,即,同一類型的service,只有顯示調用了stopService纔會銷燬
拓展知識(進程和聲明週期)
Android操作系統嘗試儘可能長時間的保持應用的進程,但當可用內存很低時最終要移走一部分進程。怎樣確定那些程序可以運行,那些要被銷燬,Android讓每一個進程在一個重要級的基礎上運行,重要級低的進程最有可能被淘汰,一共有5級,下面這個列表就是按照重要性排列的:
1 一個前臺進程顯示的是用戶此時需要處理和顯示的。下列的條件有任何一個成立,這個進程都被認爲是在前臺運行的。 a 與用戶正發生交互的。 b 它控制一個與用戶交互的必須的基本的服務。 c 有一個正在調用生命週期的回調函數的service(如onCreate()、onStar()、onDestroy()) d 它有一個正在運行onReceive()方法的廣播接收對象。 只有少數的前臺進程可以在任何給定的時間內運行,銷燬他們是系統萬不得已的、最後的選擇——當內存不夠系統繼續運行下去時。通常,在這一點上,設備已經達到了內存分頁狀態,所以殺掉一些前臺進程來保證能夠響應用戶的需求。
2 一個可用進程沒有任何前臺組件,但它仍然可以影響到用戶的界面。下面兩種情況發生時,可以稱該進程爲可用進程。 它是一個非前臺的activity,但對用戶仍然可用(onPause()方法已經被調用)這是可能發生的,例如:前臺的activity是一個允許上一個activity可見的對話框,即當前activity半透明,能看到前一個activity的界面,它是一個服務於可用activity的服務。
3 一個服務進程是一個通過調用startService()方法啓動的服務,並且不屬於前兩種情況。儘管服務進程沒有直接被用戶看到,但他們確實是用戶所關心的,比如後臺播放音樂或網絡下載數據。所以系統保證他們的運行,直到不能保證所有的前臺可見程序都正常運行時纔會終止他們。
4 一個後臺進程就是一個非當前正在運行的activity(activity的onStop()方法已經被調用),他們不會對用戶體驗造成直接的影響,當沒有足夠內存來運行前臺可見程序時,他們將會被終止。通常,後臺進程會有很多個在運行,所以他們維護一個LRU最近使用程序列表來保證經常運行的activity能最後一個被終止。如果一個activity正確的實現了生命週期的方法,並且保存它當前狀態,殺死這些進程將不會影響到用戶體驗。
5 一個空線程沒有運行任何可用應用程序組,保留他們的唯一原因是爲了設立一個緩存機制,來加快組件啓動的時間。系統經常殺死這些內存來平衡系統的整個系統的資源,進程緩存和基本核心緩存之間的資源。 Android把進程裏優先級最高的activity或服務,作爲這個進程的優先級。例如,一個進程擁有一個服務和一個可見的activity,那麼這個進程將會被定義爲可見進程,而不是服務進程。
此外,如果別的進程依賴某一個進程的話,那麼被依賴的進程會提高優先級。一個進程服務於另一個進程,那麼提供服務的進程會獲得不低於被服務的進程的優先級。例如,如果進程A的一個內容提供商服務於進程B的一個客戶端,或者進程A的一個service被進程B的一個組件綁定,那麼進程A至少擁有和進程B一樣的優先級,或者更高。
onStartCommand裏執行一個長時間運行的操作可能會拖垮這個activity,可以理解爲在activity裏調用了一個函數,該函數長時間執行操作,則應用anr了。
----------------------------------------------------------------------------------------------------
注:此文章爲原創,任何形式的轉載都請聯繫作者獲得授權並註明出處!
若您覺得這篇文章還不錯,請點擊下方的【推薦】,非常感謝!