Service 是一個可以在后臺執(zhí)行長時間運行操作而不使用用戶界面的應(yīng)用組件筋栋。服務(wù)可由其他應(yīng)用組件啟動炊汤,而且即使用戶切換到其他應(yīng)用,服務(wù)仍將在后臺繼續(xù)運行弊攘。 此外抢腐,組件可以綁定到服務(wù)并與之進行交互,甚至是執(zhí)行進程間通信 (IPC)襟交。 例如迈倍,服務(wù)可以處理網(wǎng)絡(luò)事務(wù)、播放音樂捣域,執(zhí)行文件 I/O 或與內(nèi)容提供程序交互啼染,而所有這一切均可在后臺進行宴合。
服務(wù)在其托管進程的主線程中運行,它既不創(chuàng)建自己的線程迹鹅,也不在單獨的進程中運行(除非另行指定)。
應(yīng)使用服務(wù)還是線程?
服務(wù)是一種即使用戶未與應(yīng)用交互弟蚀,但它仍可以在后臺運行的組件蚤霞。 因此,應(yīng)僅在必要時才創(chuàng)建服務(wù)义钉。如果您確實要使用服務(wù)昧绣,則默認情況下,它仍會在應(yīng)用的主線程中運行捶闸,因此滞乙,如果服務(wù)執(zhí)行的是密集型或阻止性操作(例如 MP3 播放或聯(lián)網(wǎng)),則仍應(yīng)在服務(wù)內(nèi)創(chuàng)建新線程鉴嗤。
如需在主線程外部執(zhí)行工作,不過只是在用戶正在與應(yīng)用交互時才有此需要序调,則應(yīng)創(chuàng)建新線程而非服務(wù)醉锅。 例如,如果只是想在 Activity 運行的同時播放一些音樂发绢,則可在 onCreate() 中創(chuàng)建線程硬耍,在 onStart() 中啟動線程,然后在 onStop() 中停止線程边酒。還可以考慮使用 AsyncTask 或 HandlerThread经柴,而非傳統(tǒng)的 Thread 類。
Service的種類
- 按運行類型分:
類別 | 區(qū)別 | 應(yīng)用 |
---|---|---|
前臺服務(wù) | 會在通知欄顯示onGoing的 Notification | 當服務(wù)被終止的時候墩朦,通知一欄的 Notification 也會消失坯认,這樣對于用戶有一定的通知作用。常見的如音樂播放服務(wù)氓涣。 |
后臺服務(wù) | 默認的服務(wù)即為后臺服務(wù)牛哺,即不會在通知一欄顯示 onGoing的 Notification。 | 當服務(wù)被終止的時候劳吠,用戶是看不到效果的引润。某些不需要運行或終止提示的服務(wù),如天氣更新痒玩,日期同步淳附,郵件同步等议慰。 |
- 按使用方式分:
類別 | 區(qū)別 |
---|---|
startService啟動的服務(wù) | 主要用于啟動一個服務(wù)執(zhí)行后臺任務(wù),不進行通信奴曙。停止服務(wù)使用stopService别凹。 |
bindService啟動的服務(wù) | 方法啟動的服務(wù)要進行通信。停止服務(wù)使用unbindService缆毁。 |
同時使用startService番川、bindService 啟動的服務(wù) | 停止服務(wù)應(yīng)同時使用stopService與unbindService。 |
使用service
- 使用startService啟動服務(wù)
1.定義一個類繼承service
public class MyService extends Service {
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
//TODO do something useful
return Service.START_NOT_STICKY;
}
@Override
public IBinder onBind(Intent intent) {
//TODO for communication return IBinder implementation
return null;
}
}
onstartCommad方法返回一個int類型用來定義服務(wù)在被android系統(tǒng)終止之后的重啟方式脊框。最常用的三種常量返回值
2.在Manifest.xml文件中配置該Service
<service
android:name="MyService"
android:icon="@drawable/icon"
android:label="@string/service_name"
>
</service>
3.使用Context的startService(Intent)方法啟動該Service
Intent intent = new Intent(this, MyService.class);
startService(intent);
4.不再使用時颁督,調(diào)用stopService(Intent)方法停止該服務(wù)
.
使用這種方式創(chuàng)建啟動服務(wù)的生命周期如下圖:
注意:
1.如果服務(wù)已經(jīng)開啟,不會重復(fù)的執(zhí)行onCreate()浇雹,而是會調(diào)用onStartCommand()沉御。
2.服務(wù)停止的時候調(diào)用 onDestory()。服務(wù)只會被停止一次昭灵。
- 使用bindService方式啟動服務(wù)
如果您的服務(wù)僅供本地應(yīng)用使用吠裆,不需要跨進程工作,則可以實現(xiàn)自有 Binder 類烂完,讓您的客戶端通過該類直接訪問服務(wù)中的公共方法试疙。
注:此方法只有在客戶端和服務(wù)位于同一應(yīng)用和進程內(nèi)這一最常見的情況下方才有效。 例如抠蚣,對于需要將 Activity 綁定到在后臺播放音樂的自有服務(wù)的音樂應(yīng)用祝旷,此方法非常有效。
具體的創(chuàng)建服務(wù)的方法:
① 在服務(wù)中嘶窄,創(chuàng)建一個可滿足下列任一要求的 Binder 實例:
- 包含客戶端可調(diào)用的公共方法
- 返回當前 Service實例怀跛,其中包含客戶端可調(diào)用的公共方法
- 返回由服務(wù)承載的其他類的實例,其中包含客戶端可調(diào)用的公共方法
③ 在客戶端中吻谋,從 [onServiceConnected()](https://developer.android.com/reference/android/content/ServiceConnection.html#onServiceConnected(android.content.ComponentName, android.os.IBinder))回調(diào)方法接收 Binder,并使用提供的方法調(diào)用綁定服務(wù)现横。
例如漓拾,以下這個服務(wù)可讓客戶端通過 Binder 實現(xiàn)訪問服務(wù)中的方法:
public class LocalService extends Service {
// Binder given to clients
private final IBinder mBinder = new LocalBinder();
// Random number generator
private final Random mGenerator = new Random();
//Binder中包含返回該實例的方法
public class LocalBinder extends Binder {
LocalService getService() {
// Return this instance of LocalService
//so clients can call public methods
return LocalService.this;
}
}
// onBind()回調(diào)方法返回此 Binder實例。
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
/** method for clients */
public int getRandomNumber() {
return mGenerator.nextInt(100);
}
}
LocalBinder 為客戶端提供 getService() 方法戒祠,以檢索 LocalService 的當前實例晦攒。這樣,客戶端便可調(diào)用服務(wù)中的公共方法得哆。 例如脯颜,客戶端可調(diào)用服務(wù)中的 getRandomNumber()。
點擊按鈕時贩据,以下這個 Activity 會綁定到 LocalService 并調(diào)用 getRandomNumber():
public class BindingActivity extends Activity {
LocalService mService;
boolean mBound = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
@Override
protected void onStart() {
super.onStart();
// Bind to LocalService栋操,建議在onstart方法中進行綁定
Intent intent = new Intent(this, LocalService.class);
//利用bindService(Intent, ServiceConnection, int)方法啟動該Service
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onStop() {
super.onStop();
// Unbind from the service闸餐,建議在onstop方法中進行解綁
if (mBound) {
unbindService(mConnection);
mBound = false;
}
}
/** Called when a button is clicked (the button in the layout file attaches to
* this method with the android:onClick attribute) */
public void onButtonClick(View v) {
if (mBound) {
// Call a method from the LocalService.
// However, if this call were something that might hang,
//then this request should occur in a separate thread
//to avoid slowing down the activity performance.
int num = mService.getRandomNumber();
Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show();
}
}
/** Defines callbacks for service binding, passed to bindService() */
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName className,
IBinder service) {
// We've bound to LocalService, cast the IBinder
//and get LocalService instance
LocalBinder binder = (LocalBinder) service;
mService = binder.getService();
mBound = true;
}
@Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
};
}
特點:bind的方式開啟服務(wù),綁定服務(wù)矾芙,調(diào)用者掛了舍沙,服務(wù)也會跟著掛掉。綁定者可以調(diào)用服務(wù)里面的方法剔宪。
使用這種方式創(chuàng)建啟動服務(wù)的生命周期如下圖:
Service 元素的常見屬性
屬性 | 描述 |
---|---|
android:name | 服務(wù)類名 |
android:label | 服務(wù)的名字拂铡,如果此項不設(shè)置,那么默認顯示的服務(wù)名則為類名 |
android:icon | 服務(wù)的圖標 |
android:permission | 申明此服務(wù)的權(quán)限葱绒,這意味著只有提供了該權(quán)限的應(yīng)用才能控制或連接此服務(wù) |
android:process | 表示該服務(wù)是否運行在另外一個進程感帅,如果設(shè)置了此項,那么將會在包名后面加上這段字符串表示另一進程的名字 |
android:enabled | 如果此項設(shè)置為 true地淀,那么 Service 將會默認被系統(tǒng)啟動失球,不設(shè)置默認此項為 false |
android:exported | 表示該服務(wù)是否能夠被其他應(yīng)用程序所控制或連接,不設(shè)置默認此項為 false |
IntentService
IntentService是繼承于Service并處理異步請求的一個類帮毁,在IntentService內(nèi)有一個工作線程來處理耗時操作实苞,啟動IntentService的方式和啟動傳統(tǒng)Service一樣,同時烈疚,當任務(wù)執(zhí)行完后黔牵,IntentService會自動停止,而不需要我們?nèi)ナ謩涌刂啤?br>
另外爷肝,可以啟動IntentService多次荧止,而每一個耗時操作會以工作隊列的方式在IntentService的onHandleIntent回調(diào)方法中執(zhí)行,并且阶剑,每次只會執(zhí)行一個工作線程,執(zhí)行完第一個再執(zhí)行第二個危号,以此類推牧愁。
那么,用IntentService有什么好處呢外莲?首先猪半,我們省去了在Service中手動開線程的麻煩,第二偷线,當操作完成時磨确,我們不用手動停止Service
下面來寫一個Demo來模擬耗時操作在IntentService中的運行過程
自定義intentService
public class MyIntentService extends IntentService {
public static final String REUSLT = "reuslt";
public MyIntentService() {
super("MyIntentService");
}
@Override
protected void onHandleIntent(Intent intent) {
String msg = intent.getStringExtra(MainActivity.COM_KEVINWANGY_TESTINTENTSERVICE_MSG);
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
msg = "get result \"" + msg + "_result\" at "
+ android.text.format.DateFormat.format("dd/MM/yy h:mm:ss aa", System.currentTimeMillis());
Log.i("onHandleIntent", msg);
Intent resultIntent = new Intent();
resultIntent.setAction(MainActivity.ResultReceiver.RESULT_ACTION);
resultIntent.putExtra(REUSLT, msg);
LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(this); //Service本身就是Context
localBroadcastManager.sendBroadcast(resultIntent);
}
}
定義MainActiviy , 其中包含一個BroadCastReceiver
public class MainActivity extends AppCompatActivity {
public static final String COM_KEVINWANGY_TESTINTENTSERVICE_MSG = "com.kevinwangy.testintentservice.msg";
private Button mButton;
private TextView mStart_text;
private TextView mFinish_text;
private EditText mEditText;
private String mStart_msg;
private ResultReceiver mResultReceiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final StringBuilder stringBuilder = new StringBuilder();
mStart_text = (TextView)findViewById(R.id.start_text);
mFinish_text = (TextView)findViewById(R.id.finish_text);
mEditText = (EditText)findViewById(R.id.input_edit);
mButton = (Button)findViewById(R.id.input_btn);
mButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mStart_msg = mEditText.getText().toString();
stringBuilder.append("send message \"" + mStart_msg + "\" at "
+ android.text.format.DateFormat.format("dd/MM/yy h:mm:ss aa", System.currentTimeMillis()) + "\n");
mStart_text.setText(stringBuilder.toString());
Intent intent = new Intent(MainActivity.this, MyIntentService.class);
intent.putExtra(COM_KEVINWANGY_TESTINTENTSERVICE_MSG, mStart_msg);
startService(intent);
}
});
}
@Override
protected void onStart() {
super.onStart();
}
@Override
protected void onStop() {
super.onStop();
}
public class ResultReceiver extends BroadcastReceiver {
}
}
ResultReceiver 的定義如下
public class ResultReceiver extends BroadcastReceiver {
public static final String RESULT_ACTION = "com.kevinwang.testintentservice.resultReceiver";
@Override
public void onReceive(Context context, Intent intent) {
if (intent != null && TextUtils.equals(intent.getAction(), RESULT_ACTION)) {
String result = intent.getStringExtra(MyIntentService.REUSLT);
Log.i("onReceive", result);
Log.i("onReceive", "context is " + context.toString());
mFinish_text.setText(result);
}
}
}
在onstart中注冊BroadCastReceiver
protected void onStart() {
super.onStart();
IntentFilter filter = new IntentFilter(ResultReceiver.RESULT_ACTION);
mResultReceiver = new ResultReceiver();
LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(this);
localBroadcastManager.registerReceiver(mResultReceiver, filter);
}
在onstop中解除注冊
protected void onStop() {
super.onStop();
LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(this);
localBroadcastManager.unregisterReceiver(mResultReceiver);
}
在androidManifest中聲明
<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"/>
關(guān)于service、intentService声邦、thread和AsyncTask的對比
參考文檔及博客服務(wù)乏奥,綁定服務(wù),Service那點事兒