A Service is an application component representing either an application's desire to perform a longer-running operation while not interacting with the user or to supply functionality for other applications to use. Each service class must have a corresponding <service> declaration in its package'sAndroidManifest.xml. Services can be started with Context.startService() and Context.bindService().
Note that services, like other application objects, run in the main thread of their hosting process. This means that, if your service is going to do any CPU intensive (such as MP3 playback) or blocking (such as networking) operations, it should spawn its own thread in which to do that work. More information on this can be found in Processes and Threads. The IntentService class is available as a standard implementation of Service that has its own thread where it schedules its work to be done.
從官方文檔上可以看出,Service服務(wù)是不與用戶交互肥卡,長時間在后臺運行的一個組件。但是所在線程是在主線程球涛,如果要處理耗時操作如播放音樂,處理網(wǎng)絡(luò)請求的話需要啟動一個子線程來處理苛秕。
一堕油、啟動與銷毀
-
啟動Service
啟動Service有兩種方法:
①startService()
Intent intent = new Intent(MainActivity.this,TestService.class);
startService(intent);
生命流程:onCreate() → onStartCommand() → onDestory()
注意: onCreate()方法只會執(zhí)行一次,多次調(diào)用StartService()方法只會在第一次調(diào)用onCreate()拇涤,而onStartCommand()會多次調(diào)用。
當(dāng)服務(wù)被啟動后誉结,Service與Activity就沒有了關(guān)系鹅士,Activity退出后Service還會執(zhí)行。
②bindService()
bindService(intent,mcon,BIND_AUTO_CREATE);
public MCon mcon = new MCon();
public class MCon implements ServiceConnection{
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
myBinder = (TestService.MyBinder)service;
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
}
onServiceConnected()
系統(tǒng)調(diào)用這個來傳送在service的onBind()中返回的IBinder.
OnServiceDisconnected()
Android系統(tǒng)在同service的連接意外丟失時調(diào)用這個.比如當(dāng)service崩潰了或被強殺了.
當(dāng)客戶端解除綁定時惩坑,這個方法不會被調(diào)用. 類ServiceConnection中的onServiceDisconnected()方法在正常情況下是不被調(diào)用的掉盅,
它的調(diào)用時機是當(dāng)Service服務(wù)被異外銷毀時也拜,例如內(nèi)存的資源不足時這個方法才被自動調(diào)用。
生命流程: onCreate() → onBind() → onUnbind() → onDestory()
多次調(diào)用bindService()并不會再次調(diào)用onCreate() 和onBind()趾痘。
當(dāng)服務(wù)被啟動后慢哈,Service與Activity就綁定在了一起,當(dāng)Activity退出之后Service也退出永票。
銷毀service
使用startService()啟動之后調(diào)用stopService()來銷毀服務(wù)卵贱。
使用bindService()綁定之后調(diào)用unbindService()來銷毀服務(wù)。
如果同時調(diào)用startService()與bindService()侣集,銷毀時需要同時調(diào)用stopService()與unbindService()來銷毀键俱。
1.如果先bindService,再startService:
在bind的Activity退出的時候,Service會執(zhí)行unBind方法而不執(zhí)行onDestory方法,因為有startService方法調(diào)用過,所以Activity與Service解除綁定后會有一個與調(diào)用者沒有關(guān)連的Service存在
2.如果先bindService,再startService,再調(diào)用Context.stopService
Service的onDestory方法不會立刻執(zhí)行,因為有一個與Service綁定的Activity,但是在Activity退出的時候,會執(zhí)行onDestory,如果要立刻執(zhí)行stopService,就得先解除綁定
要注意合理中斷Service中的線程,最好設(shè)置變量檢測中斷(先挖個坑)世分。onStartCommand返回值
START_STICKY:如果service進(jìn)程被kill掉编振,保留service的狀態(tài)為開始狀態(tài),但不保留遞送的intent對象罚攀。隨后系統(tǒng)會嘗試重新創(chuàng)建service党觅,由于服務(wù)狀態(tài)為開始狀態(tài)雌澄,所以創(chuàng)建服務(wù)后一定會調(diào)用onStartCommand(Intent,int,int)方法斋泄。如果在此期間沒有任何啟動命令被傳遞到service,那么參數(shù)Intent將為null镐牺。
START_NOT_STICKY:“非粘性的”炫掐。使用這個返回值時,如果在執(zhí)行完onStartCommand后睬涧,服務(wù)被異常kill掉募胃,系統(tǒng)不會自動重啟該服務(wù)
START_REDELIVER_INTENT:重傳Intent。使用這個返回值時畦浓,如果在執(zhí)行完onStartCommand后痹束,服務(wù)被異常kill掉,系統(tǒng)會自動重啟該服務(wù)讶请,并將Intent的值傳入祷嘶。
START_STICKY_COMPATIBILITY:START_STICKY的兼容版本,但不保證服務(wù)被kill后一定能重啟夺溢。**bindService參數(shù) **
BIND_AUTO_CREATE:一般為這個论巍,代表Service不存在時自動創(chuàng)建該Service。
二风响、Service與Activity通信
- 采用onBind與接口方式雙向通信
public interface BinderInterface {
int getI();
void setI(int a);
}
class MyBinder extends Binder implements BinderInterface{
@Override
public int getI() {
return i;
}
@Override
public void setI(int a) {
i = a;
mtThread.interrupt();
}
}
public MyBinder mBinder = new MyBinder();
public IBinder onBind(Intent intent) {
return mBinder;
}
利用obBind()將一個Binder對象傳遞給Activity嘉汰。
public TestService.MyBinder myBinder;
public MCon mcon = new MCon();
public class MCon implements ServiceConnection{
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
myBinder = (TestService.MyBinder)service;
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
}
轉(zhuǎn)化為MyBinder對象之后就可以使用MyBinder中的方法來相互通信了。
myBinder.setI(1000);
int i = myBinder.getI();
-
使用Intent通信
使用Intetnt在Activity啟動Service時状勤,將數(shù)據(jù)放入Intent之中鞋怀,之后在Service中的onStartCommand(Intent intent, int flags, int startId)
方法中獲取到Intetnt并提取出數(shù)據(jù)双泪。
Activity中:
Intent intent = new Intent(MainActivity.this,TestService.class)
intent.putExtra("name","li");
startService(intent);
Service中
public int onStartCommand(Intent intent, int flags, int startId) {
String name = (intent.getExtras()).getString("name");
return START_STICKY;
}
三、前臺服務(wù)
-
提升為前臺服務(wù)
什么是前臺服務(wù)
A foreground service(前臺服務(wù)) is a service that's considered to be(被用戶所認(rèn)可的) something the
user is actively aware of and thus not a candidate for(而不是一個候選的密似,可以在內(nèi)存不足時攒读,被系統(tǒng)殺死
的) the system to kill when low on memory. A foreground service must provide a notification for the status
bar(前臺服務(wù)必須提供一個顯示通知), which is placed under the "Ongoing" heading(它是不可以忽略的), >which means that the notification cannot be dismissed unless the service is either stopped or removed from >the foreground.(意思是通知信息不能被忽略,除非服務(wù)停止或主動移除辛友,否則將一直顯示)
前臺服務(wù)是那些被認(rèn)為用戶知道(用戶認(rèn)可所認(rèn)可)且在系統(tǒng)內(nèi)存不足的時候不允許系統(tǒng)殺死的服務(wù)薄扁。 前臺服務(wù)必須給狀態(tài)欄提供一個通知,它被放到正在運行(Ongoing)標(biāo)題之下——這就意味著通知只有在這個服務(wù)被終止或從前臺主動移除通知后才能被解除废累。
如果我們希望Service可以一直保持運行狀態(tài)且不會在內(nèi)存不足的情況下被回收時邓梅,可以選擇將需要保持運行的Service設(shè)置為前臺服務(wù)。
創(chuàng)建Notifition
private void bulidNotifition() {
notificationBuilder = new Notification.Builder(this);
Intent intent = new Intent(this,MainActivity.class);
notification = notificationBuilder.setContentIntent(PendingIntent.getActivity(this,0,intent,0))
.setLargeIcon(BitmapFactory.decodeResource(this.getResources(),R.mipmap.ic_launcher))
.setContentTitle("前臺Serviece")
.setContentText("內(nèi)容")
.setWhen(System.currentTimeMillis()).build();
}
在onStartCommand中啟動前臺服務(wù)
public int onStartCommand(Intent intent, int flags, int startId) {
bulidNotifition();
startForeground(100,notification); //100表示前臺服務(wù)的id 當(dāng)使用的通知ID一致時邑滨,只會更新當(dāng)前Notification
return START_STICKY;
}
停止前臺服務(wù)
stopForeground(true);
啟動服務(wù)之后日缨,就會看到提示框那里有個提示欄,說明我們的Service已經(jīng)成為前臺服務(wù)了掖看。
四匣距、IntentService
開啟一個線程來處理用戶的intent請求,采用隊列等待哎壳,一個時間只有一個intent請求被執(zhí)行毅待。
主要方法:onHandleIntent(Intent intent)
此方法在具有請求的工作線程上被調(diào)用。 每次只處理一個Intent归榕,但是處理發(fā)生在獨立于其他應(yīng)用程序邏輯運行的工作線程上尸红。 所以,如果這段代碼需要很長時間刹泄,它會阻止對同一IntentService的其他請求外里,但它不會阻止任何其他。 當(dāng)所有請求都被處理后特石,IntentService停止自己盅蝗,所以你不應(yīng)該調(diào)用stopSelf()。
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intentservice1 = new Intent(MainActivity.this,MyIntentService.class);
intentservice1.putExtra("action",1);
startService(intentservice1);
}
});
button2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intentservice2 = new Intent(MainActivity.this,MyIntentService.class);
intentservice2.putExtra("action",2);
startService(intentservice2);
}
}
);
protected void onHandleIntent(Intent intent) {
Log.d("intent",intent.getIntExtra("action",0)+"");
try {
Log.d("A1sleep","A1sleep");
Thread.sleep(2000);
Log.d("sleep down","sleep down");
} catch (InterruptedException e) {
e.printStackTrace();
}
}