IntentService

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方法銷毀自己。

需要注意的是因為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彼此不會互相影響,各自執行任務。

 

Orignal From: IntentService

Error: Default interface methods are only supported starting with Android N (--min-api 24)

這是在 Android Studio 中套用了 androidx.core 之後出現的問題,build project 出現以下錯誤:
Error: Default interface methods are only supported starting with Android N (--min-api 24): android.view.MenuItem androidx.core.internal.view.SupportMenuItem.setContentDescription(java.lang.CharSequence)

解決方法有 2 種:
1. 在 /app/build.gradle 修改 minSdkVersion 為 24
android {  
...
defaultConfig {
...
minSdkVersion 24
...
}
...
}

 

2.在 /app/build.gradle 加入以下內容
android {  
...
compileOptions {
sourceCompatibility = '1.8'
targetCompatibility = '1.8'
}
...
}

 

Orignal From: Error: Default interface methods are only supported starting with Android N (--min-api 24)

Twitter Delicious Facebook Digg Stumbleupon Favorites More

 
Design by Free WordPress Themes | Bloggerized by Lasantha - Premium Blogger Themes | Affiliate Network Reviews