Service 理解
Service是什么?
Service 作為android系統的四大組件之一,是一種可以在后臺長時間運行操作而沒有用戶界面的應用組件。
Service和Thread的區別
1、Thread是程序運行的最小單位即線程,可以執行異步長時間耗時的操作。
2、Service是android中的組件,是運行在主線程上的,是要依托android程序運行的,所以不能做耗時操作。
Service android是四大組件之一。Service 是一個抽象類,我們需要些一個自定義Service繼承于Service。
啟動方式
Service 的啟動方式有兩種,一種是startService(),一種是bindService().這兩種方式有有什么區別.
- startService(),啟動完之后該service就在后臺運行,其生命周期跟啟動它的Context沒有任何關系。也不能跟Context通訊。
- bindService()啟動之后生命周期跟啟動它的Context有關,比如Activity、fragment、service等。在Context中解綁之后,如果改Service沒有任何綁定后該Service也就結束。
生命周期
Service 的生命周期跟啟動方式有關。
stratService的生命周期: onCreate() -> onStartCommand() -> onDestroy()
bindService的生命周期: onCreate() -> onBind() -> onUnbind() -> onDestroy()
startService
用startService 方式啟動Service的時候重寫onStartCommand()的方法。每次用該方式啟動Service的時候都會調用改方法。
返回值是一個int類型的:
- START_STICKY: 當Service因內存不足而被系統kill后,一段時間后內存再次空閑時,系統將會嘗試重新創建此Service,一旦創建成功后將回調onStartCommand方法,但其中的Intent將是null,除非有掛起的Intent,如pendingintent,這個狀態下比較適用于不執行命令、但無限期運行并等待作業的媒體播放器或類似服務。
- START_NOT_STICKY:當Service因內存不足而被系統kill后,即使系統內存再次空閑時,系統也不會嘗試重新創建此Service。除非程序中再次調用startService啟動此Service,這是最安全的選項,可以避免在不必要時以及應用能夠輕松重啟所有未完成的作業時運行服務。
- START_REDELIVER_INTENT:當Service因內存不足而被系統kill后,則會重建服務,并通過傳遞給服務的最后一個 Intent 調用 onStartCommand(),任何掛起 Intent均依次傳遞。
- START_STICKY_COMPATIBILITY:START_STICKY的兼容版本,但不保證服務被kill后一定能重啟。
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
String test = intent.getStringExtra("test");
LogHelper.i("-------test-------" + test);
LogHelper.i("-------flags-------" + flags);
LogHelper.i("-------startId-------" + startId);
LogHelper.i("-------onStartCommand-------");
return super.onStartCommand(intent, flags, startId);
}
這里的參數是:
- intent: 啟動時,啟動組件傳遞過來的Intent,如Activity可利用Intent封裝所需要的參數并傳遞給Service。
- flags: 表示啟動請求時是否有額外數據,可選值有 0,START_FLAG_REDELIVERY,START_FLAG_RETRY,0代表沒有.START_FLAG_REDELIVERY: 這個值代表了onStartCommand方法的返回值為START_REDELIVER_INTENT,意味著當Service因內存不足而被系統kill后,則會重建服務,并通過傳遞給服務的最后一個 Intent 調用 onStartCommand()。START_FLAG_RETRY : 該flag代表當onStartCommand調用后一直沒有返回值時,會嘗試重新去調用onStartCommand()。
- startId:指明當前服務的唯一ID,與stopSelfResult (int startId)配合使用,stopSelfResult 可以更安全地根據ID停止服務。
startService的完整Service:
public class SimpleService extends Service {
/**
* 綁定服務時才會調用,必須要實現的方法
* @param intent
* @return
*/
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
/**
* Called by the system when the service is first created.
* 首次創建服務時,系統將調用此方法來執行一次性設置程序(在調用 onStartCommand() 或 onBind() 之前)。
* 如果服務已在運行,則不會調用此方法。該方法只被調用一次
*/
@Override
public void onCreate() {
super.onCreate();
LogHelper.i("-------onCreate-------");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
String test = intent.getStringExtra("test");
LogHelper.i("-------test-------" + test);
LogHelper.i("-------flags-------" + flags);
LogHelper.i("-------startId-------" + startId);
LogHelper.i("-------onStartCommand-------");
return super.onStartCommand(intent, flags, startId);
}
/**
* 服務銷毀時的回調
*/
@Override
public void onDestroy() {
LogHelper.i("-------onDestroy-------");
super.onDestroy();
}
}
調用也就是簡單的startService:
mStart.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(ServiceActivity.this,SimpleService.class);
intent.putExtra("test","數據傳輸");
startService(intent);
}
});
mEnd.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(ServiceActivity.this,SimpleService.class);
stopService(intent);
}
});
bindService
bindService 的方式啟動Service,其作用是該Service可以和啟動它的Context(Activity等)進行通訊。其是ServiceConnection()的接口方法和服務器交互,在綁定即onBind()的時候回調。在這個方法中獲取Service傳遞過來的IBinder對象,通過這個對象實現跟宿主交互。
BindService的Service:
public class BindService extends Service {
private LocalBinder mBinder = new LocalBinder();
private Thread mThread;
private int count;
@Nullable
@Override
public IBinder onBind(Intent intent) {
LogHelper.i("------onBind-----");
return mBinder;
}
@Override
public void onCreate() {
super.onCreate();
LogHelper.i("------onCreate-----");
mThread = new Thread(new Runnable() {
@Override
public void run() {
while (true){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
count++;
}
}
});
mThread.start();
}
@Override
public int onStartCommand(Intent intent,int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
LogHelper.i("------onDestroy-----");
}
@Override
public boolean onUnbind(Intent intent) {
LogHelper.i("------onUnbind-----");
return super.onUnbind(intent);
}
public int getCount(){
return count;
}
/**
* 創建Binder對象,為后面給綁定的Activity使用。
*/
public class LocalBinder extends Binder {
/**
* 提供一個方法,返回當前對象LocalService,這樣我們就可在客戶端端調用Service的公共方法了
* @return
*/
BindService getService(){
return BindService.this;
}
}
}
調用的方式:先創建ServiceConnection:
mConn = new ServiceConnection(){
/**
* 與服務器端交互的接口方法 綁定服務的時候被回調,在這個方法獲取綁定Service傳遞過來的IBinder對象,
* 通過這個IBinder對象,實現宿主和Service的交互。
*/
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
LogHelper.i("---綁定成功.---");
BindService.LocalBinder binder = (BindService.LocalBinder)service;
mBindService = binder.getService();
}
/**
* 當取消綁定的時候被回調。但正常情況下是不被調用的,它的調用時機是當Service服務被意外銷毀時,
* 例如內存的資源不足時這個方法才被自動調用。
*/
@Override
public void onServiceDisconnected(ComponentName name) {
LogHelper.i("---取消綁定.---");
mBindService = null;
}
};
//綁定啟動Service.
mStart.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(BindServiceActivity.this,BindService.class);
bindService(intent,mConn, Service.BIND_AUTO_CREATE);
}
});
//解綁Service
mEnd.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(mBindService != null){
mBindService = null;
unbindService(mConn);
}
}
});
//通過IBinder獲取Service對象,然后訪問Service的public方法。
mGet.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(mBindService != null){
int count = mBindService.getCount();
LogHelper.i("-------count--------" + count);
mText.setText("---" + count);
}else {
LogHelper.i("-------service 未綁定--------");
}
}
});
區別
調用方式不同;
startService
使用Service的步驟:
1.定義一個類繼承Service
2.在Manifest.xml
文件中配置該Service
3.使用Context的startService(Intent)
方法啟動該Service
4.不再使用時,調用stopService(Intent)
方法停止該服務
使用這種start方式啟動的Service的生命周期如下:
onCreate()
--->onStartCommand()
(onStart()
方法已過時) ---> onDestory()
說明:如果服務已經開啟,不會重復的執行onCreate()
, 而是會調用onStart()
和onStartCommand()
。
服務停止的時候調用 onDestory()
。服務只會被停止一次。
特點:一旦服務開啟跟調用者(開啟者)就沒有任何關系了。開啟者退出了,開啟者掛了,服務還在后臺長期的運行。開啟者不能調用服務里面的方法。
bindService
使用Service的步驟:
1.定義一個類繼承Service
2.在Manifest.xml
文件中配置該Service
3.使用Contex
t的bindService(Intent, ServiceConnection, int)
方法啟動該Service
4.不再使用時,調用unbindService(ServiceConnection)
方法停止該服務作者:
使用這種start方式啟動的Service的生命周期如下:
onCreate()
--->onBind()
--->onunbind()
--->onDestory()
注意:綁定服務不會調用onstart()
或者onstartcommand()
方法
特點:bind的方式開啟服務,綁定服務,調用者掛了,服務也會跟著掛掉。
綁定者可以調用服務里面的方法。