Service基礎使用(一) 之前的文章一直介紹Activity的使用,很多知識和用法單一的配合Activity使用,這次將總結Android四大組件之二—— . 本文將要介紹以下內容: 1. Service是什麼 2. 兩種Service啟動 3. Service 前臺服務與Notificatio ...
Service基礎使用(一)
之前的文章一直介紹Activity的使用,很多知識和用法單一的配合Activity使用,這次將總結Android四大組件之二——Service
.
本文將要介紹以下內容:
- Service是什麼
- 兩種Service啟動
- Service 前臺服務與Notification
由於篇幅可能過長,這篇就寫這個三個,下篇將介紹後臺服務,IntentService等知識。
Service是什麼
Service 是一個可以在後臺執行長時間運行操作而不使用用戶界面的應用組件。服務可由其他應用組件啟動,而且即使用戶切換到其他應用,服務仍將在後臺繼續運行。 此外,組件可以綁定到服務,以與之進行交互,甚至是執行進程間通信 (IPC)。 例如,服務可以處理網路事務、播放音樂,執行文件 I/O 或與內容提供程式交互,而所有這一切均可在後臺進行。
上面說了這麼多可以做的耗時操作,但不要真的認為Service預設會運行在子線程中,他也不運行在一個獨立的進程中,他同樣執行在UI線程中,因此,不要在Service中執行耗時操作,除非你在Service中創建了子線程來完成耗時操作。
Service不因程式切換到後臺或者用戶切換到另一個APP而停止,但如果應用程式被殺死,他當然就也消失了。
兩種Service的啟動
服務啟動分為兩種形式,一種是通過StartService()
啟動Service,另一種是通過BindService()
,至於先啟動在綁定這個我們最後再說。本文主要介紹的就是這兩種,這兩種有什麼區別呢?我們先看一張他們的生命周期圖片,然後在慢慢細說。
StartService()
當應用組件(如 Activity)通過調用 startService() 啟動服務時,服務即處於“啟動”狀態。一旦啟動,服務即可在後臺無限期運行,即使啟動服務的組件已被銷毀也不受影響。 已啟動的服務通常是執行單一操作,而且不會將結果返回給調用方。例如,它可能通過網路下載或上傳文件。 操作完成後,服務會自行停止運行。
通過上面的生命周期圖也可以看出來首次啟動會創建一個Service的實例,然後依次調用onCreate()和onStartCommand(),此時Service進入運行狀態,即使你多次調用StartService()啟動Service,也不會創建新的Service對象,而是直接復用前面創建的Service對象,調用它的startCommand()方法。下麵介紹一下startService各個回調方法,我們該做什麼
onCreate():首次創建服務,系統將調用此方法來執行一次性設置程式,如果服務已經運行,則不會調用此方法
onStartCommand():啟動服務的時候,系統將會調用此方法。如果實現了此方法,則在服務工作完成後,需要主動調用stopSelf()或者stopService()來停止服務。
onDestroy(),當服務不再使用且將被銷毀時,系統將會調用此方法,服務應該實現此方法來清理所有資源。這是服務接受的最後一個調用。
下麵我將通過一個實例展示這個service的實現,以及方法調用的順序。註意,通過AS新建一個Service則不需要配置mainfest文件,否則需要加入service聲明,大概如下麵這樣。且註意始終通過顯示Intent啟動或者綁定Service,不要為他設置intent-filter
<application ... >
<service android:name=".ExampleService" />
</application>
Service代碼如下:
public class TestService extends Service {
public TestService() {
}
@Override
public void onCreate() {
super.onCreate();
//處理一次性設置
Log.i("TestService","onCreate被調用");
}
//必須要有這個方法
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
@Override
public void onDestroy() {
Log.i("TestService","onDestroy被調用");
super.onDestroy();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
//處理Service邏輯
Log.i("TestService","onStartCommand被調用");
return super.onStartCommand(intent, flags, startId);
}
}
Activity中佈局文件放置了一個啟動按鈕,一個停止按鈕,在onCreate()方法,實現startService,代碼如下:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
stop = (Button)findViewById(R.id.stop);
start = (Button) findViewById(R.id.start);
final Intent intent = new Intent(this, TestService.class);
start.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startService(intent);
}
});
stop.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
stopService(intent);
}
});
}
調用的結果如下:
點擊啟動service按鈕後
I/TestService: onCreate被調用
I/TestService: onStartCommand被調用
點擊停止service按鈕後
I/TestService: onDestroy被調用
bindService()
當應用組件通過調用 bindService() 綁定到服務時,服務即處於“綁定”狀態。綁定服務提供了一個客戶端-伺服器介面,允許組件與服務進行交互、發送請求、獲取結果,甚至是利用進程間通信 (IPC) 跨進程執行這些操作。 僅當與另一個應用組件綁定時,綁定服務才會運行。 多個組件可以同時綁定到該服務,但全部取消綁定後,該服務即會被銷毀。
和startService()
一樣,首次使用bindService時綁定一個Service時,系統會實例化一個Service實例,並調用onCreate()和onBind()方法,此後如果再次使用bindService綁定Service,系統不會創建新的Service實例,也不會再調用onBInd()方法,只是會直接把IBinder對象傳遞給其他後來增加的客戶端。 如果我們解除與服務的綁定,只需調用unbindService(),此時onUnbind和onDestory方法將會被調用!這是一個客戶端的情況,假如是多個客戶端綁定同一個Service的話,情況如下 當一個客戶完成和service之間的互動後,它調用 unbindService() 方法來解除綁定。當所有的客戶端都和service解除綁定後,系統會銷毀service。(除非service也被startService()方法開啟)。但一旦調用者銷毀,Service也立即終止。下麵主要說一下onBInd
這個回調方法。
第一種啟動方式並沒有直接提供Service與Activity的交互方式。第二種啟動方式即用bindService提供了Service與Activity交互方式,可以很方便的利用Ibinder實現Service與Activity的通信。關鍵在onBind方法
onBind()方法返回值是一個IBinder 對象,這個方法必須實現,通過startService返回為null,表示不調用,bindService則返回一個擴展Binder類的對象。
步驟如下:
- 定義一個繼承Binder類的類,在類裡面編寫想要Activity調用的方法.
- 生成一個該類的對象,放到onBInd()方法中返回。
代碼例子如下:
public class TestService2 extends Service {
public TestService2() {
}
public Mybinder mybinder = new Mybinder();
public int getInfo() {
return 123;
}
public class Mybinder extends Binder {
public TestService2 getService() {
return TestService2.this;
}
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
Log.i("TS","onbind被調用");
return mybinder;
}
@Override
public void onDestroy() {
super.onDestroy();
Log.i("TS","onDestory被調用");
}
@Override
public void onRebind(Intent intent) {
super.onRebind(intent);
Log.i("TS","onRebind被調用");
}
}
這個例子Mybinder對象中getService方法,得到這個Service對象,從而調用Service中所有方法。
在Activity中的代碼,要實現ServiceConnection類中的onServiceDisconnected和onServiceConnected方法,並且通過bindService來綁定服務,unbindService來解綁服務。
主要代碼如下:
TestService2.Mybinder binder;
private ServiceConnection conn = new ServiceConnection() {
//Activity與Service斷開連接時回調該方法
@Override
public void onServiceDisconnected(ComponentName name) {
System.out.println("------Service DisConnected-------");
}
//Activity與Service連接成功時回調該方法
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//將Service強制轉換類型為Binder,這種用法在回調中很常見。
System.out.println("------Service Connected-------");
binder = (TestService2.Mybinder) service;
}
};
...
@Override
protected void onCreate(Bundle savedInstanceState) {
...
start.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
bindService(intent, conn, Service.BIND_AUTO_CREATE);
}
});
stop.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
unbindService(conn);
}
});
//通過binder對象就可以對我們綁定的Service進行各種操作
status.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this,binder.getService().getInfo() + "",Toast.LENGTH_SHORT).show();
}
});
}
至於調用順序,還是和流程圖一樣,就不一一詳說了。這裡已經說明瞭2種啟動Service的方式和區別。下麵將介紹一個很流行的Service應用,前臺服務。
Service 前臺服務與Notification
我們在用很多應用的時候,發現他們啟動的時候,會在通知欄生成一個和該App的通知,來繼續執行Service,比如墨跡天氣,很多音樂App.這種叫前臺服務,其實這種Service有一個很好的一點,就是不會因為Service自身的優先順序低,而被系統KILL,而前臺服務就不會。
前臺服務的寫法很容易,只需要在onCreate()中,建立一個通知,然後用startForeground()設置為前臺服務即可。
下麵直接放出代碼,結合代碼註釋看看就好了,關於通知更多的內容可以看看Notification詳解
這裡只列出Service的onCreate()部分代碼
@Override
public void onCreate() {
super.onCreate();
//設定一個PendingIntent,來表示點擊通知欄時跳轉到哪裡
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, MainActivity.class), 0);
Notification.Builder builder = new Notification.Builder(this);
//建立一個notificationManager來管理通知的出現
notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
//構造通知的樣式,包括圖片,標題,內容,時間。
builder.setSmallIcon(R.mipmap.ic_launcher).
setWhen(System.currentTimeMillis()).
setContentTitle("我是標題").
setContentText("我是內容").
setTicker("在啟動時彈出一個消息").//這個Android5.0以上可能會失效
setWhen(System.currentTimeMillis()).
setContentIntent(contentIntent);
//最後通過build建立好通知
Notification notification = builder.build();
//通過manager來顯示通知,這個1為notification的id
notificationManager.notify(1,notification);
//啟動為前臺服務,這個1為notification的id
startForeground(1,notification);
}
後續關於後臺服務和IntentService的介紹,敬請期待第二篇。