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了。
----------------------------------------------------------------------------------------------------
注:此文章為原創,任何形式的轉載都請聯絡作者獲得授權並註明出處!
若您覺得這篇文章還不錯,請點選下方的【推薦】,非常感謝!