android基础知识05:四大组件之service 01

迷途d书童 发布于 2012/03/23 18:39
阅读 355
收藏 0

华为云11月刊推送:DIY微信问答机器人,高性能计算代码的20个技巧!>>>

        本文主要介绍service相关内容。包括两篇文章:

        android基础知识05:四大组件之service 01

        android基础知识05:四大组件之service 02:远程调用

       android基础知识05:四大组件之service 03:实现机制


        本文资料来源于网络,参考了最牛网 中关于android service的相关分析。

       实例程序地址:http://download.csdn.net/detail/xianming01/4131098

                                   http://download.csdn.net/detail/xianming01/4131146

1、什么是service

        Service,看名字就知道跟正常理解的“服务”差不多,后台运行,可交互这样的一个东西。它跟Activity的级别差不多,但是他不能自己运行,需要通过某一个Activity或者其他Context对象来调用, Context.startService() 和 Context.bindService()。
        两种启动Service的方式有所不同。这里要说明一下的是如果你在Service的onCreate或者onStart做一些很耗时间的事情,最好在Service里启动一个线程来完成,因为Service是跑在主线程中,会影响到你的UI操作或者阻塞主线程中的其他事情。
        什么时候需要Service呢?比如播放多媒体的时候用户启动了其他Activity这个时候程序要在后台继续播放,比如检测SD卡上文件的变化,再或者在后台记录你地理信息位置的改变等等,总之服务嘛,总是藏在后头的。

        Service是在一段不定的时间运行在后台,不和用户交互应用组件。每个Service必须在manifest中 通过<service>来声明。可以通过contect.startservice和contect.bindserverice来启动。
       Service和其他的应用组件一样,运行在进程的主线程中。这就是说如果service需要很多耗时或者阻塞的操作,需要在其子线程中实现。
       service的两种模式(startService()/bindService()不是完全分离的):
1)本地服务 Local Service 用于应用程序内部。
        它可以启动并运行,直至有人停止了它或它自己停止。在这种方式下,它以调用Context.startService()启动,而以调用Context.stopService()结束。它可以调用Service.stopSelf() 或 Service.stopSelfResult()来自己停止。不论调用了多少次startService()方法,你只需要调用一次stopService()来停止服务。
        用于实现应用程序自己的一些耗时任务,比如查询升级信息,并不占用应用程序比如Activity所属线程,而是单开线程后台执行,这样用户体验比较好。
2)远程服务 Remote Service 用于android系统内部的应用程序之间。
        它可以通过自己定义并暴露出来的接口进行程序操作。客户端建立一个到服务对象的连接,并通过那个连接来调用服务。连接以调用Context.bindService()方法建立,以调用 Context.unbindService()关闭。多个客户端可以绑定至同一个服务。如果服务此时还没有加载,bindService()会先加载它。
         可被其他应用程序复用,比如天气预报服务,其他应用程序不需要再写这样的服务,调用已有的即可。

2、本地服务

2.1 startservice方式

        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()方法。 图片点击放大~


我们先来介绍一下本地服务的例子。

2.1.1 界面


其中可以播放音乐、暂停、停止等。同时点击finish键可以关闭应用(但服务不关闭,音乐可以继续播放),点击exit推出 应用,同时关闭服务。

2.1.2 音乐播放

/**
 * 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();
}
2.1.3 service

 
/**
 * ClassName:MusicService
 * Function: TODO ADD FUNCTION
 * Reason:	 TODO ADD REASON
 *
 * @author   Leon
 * @version
 * @since    Ver 1.1
 * @Date	 2011-5-15
 */
public class MusicService extends Service{
 
	private  String  TAG = MusicService.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(MusicService.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();
		}
 
	}
 
}
2.1.4 界面

public class ServiceTestServerActivity extends Activity implements OnClickListener{
    /** Called when the activity is first created. */
	private static final String TAG = ServiceTestServerActivity.class.getSimpleName();
	
	private TextView m_TextView_text;
	private Button btnPlay;
	private Button btnPause;
	private Button btnStop;
	private Button btnFinish;
	private Button btnExit;
	
	Intent intent;
	
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        m_TextView_text= (TextView)findViewById(R.id.text);
        
        btnPlay= (Button)findViewById(R.id.play);
        btnPause= (Button)findViewById(R.id.pause);
        btnStop= (Button)findViewById(R.id.stop);
        btnFinish= (Button)findViewById(R.id.finish);
        btnExit= (Button)findViewById(R.id.exit);
        
        btnPlay.setOnClickListener(this);
        btnPause.setOnClickListener(this);
        btnStop.setOnClickListener(this);
        btnFinish.setOnClickListener(this);
        btnExit.setOnClickListener(this);
        
        intent=new Intent("xuxm.demo.service01.MusicService");
    }
    
    private void playAction(MyMediaController playType) {
    	 
		Bundle bundle = new Bundle();
		bundle.putSerializable(MusicService.INTENT_KEY, playType);
		intent.putExtras(bundle);
		ServiceTestServerActivity.this.startService(intent);
	}

	@Override
	public void onClick(View v) {
		// TODO Auto-generated method stub
		switch(v.getId())
		{
		case R.id.play:
			playAction(MyMediaController.play);
			m_TextView_text.setText(R.string.play);
			Log.d(TAG, "play.......");
			break;
		case R.id.pause:
			playAction(MyMediaController.pause);
			m_TextView_text.setText(R.string.pause);
			Log.d(TAG, "pause.......");
			break;
		case R.id.stop:
			playAction(MyMediaController.stop);
			m_TextView_text.setText(R.string.stop);
			Log.d(TAG, "stop.......");
			break;
		case R.id.finish:
			Log.d(TAG, "close.......");
			this.finish();
			break;
		case R.id.exit:
			Log.d(TAG, "exit.......");
			stopService(intent);
			this.finish();
			break;
		default:
		}
	}
}
        程序还是蛮简单的,所以不分析了。

        运行时可以发现第一次startService时,会调用onCreate和onStart,在没有stopService前,无论点击多少次startService,都只会调用onStart。而stopService时调用onDestroy。再次点击stopService,会发现不会进入service的生命周期的,即不会再调用onCreate,onStart和onDestroy。
        而onBind在startService/stopService中没有调用。

2.1 bind service方式
        第二种是通过绑定的方式来启动Service。先看流程图,点击放大。


        在这里我们使用了this.bindService(intent, myServiceConnection, Context.BIND_AUTO_CREATE);  来启动Service,当Service创建了同时绑定了之后,会回调我们定义的ServiceConnection(),从而传回IBinder接口,我们就能够调用Service中的方法了。这时候Activity就和Service实现了绑定,Activity退出了Service就相应的退出了。

<service android:name=".MusicService02" >
            <intent-filter >
                <action android:name="xuxm.demo.service02.MusicService" />
            </intent-filter>
            </service>
主要代码如下:

MusicService02

public class MusicService02 extends Service{
 
	private  String  TAG = MusicService02.class.getSimpleName();
	private  MediaPlayer myMediaPlayer ;
	public   static final  String INTENT_KEY= "action" ;
	@Override
	public IBinder onBind(Intent arg0) { 
		// TODO Auto-generated method stub
		Log.v(TAG, TAG+" onBind");
		return mbinder;
 
	}
	
	LocalBinder mbinder=new LocalBinder();
	
	public class LocalBinder extends Binder {
		MusicService02 getService() {
            return MusicService02.this;
        }
    }
	
 
	@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);
	}
 
	@Override
	public boolean onUnbind(Intent intent) {
 
		// TODO Auto-generated method stub
		Log.v(TAG , TAG +" onUnbind ,成功没有?" + super.onUnbind(intent));
		return true;
		//return false;
 
	}
	
	@Override
	public void onRebind(Intent intent) {
 
		// TODO Auto-generated method stub
		Log.v(TAG , TAG +" onRebind()----------------------------------->");
		super.onRebind(intent);
 
	}
	
	@Override
	public void onDestroy() {
 
		// TODO Auto-generated method stub
		super.onDestroy();
		Log.v(TAG , " onDestroy");
		if(myMediaPlayer!=null){
			myMediaPlayer.stop();
			myMediaPlayer.release();
		}
 
	}

	public MediaPlayer getMyMediaPlayer() {
		return myMediaPlayer;
	}

	public void setMyMediaPlayer(MediaPlayer myMediaPlayer) {
		this.myMediaPlayer = myMediaPlayer;
	}
 
}
ServiceTestServerActivity

public class ServiceTestServerActivity extends Activity implements OnClickListener{
    /** Called when the activity is first created. */
	private static final String TAG = ServiceTestServerActivity.class.getSimpleName();
	
	private TextView m_TextView_text;
	private Button btnPlay;
	private Button btnPause;
	private Button btnStop;
	private Button btnUnbind;
	private Button btnFinish;
	private Button btnExit;
	
	private MusicService02 bindMusicService;
	
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        m_TextView_text= (TextView)findViewById(R.id.text);
        
        btnPlay= (Button)findViewById(R.id.play);
        btnPause= (Button)findViewById(R.id.pause);
        btnStop= (Button)findViewById(R.id.stop);

        btnFinish= (Button)findViewById(R.id.finish);
        btnExit= (Button)findViewById(R.id.exit);
        
        btnPlay.setOnClickListener(this);
        btnPause.setOnClickListener(this);
        btnStop.setOnClickListener(this);

        btnFinish.setOnClickListener(this);
        btnExit.setOnClickListener(this);
        
        connection();
    }
    
    private void connection() {
		Log.v(TAG , TAG+"connection");
		Intent intent = new Intent("xuxm.demo.service02.MusicService");
		//this.startService(intent);
		this.bindService(intent, myServiceConnection, Context.BIND_AUTO_CREATE);
 
	}

	@Override
	public void onClick(View v) {
		// TODO Auto-generated method stub
		switch(v.getId())
		{
		case R.id.play:
			MyMediaController.play.execute();
			m_TextView_text.setText(R.string.play);
			Log.d(TAG, "play.......");
			break;
		case R.id.pause:
			MyMediaController.pause.execute();
			m_TextView_text.setText(R.string.pause);
			Log.d(TAG, "pause.......");
			break;
		case R.id.stop:
			MyMediaController.stop.execute();
			m_TextView_text.setText(R.string.stop);
			Log.d(TAG, "stop.......");
			break;
		case R.id.finish:
			Log.d(TAG, "close.......");
			this.finish();
			break;
		case R.id.exit:
			Log.d(TAG, "exit.......");
			this.finish();
			this.stopService(new Intent("xuxm.demo.service02.MusicService"));
			break;
		default:
		}
	}
	
	//调用bindService后 Service调用onBind()后 回调此函数
		private ServiceConnection myServiceConnection = new ServiceConnection() {
	 
			@Override
			public void onServiceConnected(ComponentName name, IBinder binder) {
// This is called when the connection with the service has been 
                        // established, giving us the service object we can use to 
                        // interact with the service.    Because we have bound to a explicit 
                        // service that we know is running in our own process, we can 
                        // cast its IBinder to a concrete class and directly access it. 
				Log.v(TAG , TAG+ "onServiceConnected");
				// TODO Auto-generated method stub
				bindMusicService = ((LocalBinder)binder).getService();
				//给Controller设置Service初始化的MediaPlayer
				MyMediaController.mediaPlayer=bindMusicService.getMyMediaPlayer();
	 
			}
	 
			@Override
			public void onServiceDisconnected(ComponentName name) {
	 // This is called when the connection with the service has been 
                        // unexpectedly disconnected -- that is, its process crashed. 
                        // Because it is running in our same process, we should never 
                        // see this happen. 
				// TODO Auto-generated method stub
				bindMusicService=null;
				Log.v(TAG, "..............onServiceDisconnected");
	 
			}
	 
		};
	    //当Activity finish时必须解绑 不然会出现溢出
	 
		@Override
		public void finish() {
			// TODO Auto-generated method stub
			super.finish();
		    this.unbindService(myServiceConnection);
	 
		}
}

        运行时,发现调用次序是这样的:
bindService:
1.MusicService02: onCreate
2.MusicService02: onBind
3.Activity: onServiceConnected
unbindService: 只是调用onDestroy
可见,onStart是不会被调用的,而onServiceDisconnected没有调用的原因在上面代码的注释有说明。

        此时,activity停止时,service也停止了。

2.2 bind service的一些问题

        前面的分析中可以看到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()方法不能被重复调用。


原文链接:http://blog.csdn.net/xianming01/article/details/7341877
加载中
返回顶部
顶部