Service概述
Service是一種可以在后臺(tái)執(zhí)行長(zhǎng)時(shí)間運(yùn)行操作而沒有用戶界面的應(yīng)用組件。
它可由其它應(yīng)用組件(如Activity)啟動(dòng),一旦被啟動(dòng)將在后臺(tái)一直運(yùn)行,即使啟動(dòng)服務(wù)的組件已銷毀也不受影響。非常適合用于執(zhí)行那些不需要和用戶交互而且還需要長(zhǎng)期運(yùn)行的任務(wù)。
組件可以綁定到服務(wù),從而進(jìn)行交互。
適用場(chǎng)景:播放音樂;處理網(wǎng)絡(luò)事務(wù);在后臺(tái)記錄位置信息等。
Service分類
-
按運(yùn)行地點(diǎn)可分為本地服務(wù)(LocalService)和遠(yuǎn)程服務(wù)(RemoteService)
本地服務(wù):依附在主進(jìn)程上而不是獨(dú)立進(jìn)程,所以不能進(jìn)行耗時(shí)操作,可以在service里面創(chuàng)建一個(gè)Thread來執(zhí)行耗時(shí)任務(wù)。主進(jìn)程被kill后,服務(wù)便終止。
遠(yuǎn)程服務(wù):即獨(dú)立服務(wù),對(duì)應(yīng)進(jìn)程名為所在包名加上指定的android:process字符串。因?yàn)槭仟?dú)立進(jìn)程,所以Activity所在進(jìn)程被kill時(shí),該服務(wù)不受其它進(jìn)程影響??蛇M(jìn)行跨進(jìn)程通信(IPC)。
-
按運(yùn)行類型可分為前臺(tái)服務(wù)(Foreground Service)和后臺(tái)服務(wù)
前臺(tái)服務(wù):會(huì)在通知欄顯示Ongoing的Notification。當(dāng)服務(wù)被終止時(shí),通知欄的Notification也會(huì)消失,這樣對(duì)于用戶有一定的通知作用。常見如音樂播放服務(wù)。
后臺(tái)服務(wù):默認(rèn)的服務(wù)即為后臺(tái)服務(wù),不會(huì)顯示在Notification。當(dāng)服務(wù)被終止時(shí),用戶是看不到效果的。某些不需要運(yùn)行或終止提示的服務(wù),如天氣更新,日期同步等。
-
按使用方式可分為:
使用startService:主要用于啟動(dòng)一個(gè)服務(wù)執(zhí)行后臺(tái)任務(wù),不進(jìn)行通信。對(duì)應(yīng)的停止服務(wù)為stopService。
使用bindService:該方式啟動(dòng)的服務(wù)可進(jìn)行通信,調(diào)用者掛掉后,服務(wù)也會(huì)跟著掛掉。對(duì)應(yīng)的停止服務(wù)為unbindService。
使用startService和bindService:停止服務(wù)stopService和unbindService也必須使用。
Service的生命周期

onCreate(): 首次創(chuàng)建服務(wù)時(shí)調(diào)用。如果服務(wù)已運(yùn)行,則不會(huì)調(diào)用。只會(huì)在第一次創(chuàng)建Service時(shí)調(diào)用,適合完成一些初始化工作。
onStartCommand(): 當(dāng)另一個(gè)組件通過調(diào)用startService()請(qǐng)求啟動(dòng)服務(wù)時(shí),系統(tǒng)將調(diào)用該方法。
onDestroy(): 當(dāng)服務(wù)不再使用且將被銷毀時(shí),系統(tǒng)調(diào)用該方法。
onBind(): 當(dāng)另一個(gè)組件通過調(diào)用bindService()與服務(wù)綁定時(shí),系統(tǒng)將調(diào)用該方法。該方法是抽象方法,所以onBind()方法必須重寫。
onUnbind(): 當(dāng)另一個(gè)組件通過調(diào)用unbindService()與服務(wù)解綁時(shí),系統(tǒng)將調(diào)用該方法。
onRebind(): 當(dāng)startService和bindService都啟用,之后調(diào)用unbindService解綁服務(wù)時(shí),另一個(gè)組件想要與該服務(wù)綁定,并且之前onUnbind()方法返回true,該方法將被調(diào)用。
生命周期調(diào)用:
啟動(dòng)-->停止Service:startService() > onCreate() > onStartCommand() > onStartCommand() (多次啟動(dòng))--> stopService() > onDestroy()
綁定-->解綁Service:bindService() > onCreate() > onBind() --> unbindService() > onUnbind() > onDestroy()
啟動(dòng)綁定-->解綁停止Service:startService() > onCreate() > onStartCommand() > bindService() > onBind() --> unbindService() > onUnbind() > stopService() > onDestroy()
解綁綁定Service:unbindService() > onUnbind(ture) > bindService() > onRebind()
代碼實(shí)現(xiàn)
MyService.java代碼如下:
public class MyService extends Service {
public static final String TAG = "Joy";
//通過binder實(shí)現(xiàn)調(diào)用者client與Service之間的通信
private MyBinder binder = new MyBinder();
@Override
public void onCreate() {
super.onCreate();
Log.d(TAG,"oncreate");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG,"onStartCommand startId = "+startId);
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG,"onDestroy");
}
@Override
public boolean onUnbind(Intent intent) {
Log.d(TAG,"onUnbind");
return super.onUnbind(intent);
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.d(TAG,"onBind");
return binder;
}
public class MyBinder extends Binder {
public MyService getService() {
return MyService.this;
}
}
//該方法提供給綁定者調(diào)用
public int getNumber() {
return new Random().nextInt();
}
}
- 使用startService啟動(dòng)service
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(this, MyService.class);
startService(intent);
startService(intent);
stopService(intent);
startService(intent);
}
}
log如下:
02-27 16:22:02.518 26058-26058/com.android.myapplication D/Joy: oncreate
02-27 16:22:02.518 26058-26058/com.android.myapplication D/Joy: onStartCommand startId = 1
02-27 16:22:02.518 26058-26058/com.android.myapplication D/Joy: onStartCommand startId = 2
02-27 16:22:02.518 26058-26058/com.android.myapplication D/Joy: onDestroy
02-27 16:22:02.518 26058-26058/com.android.myapplication D/Joy: oncreate
02-27 16:22:02.518 26058-26058/com.android.myapplication D/Joy: onStartCommand startId = 1
總結(jié):可以看出多次調(diào)用startService不會(huì)重復(fù)執(zhí)行onCreate回調(diào),但每次都會(huì)執(zhí)行onStartCommand回調(diào),且只需要調(diào)用一次stopService方法便可以停止服務(wù),無論之前被調(diào)用了幾次啟動(dòng)服務(wù)方法。
- 使用bindService啟動(dòng)service
public class MainActivity extends AppCompatActivity {
public static final String TAG = "Joy";
private Button bind;
private Button unbind;
private MyService myService = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bind = findViewById(R.id.bind);
unbind = findViewById(R.id.unbind);
bind.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
bindService(new Intent(MainActivity.this, MyService.class), conn, Context.BIND_AUTO_CREATE);
}
});
unbind.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
unbindService(conn);
}
});
}
private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
MyService.MyBinder myBinder = (MyService.MyBinder) service;
myService = myBinder.getService();
int num = myService.getNumber();
Log.d(TAG,"onServiceConnected");
Log.d(TAG,"num = "+num);
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.d(TAG,"onServiceDisconnected");
}
};
}
啟動(dòng)界面如下:

點(diǎn)擊BIND SERVICE按鈕log如下:
02-27 16:43:47.166 16555-16555/com.android.myapplication D/Joy: oncreate
02-27 16:43:47.166 16555-16555/com.android.myapplication D/Joy: onBind
02-27 16:43:47.176 16555-16555/com.android.myapplication D/Joy: onServiceConnected
02-27 16:43:47.176 16555-16555/com.android.myapplication D/Joy: num = 445451174
點(diǎn)擊UNBIND SERVICE按鈕或者按返回鍵log如下:
02-27 16:44:37.036 16555-16555/com.android.myapplication D/Joy: onUnbind
02-27 16:44:37.036 16555-16555/com.android.myapplication D/Joy: onDestroy
總結(jié):
- 綁定者可以調(diào)用服務(wù)里面的方法。
- 即使多次點(diǎn)擊BIND SERVER按鈕,也不會(huì)多次觸發(fā)onBind()方法。
- Service中需要?jiǎng)?chuàng)建一個(gè)實(shí)現(xiàn)IBinder的內(nèi)部類。在onBind()方法中需返回一個(gè)IBinder實(shí)例,不然onServiceConnected()方法不會(huì)調(diào)用。
- onServiceDisconnected() 在service正常關(guān)閉的情況下是不會(huì)被調(diào)用的,該方法只在Service被異常中止或者被殺死的時(shí)候調(diào)用。
-
Remote Service啟動(dòng)服務(wù)
因?yàn)檫h(yuǎn)程服務(wù)是在另一個(gè)進(jìn)程,它不受其它進(jìn)程影響,可以為其它應(yīng)用程序提供調(diào)用的接口--實(shí)際上就是進(jìn)程間通信(IPC)。Android提供了AIDL工具來幫助進(jìn)程間接口的建立。
前臺(tái)服務(wù)
前臺(tái)服務(wù)是那些被認(rèn)為用戶所認(rèn)可的且在系統(tǒng)內(nèi)存不足時(shí)不允許系統(tǒng)殺死的服務(wù)。前臺(tái)服務(wù)必須給狀態(tài)欄提供一個(gè)通知,它被放到正在運(yùn)行(Ongoing)標(biāo)題之下,表示只有在這個(gè)服務(wù)被終止或從前臺(tái)主動(dòng)移除通知后才能被解除。
使用原因:
在一般情況下,Service都是在后臺(tái)運(yùn)行,它們的系統(tǒng)優(yōu)先級(jí)相對(duì)較低。當(dāng)系統(tǒng)內(nèi)存不足時(shí),在后臺(tái)運(yùn)行的Service就有可能被回收。所以可以選擇將需要保持運(yùn)行的Service設(shè)置為前臺(tái)服務(wù)。代碼實(shí)現(xiàn) :
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG,"onStartCommand startId = "+startId);
Notification.Builder builder = new Notification.Builder(this.getApplicationContext());
Intent intent1 = new Intent(this,MainActivity.class);
builder.setContentIntent(PendingIntent.getActivity(this,0,intent1,0))
.setLargeIcon(BitmapFactory.decodeResource(this.getResources(),R.mipmap.ic_launcher))
.setContentTitle("title")
.setSmallIcon(R.mipmap.ic_launcher)
.setContentText("content")
.setWhen(System.currentTimeMillis());
Notification notification = builder.build();
notification.defaults = Notification.DEFAULT_SOUND;
startForeground(110,notification);
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
stopForeground(true);
Log.d(TAG,"onDestroy");
}
重寫onStartCommand()方法,使用startForeground(int, Notification)方法來啟動(dòng)service。需要在onDestroy()方法中通過stopForeground(true)方法來取消前臺(tái)運(yùn)行狀態(tài)。
IntentService
Service不能直接處理耗時(shí)的任務(wù),一般可以使用Service+Thread來實(shí)現(xiàn)。而IntentService可以處理異步任務(wù)請(qǐng)求。
- IntentService是Service的子類,內(nèi)部有一個(gè)工作線程來處理耗時(shí)操作。
- 當(dāng)任務(wù)執(zhí)行完成后,IntentService會(huì)自動(dòng)停止,不需要手動(dòng)結(jié)束。
- 如果多次啟動(dòng)IntentService,每個(gè)耗時(shí)操作會(huì)以工作隊(duì)列的方式在IntentService的onHandleIntent() 方法中執(zhí)行,依次執(zhí)行,使用串行的方式,執(zhí)行完自動(dòng)結(jié)束。無需處理多線程問題。
相關(guān)代碼:
MyIntentService.java代碼:
public class MyIntentService extends IntentService {
public MyIntentService() {
super("MyIntentService");
}
@Override
protected void onHandleIntent(@Nullable Intent intent) {
long endTime = System.currentTimeMillis() + 20 *1000;
Log.d("MyIntentService","onHandleIntent");
while (System.currentTimeMillis() < endTime) {
synchronized (this) {
try {
wait(endTime - System.currentTimeMillis());
} catch (Exception e) {
}
}
}
Log.d("MyIntentService","finished");
}
}
MainActivity.java利用startService啟動(dòng):
final Intent intent = new Intent(MainActivity.this, MyIntentService.class);
startService(intent);
log如下:
02-27 15:36:18.061 23525-24995/com.android.myapplication D/MyIntentService: onHandleIntent
0227-04 15:36:38.061 23525-24995/com.android.myapplication D/MyIntentService: finished
因MyIntentService繼承了IntentService,所以不需要實(shí)現(xiàn)onBind(), onStartCommand()方法,只需實(shí)現(xiàn)onHandleIntent()即可。
不建議通過bindService來啟動(dòng)IntentService,因?yàn)镮ntentService源碼中onBind()默認(rèn)返回null。
Service與Thread的區(qū)別
Thread:Thread 是程序執(zhí)行的最小單元,它是分配CPU的基本單位。Thread可以用來執(zhí)行一些異步的操作。
Service:Service是android的一種機(jī)制,當(dāng)它是Local Service,對(duì)應(yīng)的Service是運(yùn)行在主進(jìn)程的 main 線程上的。如果是Remote Service,對(duì)應(yīng)的Service是運(yùn)行在獨(dú)立進(jìn)程的 main 線程上。
Thread的運(yùn)行是獨(dú)立于Activity的,當(dāng)Activity被finish后,如果Thread沒有被主動(dòng)停止或run()方法沒有執(zhí)行完畢,Thread會(huì)一直執(zhí)行。因此當(dāng)Activity被finish后,Thread引用則不被持有,且沒有辦法在別的Activity對(duì)同一個(gè)Thread進(jìn)行控制。
假如有需求的話,可以創(chuàng)建并啟動(dòng)一個(gè)Service,在Service里面創(chuàng)建、運(yùn)行并控制該Thread,即可實(shí)現(xiàn)對(duì)Thread的控制。