轉載請標明出處:http://blog.csdn.net/wu_wxc/article/details/51377512
本文出自【吳孝城的CSDN博客】
關於Service的生命週期,可以看:Services的生命週期
IntentService
如果程序不需要同時處理多個請求,IntentService將是最好的選擇。
可以啓動IntentService多次,每一次耗時操作都會以隊列的形式在IntentService的onHandleIntent回調方法中執行,每次只執行一個工作線程,執行完再執行下一個。這種單線程形式保證了主線程(UI線程)不會被阻塞
處理完所有的啓動請求後,IntentService會自動停止服務,所以不需要調用stopSelf()來停止服務。
提供缺省的onBind()實現代碼,因爲不提供綁定,所以它返回null。
提供缺省的onStartCommand()實現代碼,它把intent送入工作隊列,稍後會再傳給你的onHandleIntent()實現代碼。
以上所有的步驟匯成一個結果,我們需要做的就是實現onHandleIntent()來完成客戶端提交的任務,還有就是爲服務提供一小段構造方法
以下是一個IntentService的實現例子:
public class MyIntentService extends IntentService {
//必須實現一個構造方法,且以工作線程名稱作爲參數
public MyIntentService() {
super("MyIntentService");
}
/**
* 從缺省的工作空間調用本方法,並用啓動服務的Intent作爲參數
* 本方法返回後,IntentService會適時終止這個服務
*/
@Override
protected void onHandleIntent(Intent intent) {
// 我們可以在這裏執行一些工作,如下載文件等
}
}
如果想重寫其他回調方法,要確保調用一下父類的實現代碼以便IntentService能正確處理工作線程的生命週期。
下面程序回調了Service生命週期的其他方法
MainActivity.java
package cn.wuxiaocheng.intentservice;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void onHandleIntent(View v) {
startService(new Intent(MainActivity.this, MyIntentService.class));
}
}
MyIntentService.java
package cn.wuxiaocheng.intentservice;
import android.app.IntentService;
import android.content.Intent;
import android.os.IBinder;
public class MyIntentService extends IntentService {
//必須實現一個構造方法,且以工作線程名稱作爲參數
public MyIntentService() {
super("MyIntentService");
}
/**
* 從缺省的工作空間調用本方法,並用啓動服務的Intent作爲參數
* 本方法返回後,IntentService會適時終止這個服務
*/
@Override
protected void onHandleIntent(Intent intent) {
//我們可以在這裏執行一些工作,如下載文件等
try {
//作爲演示,這裏我讓它休息3秒,然後輸出onHandleIntent
Thread.sleep(3000);
System.out.println("onHandleIntent");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public void onCreate() {
System.out.println("onCreate");
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
System.out.println("onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void setIntentRedelivery(boolean enabled) {
super.setIntentRedelivery(enabled);
System.out.println("setIntentRedelivery");
}
@Override
public IBinder onBind(Intent intent) {
//不支持綁定,所以返回null
return null;
}
@Override
public void onDestroy() {
System.out.println("onDestroy");
super.onDestroy();
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="cn.wuxiaocheng.intentservice.MainActivity">
<Button
android:onClick="onHandleIntent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="onHandleIntent" />
</RelativeLayout>
還有要在配置清單文件裏添加聲明
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="cn.wuxiaocheng.intentservice">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".MyIntentService"
android:exported="false"></service>
</application>
</manifest>
其中第19-21行就是
Service
下面說下繼承Service的使用
如果Service需要多線程運行,可以繼承Service來完成每個Intent處理。
對於每一個啓動請求,它都以一個工作線程來完成處理,並且每次只處理一個請求。因爲是自行處理每個onStartCommand()調用,所以可以爲每個請求創建一個新的線程,並立即運行它們,不需要等待前一個請求處理完畢。這就實現了多線程的操作。
來個小例子
MainActivity.java
package cn.wuxiaocheng.started;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
public class MainActivity extends AppCompatActivity {
private Intent intent;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
intent = new Intent(MainActivity.this, MyService.class);
}
public void startService(View v) {
startService(intent);
}
}
MyService.java
package cn.wuxiaocheng.started;
import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.Process;
public class MyService extends Service {
private Looper mServiceLooper;
private ServiceHandler mServiceHandler;
//程序從線程接收消息
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
// 通常我們在這裏執行一些操作,如下載文件
// 這裏我們讓它休息3秒
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
//恢復中斷狀態
Thread.currentThread().interrupt();
}
//通過startId來停止服務,這樣我們就不用在處理其他工作的過程中再來停止服務
stopSelf(msg.arg1);
}
}
@Override
public void onCreate() {
// 啓動運行服務的線程
// 注意要創建一個單獨的線程,因爲服務通常運行於進行的主線程中,我們不想阻塞主線程
// 還要賦予它後臺服務的保優先級,這樣處理密集的工作就不會干擾我們的UI
HandlerThread thread = new HandlerThread("ServiceStartArguments", Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
// 獲得HandlerThread的Looper的隊列並用於Handler
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
System.out.println("onCreate");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
System.out.println("service starting");
// 對於每一個請求,都發送一個消息來啓動處理。
// 同時傳入啓動ID,以便任務完成後我們知道該終止哪一個請求
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
mServiceHandler.sendMessage(msg);
// 如果我們被殺死,那從這裏返回後被重啓
return START_STICKY;
}
@Override
public void onDestroy() {
System.out.println("onDestroy");
}
@Override
public IBinder onBind(Intent intent) {
// 不提供綁定,所有返回null
return null;
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="cn.wuxiaocheng.started.MainActivity">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="startService"
android:text="startService" />
</LinearLayout>
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="cn.wuxiaocheng.started">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".MyService"
android:enabled="true"
android:exported="true"></service>
</application>
</manifest>
onStartCommand()的返回值必須是以下常量之一 START_NOT_STICKY 在onStartCommand()返回後,如果系統kill這個服務,系統不會自動重啓這個服務,直到startService(Intent intent)方法再次被調用。 START_STICKY 如果系統在onStartCommand()後殺死了這個服務,則將重啓並調用onStartCommand(),但不會再次傳入一個intent,而是用null的intent來調用onStartCommand(),如果還有啓動服務的intent未發送完,那麼這些剩下的intent會繼續發送。這適用於媒體播放器(或類似服務),它們不執行命令,但需要一直運行並隨時待命。 START_REDELIVER_INTENT 如果系統在onStartCommand()返回後殺死了服務,則將重建服務並用上一個已送過的intent調用onStartCommand()。任何未發送完的intent也都會依次送入。這適用於那些需要立即恢復工作的活躍服務,比如下載文件。
Started:非綁定服務
package cn.wuxiaocheng.started;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.support.annotation.Nullable;
public class MyService extends Service {
public MyService() {
}
@Override
public void onCreate() {
//線程開始被創建
System.out.println("onCreate");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
//啓動線程後執行的內容
System.out.println("onStartCommand");
// 服務被殺死看後的表現
return START_STICKY ;
}
@Override
public void onDestroy() {
//線程摧毀
System.out.println("onDestroy");
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
//不允許綁定,所有返回null
return null;
}
}
Bound:綁定服務
MyService.java
package cn.wuxiaocheng.bound;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
public class MyService extends Service {
IBinder mBinder; // 客戶端綁定接口
boolean mAllowRebind; // 聲明是否使用onRebind
public MyService() {
}
@Override
public void onCreate() {
//服務被創建
System.out.println("onCreate");
}
@Override
public IBinder onBind(Intent intent) {
// 客戶端調用bindService()綁定服務
return mBinder;
}
@Override
public boolean onUnbind(Intent intent) {
//所有擴客戶端都通過unbindService()解除綁定
return mAllowRebind;
}
@Override
public void onDestroy() {
//服務被摧毀
System.out.println("onDestroy");
}
}
android:exported
該屬性決定該服務是否能夠被其他應用程序組件調用或跟它交互。值爲true時,能夠被調用或交互,值爲false時,只有同一個應用程序的組件或帶有相同用戶ID的應用程序才能啓動或綁定該服務。
android:enabled
該屬性決定系統是否能實例化這個服務,值爲true時,則能夠被實例化,值爲false時,不能被實例化,默認值爲true