一、 Service簡介
Service是android 系統中的四大元件之一(Activity、Service、BroadcastReceiver、ContentProvider),它跟Activity的級别差不多,但不能自己運作隻能背景運作,并且可以和其他元件進行互動。service可以在很多場合的應用中使用,比如播放多媒體的時候使用者啟動了其他Activity這個時候程式要在背景繼續播放,比如檢測SD卡上檔案的變化,再或者在背景記錄你地理資訊位置的改變等等,總之服務總是藏在背景的。
Service的啟動有兩種方式:context.startService() 和 context.bindService()
二、 Service啟動流程
context.startService() 啟動流程:
context.startService() -> onCreate() -> onStart() -> Service running -> context.stopService() -> onDestroy() -> Service stop
如果Service還沒有運作,則android先調用onCreate(),然後調用onStart();
如果Service已經運作,則隻調用onStart(),是以一個Service的onStart方法可能會重複調用多次。
如果stopService的時候會直接onDestroy,如果是調用者自己直接退出而沒有調用stopService的話,Service會一直在背景運作,該Service的調用者再啟動起來後可以通過stopService關閉Service。
是以調用startService的生命周期為: onCreate --> onStart (可多次調用) --> onDestroy
context.bindService()啟動流程:
context.bindService() -> onCreate() -> onBind() -> Service running -> onUnbind() -> onDestroy() -> Service stop
onBind()将傳回給用戶端一個IBind接口執行個體,IBind允許用戶端回調服務的方法,比如得到Service的執行個體、運作狀态或其他操作。這個時候把調用者(Context,例如Activity)會和Service綁定在一起,Context退出了,Srevice就會調用onUnbind->onDestroy相應退出。
是以調用bindService的生命周期為:onCreate --> onBind(隻一次,不可多次綁定) --> onUnbind --> onDestory。
在Service每一次的開啟關閉過程中,隻有onStart可被多次調用(通過多次startService調用),其他onCreate,onBind,onUnbind,onDestory在一個生命周期中隻能被調用一次。
三、 Service生命周期
Service的生命周期并不像Activity那麼複雜,它隻繼承了onCreate()、onStart()、onDestroy()三個方法
當我們第一次啟動Service時,先後調用了onCreate()、onStart()這兩個方法;當停止Service時,則執行onDestroy()方法。
這裡需要注意的是,如果Service已經啟動了,當我們再次啟動Service時,不會在執行onCreate()方法,而是直接執行onStart()方法。
它可以通過Service.stopSelf()方法或者Service.stopSelfResult()方法來停止自己,隻要調用一次stopService()方法便可以停止服務,無論調用了多少次的啟動服務方法。
四、 Service示例
下面我做了一個簡單的音樂播放的應用,分别使用startService和bindService來啟動本地的服務。
Activity
public class PlayMusicService extends Activity implements OnClickListener {
private Button playBtn;
private Button stopBtn;
private Button pauseBtn;
private Button exitBtn;
private Button closeBtn;
private Intent intent;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.music_service);
playBtn = (Button) findViewById(R.id.play);
stopBtn = (Button) findViewById(R.id.stop);
pauseBtn = (Button) findViewById(R.id.pause);
exitBtn = (Button) findViewById(R.id.exit);
closeBtn = (Button) findViewById(R.id.close);
playBtn.setOnClickListener(this);
stopBtn.setOnClickListener(this);
pauseBtn.setOnClickListener(this);
exitBtn.setOnClickListener(this);
closeBtn.setOnClickListener(this);
}
@Override
public void onClick(View v) {
int op = -1;
intent = new Intent("com.homer.service.musicService");
switch (v.getId()) {
case R.id.play: // play music
op = 1;
break;
case R.id.stop: // stop music
op = 2;
break;
case R.id.pause: // pause music
op = 3;
break;
case R.id.close: // close activity
this.finish();
break;
case R.id.exit: // stopService
op = 4;
stopService(intent);
this.finish();
break;
}
Bundle bundle = new Bundle();
bundle.putInt("op", op);
intent.putExtras(bundle);
startService(intent); // startService
}
@Override
public void onDestroy(){
super.onDestroy();
if(intent != null){
stopService(intent);
}
}
}
Service
public class MusicService extends Service {
private static final String TAG = "MyService";
private MediaPlayer mediaPlayer;
@Override
public IBinder onBind(Intent arg0) {
return null;
}
@Override
public void onCreate() {
Log.v(TAG, "onCreate");
Toast.makeText(this, "show media player", Toast.LENGTH_SHORT).show();
if (mediaPlayer == null) {
mediaPlayer = MediaPlayer.create(this, R.raw.tmp);
mediaPlayer.setLooping(false);
}
}
@Override
public void onDestroy() {
Log.v(TAG, "onDestroy");
Toast.makeText(this, "stop media player", Toast.LENGTH_SHORT);
if (mediaPlayer != null) {
mediaPlayer.stop();
mediaPlayer.release();
}
}
@Override
public void onStart(Intent intent, int startId) {
Log.v(TAG, "onStart");
if (intent != null) {
Bundle bundle = intent.getExtras();
if (bundle != null) {
int op = bundle.getInt("op");
switch (op) {
case 1:
play();
break;
case 2:
stop();
break;
case 3:
pause();
break;
}
}
}
}
public void play() {
if (!mediaPlayer.isPlaying()) {
mediaPlayer.start();
}
}
public void pause() {
if (mediaPlayer != null && mediaPlayer.isPlaying()) {
mediaPlayer.pause();
}
}
public void stop() {
if (mediaPlayer != null) {
mediaPlayer.stop();
try {
mediaPlayer.prepare(); // 在調用stop後如果需要再次通過start進行播放,需要之前調用prepare函數
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
AndroidManifest.xml
注冊activity
<activity
android:name=".service.PlayMusicService"
android:label="@string/app_name" />
注冊service
<service
android:name=".service.MusicService"
android:enabled="true" >
<intent-filter>
<action android:name="com.homer.service.musicService" />
</intent-filter>
</service>
五、 代碼解析
1、Activity中,PlayMusicService中通過重寫OnClickListener 接口onClick()方法實作對播放音樂的控制,把音樂各種操作用數字通過Intent傳遞給service
然後通過構造一個Intent , intent = new Intent("com.homer.service.musicService");
其中,com.homer.service.musicService是 AndroidManifest.xml 對service的定義,即上面“注冊service”
2、Activity中,音樂播放的控制,利用Bundle綁定數字op後,通過 startService(intent); 服務後發送出去
Bundle bundle = new Bundle();
bundle.putInt("op", op);
intent.putExtras(bundle);
startService(intent);
3、 Service中,會處理Activity啟動的 startService(intent);服務,依次調用service的啟動過程:onCreate --> onStart(可多次調用) --> onDestroy
onCreate(), 建立mediaPlayer
onStart(), 通過擷取Bundle bundle = intent.getExtras();,提取int op = bundle.getInt("op");,然後執行響應的音樂播放操作
onDestroy(),停止并釋放mediaPlayer音樂資源,如果當執行context.stopService()時調用此方法
4、Activity中,onClick()函數中close與exit是執行含義是不同的:
close : 隻是執行了this.finish(); 關閉了本Activity窗體,service并沒有被關掉,音樂依然會繼續在背景播放