在Android框架中,Service是比较难以理解的一部分,而网上的大多数资料最多就是讲述了如何去用Service,并没有对Service做一个深入的、系统的讲解。现在傻蛋将做一个系列文章,将对Service做一个由浅入深的梳理,帮助大家深入的掌握Android Service。
首先我们先来看看怎么使用Service,然后再谈Android Service的内部机制。
在Android中Service的启动方式有两种,今天先发第一种。
Service的启动方式一:
启动:Context.startService(new Intent(context,xxx.class));
停止:Context.stopService() ;
我画了一个Service启动的流程图,相信大家一看就懂。Activity通过 Intent启动Service,如果Service还没有运行,则android先调用onCreate()然后调用onStart();如果 Service已经运行,则只调用onStart(),所以一个Service的onStart方法可能会重复调用多次。 调用stopService就会触发Service的onDestroy()方法。
这一节里面傻蛋做了一个示例程序是一个音乐播放器,界面如下,功能很简单:播放、暂停、停止音乐、关闭Activity(这时Service仍然运行,继续播放音乐)、退出程序(停止音乐退出Activity)。
由于要控制Service的动作,傻蛋写了一个播放的通用类,这样在以后的课程中还能用上,代码如下:
/**
* MyMediaController.java
* com.androidtest.service.mediaplayer
*
* Function: TODO
*
* ver date author
* ──────────────────────────────────
* 2011-5-16 Leon
*
* Copyright (c) 2011, 最牛网 All Rights Reserved.
*/
package com.zuiniuwang;
import java.io.Serializable;
import android.media.MediaPlayer;
/**
* ClassName:MyMediaController
* Function: Mediaplayer 的一个控制类,控制播放器的播放 暂停 停止 等动作
* REASON
*
* @author Leon
* @version
* @since Ver 1.1
* @Date 2011-5-16
*/
public enum MyMediaController implements Serializable {
play {
@Override
public void execute() {
if (mediaPlayer != null && !mediaPlayer.isPlaying())
mediaPlayer.start();
// TODO Auto-generated method stub
}
},
pause {
@Override
public void execute() {
// TODO Auto-generated method stub
if (mediaPlayer != null && mediaPlayer.isPlaying()) {
mediaPlayer.pause();
}
}
},
stop {
@Override
public void execute() {
// TODO Auto-generated method stub
if (mediaPlayer != null) {
mediaPlayer.stop();
try {
// 在stop后如果要重新Start需要prepare一下
mediaPlayer.prepare();
// 从头播放
mediaPlayer.seekTo(0);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
};
public static MediaPlayer mediaPlayer;
public abstract void execute();
}
然后是控制播放的Activity:
/**
* MusicPlayer.java
* com.androidtest.activity
*
* Function: TODO
*
* ver date author
* ──────────────────────────────────
* 2011-5-15 Leon
*
* Copyright (c) 2011, 最牛网 All Rights Reserved.
*/
package com.androidtest.activity.musicplayer;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import com.androidtest.MyImageButton;
import com.androidtest.R;
import com.androidtest.service.mediaplayer.MyMediaController;
import com.androidtest.service.mediaplayer.NormalMusicService;
import com.androidtest.sharedpreferences.TestSharePreferences;
/**
* ClassName:MusicPlayer Function: TODO ADD FUNCTION Reason: TODO ADD REASON
*
* @author Leon
* @version
* @since Ver 1.1
* @Date 2011-5-15
*/
public class NormalMusicPlayerActivity extends Activity implements OnClickListener {
private static final String TAG = NormalMusicPlayerActivity.class.getSimpleName();
private Intent intent ;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
this.setContentView(R.layout.music_player_layout);
Button playButton = (Button) this.findViewById(R.id.play);
playButton.setOnClickListener(this);
Button pauseButton =(Button) this.findViewById(R.id.pause);
pauseButton.setOnClickListener(this);
Button stopButton =(Button)this.findViewById(R.id.stop);
stopButton.setOnClickListener(this);
Button closeActivityButton =(Button)this.findViewById(R.id.close);
closeActivityButton.setOnClickListener(this);
Button exitActivityButton =(Button)this.findViewById(R.id.exit);
exitActivityButton.setOnClickListener(this);
intent = new Intent("com.androidtest.service.mediaplayer.NormalMusicService");
TestSharePreferences testSharePreferences=(TestSharePreferences)this.getApplication();
Log.v(TAG , ""+testSharePreferences.getSharedInteger());
}
private void playAction(MyMediaController playType) {
Bundle bundle = new Bundle();
bundle.putSerializable(NormalMusicService.INTENT_KEY, playType);
intent.putExtras(bundle);
NormalMusicPlayerActivity.this.startService(intent);
}
@Override
public void onClick(View view) {
// TODO Auto-generated method stub
switch (view.getId()) {
case R.id.play:
Log.d(TAG, "play.......");
playAction(MyMediaController.play);
break;
case R.id.pause:
Log.d(TAG, "pause.......");
playAction(MyMediaController.pause);
break;
case R.id.stop:
Log.d(TAG, "stop.......");
playAction(MyMediaController.stop);
break;
case R.id.close:
Log.d(TAG, "close.......");
this.finish();
break;
case R.id.exit:
Log.d(TAG, "exit.......");
stopService(intent);
this.finish();
}
}
}
最后是Service类
/**
* MusicService.java
* com.androidtest.service
*
* Function: TODO
*
* ver date author
* ──────────────────────────────────
* 2011-5-15 Leon
*
* Copyright (c) 2011, 最牛网 All Rights Reserved.
*/
package com.zuiniuwang.service;
import java.io.Serializable;
import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.IBinder;
import android.util.Log;
import com.zuiniuwang.*;
/**
* ClassName:MusicService
* Function: TODO ADD FUNCTION
* Reason: TODO ADD REASON
*
* @author Leon
* @version
* @since Ver 1.1
* @Date 2011-5-15
*/
public class NormalMusicService extends Service{
private String TAG = NormalMusicService.class.getSimpleName();
private MediaPlayer myMediaPlayer ;
public static final String INTENT_KEY= "action" ;
@Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
@Override
public void onCreate() {
// TODO Auto-generated method stub
Log.v(TAG , TAG+ " onCreate()");
super.onCreate();
if(myMediaPlayer==null){
myMediaPlayer=MediaPlayer.create(this, R.raw.test) ;
myMediaPlayer.setLooping(false);
}
}
@Override
public void onStart(Intent intent, int startId) {
// TODO Auto-generated method stub
Log.v(TAG , TAG + " onStart()");
super.onStart(intent, startId);
if(intent!=null){
MyMediaController mediaControl =(MyMediaController)intent.getSerializableExtra(NormalMusicService.INTENT_KEY);
mediaControl.mediaPlayer=myMediaPlayer;
mediaControl.execute();
}
}
@Override
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
Log.v(TAG , " onDestroy");
if(myMediaPlayer!=null){
myMediaPlayer.stop();
myMediaPlayer.release();
}
}
}
附件为本实例的代码下载地址:http://down.51cto.com/data/326354
第二种是通过绑定的方式来启动Service。先看流程图。
绑定的方式和第一节的方式最大的不同就是在于,Activity可以和Service实现关联,当被关联的Activity结束后,相应的Service 也会停止,同时在绑定了的Activity中我们还可以回调我们在Service中定义的方法。在这里我们使用了 this.bindService(intent, myServiceConnection, Context.BIND_AUTO_CREATE); 来启动Service,当Service创建了同时绑定了Activity之后,会回调我们定义的ServiceConnection(),从而传回IBinder接口,我们就能够调用Service中的方法了。这时候Activity就和 Service实现了绑定,Activity退出了Service就相应的退出了。Service的申明如下,intent filter 是对接收Service的过滤。
<service android:enabled="true" android:name=".service.mediaplayer.BindMusicService">
<intent-filter>
http://down.51cto.com/data/326354<action android:name="com.androidtest.service.mediaplayer.BindMusicService" />
</intent-filter>
</service>
本节的源代码可以在此下载: http://down.51cto.com/data/326385
前两节中可以看到Activity和Service,context.startService对应着Service中的onStart()方法,context.onBindService对应的是Service中的onBind()方法。当我们继想绑定一个Service又想在 Activity停止时,Service不会停止,我们可以先StartService,然后再BindService()。这时候的流程图如下所示:
此时需要注意一个问题,当Activity退出的时候,Sercvice并不会停止,此时我们可以再进入Activity重新绑定,当这时候 Service就会调用onRebind()方法,但是调用onRebind()方法的前提是先前的onUnbind()方法执行成功,但是使用 super.onUnbind(intent)是执行不成功的,这时候我们要手动的使其返回true,再次绑定时Rebind()就会执行。否则,如果退出时不显示的指定onUnbind()为成功的话(为false),那么重新启动此Activity来绑定服务时,Service的onBind()方法和onReBind都不会执行,但是ServiceConnection方法确一定会回调了。这说明在Service中的onBind()方法不同于 onStart()方法不能被重复调用。
本节代码和上节代码大致相同,只不过是在bind之前先start service ,大家可以在DDMS中看onUnbind() onRebind()的调用情况。本节代码在此下载:http://down.51cto.com/data/326376
|