標籤:android開發
使用IntentService
1.Service缺陷 由於Service本身存在以下兩個問題: (1)Service不會專門啟動一條單獨的進程,Service與他所在應用位於同一進程中; (2)Service也不是專門一條新的線程,如果我們在Service中直接處理耗時的任務,那麼就會導致應用程式出現假性"卡死"。如果我們需要在Service處理耗時任務,也可以在Service的onCreate()方法中啟動一條新線程來處理該耗時任務(如上例)。但是,問題來了,啟動Service的Activity可能隨時被使用者退出,如果在子線程還沒有結束的情況下,Activity已經被使用者退出了,此時那些子線程所在的進程就變成了空進程(即沒有任何活動組件的進程),系統需要記憶體時可能會優先終止該進程。如果宿主進程被終止,那麼該進程內的所有子線程也會被終止,這樣就可能導致子線程無法執行完成。
2.IntentService原理 IntetnService是Service的子類,它不是普通的Service,通過IntentService恰好彌補了Service上述的兩個不足。IntentService主要使用隊列來管理請求Intent,每當用戶端代碼通過Intent請求啟動IntentService時,IntentService會將該Intent排入佇列中,然後開啟一條新的worker線程來處理該Intent。對於非同步startService()請求,IntentService會按次序依次處理隊列中的Intent,該線程保證同一時刻只處理一個Intent。由於IntentService使用新的worker線程處理Intent請求,因此IntentService不會阻塞主線程,所有IntentService自己就可以處理耗時任務了。
3.IntentService使用特徵(1)IntentService會建立單獨的worker線程來處理所有的Intent請求;(2)IntentService會建立單獨的worker線程來處理onHandleIntent()方法實現的代碼,因此開發人員無需處理多線問題;(3)當所有請求處理完成後,IntentService會自動停止,因此開發人員無須調用StopSelf()方法來停止該Service。(4)為Service的onBind()方法提供了預設實現,預設實現的onBind()方法返回null;(5)為Service的onStartCommand()方法提供了預設實現,該實現會將請求Intent添加到隊列中。注釋:擴充IntentService實現Service無須重寫onBind()、onStartCommand()方法,只要重寫onHandleIntent()方法即可。
4.源碼實戰實現:分別啟動普通Service和IntentService,且同時處理耗時任務,對比兩者效果。(1)\src\com\example\android_intentservice\ServiceAndIntentService.java實現:通過兩個按鈕分別啟動普通Service和IntentService
package com.example.android_intentservice;import android.app.Activity;import android.content.Intent;import android.os.Bundle;import android.view.View;public class ServiceAndIntentService extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } //1.啟動普通Service按鈕方法 public void startService(View source) { Intent intent = new Intent(this,MyService.class);//建立需要啟動的service的Intent startService(intent); //啟動Intent指定的Service } //2.啟動IntentService按鈕方法 public void startIntentService(View source) { Intent intent = new Intent(this,MyIntentService.class); startService(intent); }}(2)\res\layout\main.xml實現:設定Button屬性android:onClick,為按鈕綁定回應程式法
...... <Button android:onClick="startService" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="啟動普通Service" /> <Button android:onClick="startIntentService" android:layout_width="186dp" android:layout_height="wrap_content" android:text="啟動IntentService" />
(3)\src\com\example\android_intentservice\MyService.java實現:實現一個普通Service執行耗時任務(20s),觀察是否導致ANR異常(Application Not Responding)
package com.example.android_intentservice;import android.app.Service;import android.content.Intent;import android.os.IBinder;public class MyService extends Service { @Override public IBinder onBind(Intent intent) { return null; } //當啟動Service,調用該方法執行相應代碼 @Override public int onStartCommand(Intent intent, int flags, int startId) { long endTime = System.currentTimeMillis()+20*1000; System.out.println("onStart"); while(System.currentTimeMillis()<endTime) { synchronized(this) { try { wait(endTime-System.currentTimeMillis()); }catch(Exception e) { } } } System.out.println("---普通Service耗時任務執行完成---"); return START_STICKY; } }(4)\src\com\example\android_intentservice\MyIntentService.java實現:實現一個IntentService執行耗時任務(20s),觀察是否導致ANR異常
package com.example.android_intentservice;import android.app.IntentService;import android.content.Intent;public class MyIntentService extends IntentService { public MyIntentService() { super("MyIntentService"); } //IntentService會使用單獨的線程來執行方法的代碼 @Override protected void onHandleIntent(Intent intent) { //該方法內可以執行任何耗時任務,比如下載檔案等,此處只是讓線程暫停20s long endTime = System.currentTimeMillis()+20*1000; System.out.println("onStart"); while(System.currentTimeMillis()<endTime) { synchronized(this) { try { wait(endTime-System.currentTimeMillis()); }catch(Exception e) { } } } System.out.println("---IntentService耗時任務執行完成---"); }}
(5)AndroidManifest.xml實現:在工程檔案中為MyService、MyIntentService配置<service../>資訊
<application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity .......... </activity> <!--配置service--> <service android:name=".MyService"/> <service android:name=".MyIntentService"/> </application>
效果示範:a.當點擊"啟動普通service"時的效果
b.連續點擊7次"啟動IntentService"的效果
升華筆記:1.普通Service是在onStartCommand()方法內執行耗時任務;IntentService在onHandleIntent()方法內執行耗時任務;2.普通Service在沒有建立一個新線程的情況下,其執行耗時任務主要是在應用程式的主線程中完成的,由於普通Service的執行會阻塞主線程,因此啟動該Service執行耗時任務會導致程式出現ANR異常;3.IntentService主要使用隊列來管理請求Intent,每當用戶端代碼通過Intent請求啟動IntentService時,IntentService會將該Intent排入佇列中,然後開啟一條新的worker線程來處理該Intent。由於IntentService會使用單獨的線程來完成該耗時任務,因此啟動MyIntentService不會阻塞前台線程,程式介面就不會失去響應。
參考:http://wear.techbrood.com/reference/android/app/Service.html
Android學習筆記二十五.Service組件入門(三)使用IntentService