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的優點在於容易使用,保持循序。
缺點在於不容易與客戶端進行互動(可以透過內部類別來解決),無法並行。