IntentService是什麼?
IntentService是Service的一種,使用上較為方便簡單。其背景執行方式是透過 HandleThread,因此單個IntentService上的任務是循序執行的,可以保證執行緒安全。不同的IntentService在執行上也不會互相干擾。
IntentService適合用於客戶端不須和Service互動的情況下,基本上由客戶端呼叫startService並指定啟動的IntentService。
簡單的IntentService實作
public class SimpleIntentService extends IntentService { public SimpleIntentService() { super("SimpleIntentService"); } @Override protected void onHandleIntent(Intent intent) { } }
onHandleIntent方法會執行在新的執行緒上,也是放置耗時操作的位置。其參數intent就是從客戶端傳遞過來的intent。
另外需要在AndroidManifest.xml宣告該IntentService
<service android:exported="false" android:name=".simpleintentservice.SimpleIntentService"> </service>
android:exported=”false”代表是否可以由其他的App啟動。
啟動IntentService
客戶端透過呼叫startService方法來啟動IntentService
public class SimpleIntentServiceActivity extends AppCompatActivitye { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_simple_intent_service); Intent launchSimpleIntentService = new Intent(this, SimpleIntentService.class); startService(launchSimpleIntentService); } }
客戶端傳遞資料到IntentService
從客戶端透過intent放置資料便可傳遞到IntentService
Intent launchSimpleIntentService = new Intent(this, SimpleIntentService.class); launchSimpleIntentService.putExtra("data", "data from activity"); startService(launchSimpleIntentService);
透過IntentService的onHandleIntent的參數取出資料
@Override protected void onHandleIntent(Intent intent) { String data = intent.getStringExtra("data"); Log.d(TAG, "data:" + data); }
output:
D: data:data from activity
IntentService的生命週期
複寫IntentService的生命週期方法觀察呼叫順序
public class SimpleIntentService extends IntentService { private static final String TAG = SimpleIntentService.class.getSimpleName(); public SimpleIntentService() { super("SimpleIntentService"); Log.d(TAG, "SimpleIntentService: "); } @Override public void onCreate() { super.onCreate(); Log.d(TAG, "onCreate: "); } @Override public void onDestroy() { super.onDestroy(); Log.d(TAG, "onDestroy: "); } @Override public int onStartCommand(@Nullable Intent intent, int flags, int startId) { Log.d(TAG, "onStartCommand: "); return super.onStartCommand(intent, flags, startId); } @Override protected void onHandleIntent(Intent intent) { Log.d(TAG, "onHandleIntent: "); String data = intent.getStringExtra("data"); Log.d(TAG, "data:" + data); } }
Client call
Intent launchSimpleIntentService = new Intent(this, SimpleIntentService.class); launchSimpleIntentService.putExtra("data", "data from activity"); startService(launchSimpleIntentService); Log.d(TAG, "startService");
Output
D/SimpleIntentServiceActivity: startService D/SimpleIntentService: SimpleIntentService: D/SimpleIntentService: onCreate: D/SimpleIntentService: onStartCommand: D/SimpleIntentService: onHandleIntent: D/SimpleIntentService: data:data from activity D/SimpleIntentService: onDestroy:
從Output觀察IntentService生命週期的順序為
建構式 -> onCreate -> onStartCommand -> onHandleIntent -> onDestroy
客戶端停止IntentService
透過呼叫stopService()方法來停止IntentService。
Intent stopSimpleIntentService = new Intent(this, SimpleIntentService.class); stopService(stopSimpleIntentService); Log.d(TAG, "stopService");
傳入的Intent必須指定要停止的IntentService。
呼叫StopService之後,IntentService便會呼叫onDestroy方法銷毀自己。
但一般的使用情境較多為IntentService完成onHandleIntent方法後自動呼叫onDestroy銷毀的情況
需要注意的是因為onHandleIntent方法內部是由新的執行緒來執行,因此即使是客戶端呼叫了stopService,但是onHandleIntent方法不會結束。
為了測試這點在onHandleIntent方法加入計時10秒的操作
@Override protected void onHandleIntent(Intent intent) { Log.d(TAG, "onHandleIntent: "); String data = intent.getStringExtra("data"); Log.d(TAG, "data:" + data); sleep(10); } private void sleep(int sleepTimeSeconds) { for (int i = 0; i < sleepTimeSeconds; ++i) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } Log.d(TAG, "sleep: "+i); } }
客戶端並在第3秒呼叫stopService
Output如下
D/SimpleIntentServiceActivity: startService D/SimpleIntentService: SimpleIntentService: D/SimpleIntentService: onCreate: D/SimpleIntentService: onStartCommand: D/SimpleIntentService: onHandleIntent: D/SimpleIntentService: data:data from activity D/SimpleIntentService: sleep: 0 D/SimpleIntentService: sleep: 1 D/SimpleIntentService: sleep: 2 D/SimpleIntentService: sleep: 3 D/SimpleIntentServiceActivity: stopService D/SimpleIntentService: onDestroy: D/SimpleIntentService: sleep: 4 D/SimpleIntentService: sleep: 5 D/SimpleIntentService: sleep: 6 D/SimpleIntentService: sleep: 7 D/SimpleIntentService: sleep: 8 D/SimpleIntentService: sleep: 9
可以看到即使IntentService已經銷毀了,但計時仍然繼續。
因此若要呼叫stopService也一併停止onHandleIntent的內容,可以建立成員變數來控制是否要停止計時,如下
private boolean mIsDestroy; @Override public void onDestroy() { mIsDestroy = true; super.onDestroy(); Log.d(TAG, "onDestroy: "); } private void sleep(int sleepTimeSeconds) { for (int i = 0; i < sleepTimeSeconds && !mIsDestroy; ++i) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } Log.d(TAG, "sleep: "+i); } }
IntentService的循序
IntentService在單一執行緒上執行任務,若客戶端呼叫多次startService方法,IntentService也會保持等待當前的任務完成後再執行下一個任務。
修改印出耗時資訊時也印出IntentService toString
private void sleep(int sleepTimeSeconds) { for (int i = 0; i < sleepTimeSeconds && !mIsDestroy; ++i) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } Log.d(TAG, "sleep: "+i+" name:"+toString()); } }
連續啟動3次IntentService,Outout如下
D/SimpleIntentService: SimpleIntentService: D/SimpleIntentService: onCreate: D/SimpleIntentService: onStartCommand: D/SimpleIntentService: onHandleIntent: D/SimpleIntentService: data:data from activity D/SimpleIntentService: onStartCommand: D/SimpleIntentService: onStartCommand: D/SimpleIntentService: sleep: 0 name:com.codefoxx.serviceexample.simpleintentservice.SimpleIntentService@369cf9c D/SimpleIntentService: sleep: 1 name:com.codefoxx.serviceexample.simpleintentservice.SimpleIntentService@369cf9c D/SimpleIntentService: sleep: 2 name:com.codefoxx.serviceexample.simpleintentservice.SimpleIntentService@369cf9c D/SimpleIntentService: sleep: 3 name:com.codefoxx.serviceexample.simpleintentservice.SimpleIntentService@369cf9c D/SimpleIntentService: sleep: 4 name:com.codefoxx.serviceexample.simpleintentservice.SimpleIntentService@369cf9c D/SimpleIntentService: sleep: 5 name:com.codefoxx.serviceexample.simpleintentservice.SimpleIntentService@369cf9c D/SimpleIntentService: sleep: 6 name:com.codefoxx.serviceexample.simpleintentservice.SimpleIntentService@369cf9c D/SimpleIntentService: sleep: 7 name:com.codefoxx.serviceexample.simpleintentservice.SimpleIntentService@369cf9c D/SimpleIntentService: sleep: 8 name:com.codefoxx.serviceexample.simpleintentservice.SimpleIntentService@369cf9c D/SimpleIntentService: sleep: 9 name:com.codefoxx.serviceexample.simpleintentservice.SimpleIntentService@369cf9c D/SimpleIntentService: onHandleIntent: D/SimpleIntentService: data:data from activity D/SimpleIntentService: sleep: 0 name:com.codefoxx.serviceexample.simpleintentservice.SimpleIntentService@369cf9c D/SimpleIntentService: sleep: 1 name:com.codefoxx.serviceexample.simpleintentservice.SimpleIntentService@369cf9c D/SimpleIntentService: sleep: 2 name:com.codefoxx.serviceexample.simpleintentservice.SimpleIntentService@369cf9c D/SimpleIntentService: sleep: 3 name:com.codefoxx.serviceexample.simpleintentservice.SimpleIntentService@369cf9c D/SimpleIntentService: sleep: 4 name:com.codefoxx.serviceexample.simpleintentservice.SimpleIntentService@369cf9c D/SimpleIntentService: sleep: 5 name:com.codefoxx.serviceexample.simpleintentservice.SimpleIntentService@369cf9c D/SimpleIntentService: sleep: 6 name:com.codefoxx.serviceexample.simpleintentservice.SimpleIntentService@369cf9c D/SimpleIntentService: sleep: 7 name:com.codefoxx.serviceexample.simpleintentservice.SimpleIntentService@369cf9c D/SimpleIntentService: sleep: 8 name:com.codefoxx.serviceexample.simpleintentservice.SimpleIntentService@369cf9c D/SimpleIntentService: sleep: 9 name:com.codefoxx.serviceexample.simpleintentservice.SimpleIntentService@369cf9c D/SimpleIntentService: onHandleIntent: D/SimpleIntentService: data:data from activity D/SimpleIntentService: sleep: 0 name:com.codefoxx.serviceexample.simpleintentservice.SimpleIntentService@369cf9c D/SimpleIntentService: sleep: 1 name:com.codefoxx.serviceexample.simpleintentservice.SimpleIntentService@369cf9c D/SimpleIntentService: sleep: 2 name:com.codefoxx.serviceexample.simpleintentservice.SimpleIntentService@369cf9c D/SimpleIntentService: sleep: 3 name:com.codefoxx.serviceexample.simpleintentservice.SimpleIntentService@369cf9c D/SimpleIntentService: sleep: 4 name:com.codefoxx.serviceexample.simpleintentservice.SimpleIntentService@369cf9c D/SimpleIntentService: sleep: 5 name:com.codefoxx.serviceexample.simpleintentservice.SimpleIntentService@369cf9c D/SimpleIntentService: sleep: 6 name:com.codefoxx.serviceexample.simpleintentservice.SimpleIntentService@369cf9c D/SimpleIntentService: sleep: 7 name:com.codefoxx.serviceexample.simpleintentservice.SimpleIntentService@369cf9c D/SimpleIntentService: sleep: 8 name:com.codefoxx.serviceexample.simpleintentservice.SimpleIntentService@369cf9c D/SimpleIntentService: sleep: 9 name:com.codefoxx.serviceexample.simpleintentservice.SimpleIntentService@369cf9c D/SimpleIntentService: onDestroy:
可以看到每個任務都必須等到上一個任務完成後才執行。
不同IntentService的執行
觀察不同的IntentService執行的情況
新增另一個IntentService為AnotherSimpleIntentService如下
public class AnotherSimpleIntentService extends IntentService { private static final String TAG = AnotherSimpleIntentService.class.getSimpleName(); private boolean mIsDestroy; public AnotherSimpleIntentService() { super("AnotherSimpleIntentService"); Log.d(TAG, "AnotherSimpleIntentService: "); } @Override public void onCreate() { super.onCreate(); Log.d(TAG, "onCreate: "); } @Override public void onDestroy() { mIsDestroy = true; super.onDestroy(); Log.d(TAG, "onDestroy: "); } @Override public int onStartCommand(@Nullable Intent intent, int flags, int startId) { Log.d(TAG, "onStartCommand: "); return super.onStartCommand(intent, flags, startId); } @Override protected void onHandleIntent(Intent intent) { Log.d(TAG, "onHandleIntent: "); String data = intent.getStringExtra("data"); Log.d(TAG, "data:" + data); sleep(10); } private void sleep(int sleepTimeSeconds) { for (int i = 0; i < sleepTimeSeconds && !mIsDestroy; ++i) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } Log.d(TAG, "sleep: "+i+" name:"+toString()); } } }
AndroidManifest.xml宣告AnotherSimpleIntentService
<service android:exported="false" android:name=".simpleintentservice.AnotherSimpleIntentService"> </service>
在客戶端依序啟動SimpleIntentService和AnotherSimpleIntentService
public void onClick(View view) { int uiID = view.getId(); switch (uiID) { case R.id.start_intent_service: startSimpleIntentService(); startAnotherSimpleIntentService(); break; } } private void startAnotherSimpleIntentService() { Intent launchAnotherSimpleIntentService = new Intent(this, AnotherSimpleIntentService.class); launchAnotherSimpleIntentService.putExtra("data", "data from activity"); startService(launchAnotherSimpleIntentService); Log.d(TAG, "startService"); } private void startSimpleIntentService() { Intent launchSimpleIntentService = new Intent(this, SimpleIntentService.class); launchSimpleIntentService.putExtra("data", "data from activity"); startService(launchSimpleIntentService); Log.d(TAG, "startService"); }
Output如下
D/SimpleIntentServiceActivity: startService D/SimpleIntentServiceActivity: startService D/SimpleIntentService: SimpleIntentService: D/SimpleIntentService: onCreate: D/SimpleIntentService: onStartCommand: D/SimpleIntentService: onHandleIntent: D/SimpleIntentService: data:data from activity D/AnotherSimpleIntentService: AnotherSimpleIntentService: D/AnotherSimpleIntentService: onCreate: D/AnotherSimpleIntentService: onStartCommand: D/AnotherSimpleIntentService: onHandleIntent: D/AnotherSimpleIntentService: data:data from activity D/SimpleIntentService: sleep: 0 name:com.codefoxx.serviceexample.simpleintentservice.SimpleIntentService@ff71da5 D/AnotherSimpleIntentService: sleep: 0 name:com.codefoxx.serviceexample.simpleintentservice.AnotherSimpleIntentService@9de157a D/SimpleIntentService: sleep: 1 name:com.codefoxx.serviceexample.simpleintentservice.SimpleIntentService@ff71da5 D/AnotherSimpleIntentService: sleep: 1 name:com.codefoxx.serviceexample.simpleintentservice.AnotherSimpleIntentService@9de157a D/SimpleIntentService: sleep: 2 name:com.codefoxx.serviceexample.simpleintentservice.SimpleIntentService@ff71da5 D/AnotherSimpleIntentService: sleep: 2 name:com.codefoxx.serviceexample.simpleintentservice.AnotherSimpleIntentService@9de157a D/SimpleIntentService: sleep: 3 name:com.codefoxx.serviceexample.simpleintentservice.SimpleIntentService@ff71da5 D/AnotherSimpleIntentService: sleep: 3 name:com.codefoxx.serviceexample.simpleintentservice.AnotherSimpleIntentService@9de157a D/SimpleIntentService: sleep: 4 name:com.codefoxx.serviceexample.simpleintentservice.SimpleIntentService@ff71da5 D/AnotherSimpleIntentService: sleep: 4 name:com.codefoxx.serviceexample.simpleintentservice.AnotherSimpleIntentService@9de157a D/SimpleIntentService: sleep: 5 name:com.codefoxx.serviceexample.simpleintentservice.SimpleIntentService@ff71da5 D/AnotherSimpleIntentService: sleep: 5 name:com.codefoxx.serviceexample.simpleintentservice.AnotherSimpleIntentService@9de157a D/SimpleIntentService: sleep: 6 name:com.codefoxx.serviceexample.simpleintentservice.SimpleIntentService@ff71da5 D/AnotherSimpleIntentService: sleep: 6 name:com.codefoxx.serviceexample.simpleintentservice.AnotherSimpleIntentService@9de157a D/SimpleIntentService: sleep: 7 name:com.codefoxx.serviceexample.simpleintentservice.SimpleIntentService@ff71da5 D/AnotherSimpleIntentService: sleep: 7 name:com.codefoxx.serviceexample.simpleintentservice.AnotherSimpleIntentService@9de157a D/SimpleIntentService: sleep: 8 name:com.codefoxx.serviceexample.simpleintentservice.SimpleIntentService@ff71da5 D/AnotherSimpleIntentService: sleep: 8 name:com.codefoxx.serviceexample.simpleintentservice.AnotherSimpleIntentService@9de157a D/SimpleIntentService: sleep: 9 name:com.codefoxx.serviceexample.simpleintentservice.SimpleIntentService@ff71da5 D/SimpleIntentService: onDestroy: D/AnotherSimpleIntentService: sleep: 9 name:com.codefoxx.serviceexample.simpleintentservice.AnotherSimpleIntentService@9de157a D/AnotherSimpleIntentService: onDestroy:
可以看到不同的IntentService彼此不會互相影響,各自執行任務。
IntentService的優缺點
IntentService的優點在於容易使用,保持循序。
缺點在於不容易與客戶端進行互動(可以透過內部類別來解決),無法並行。