前言
记得有一次面试,面试题里有一题是:请说说android四大组件及其特性。当时就懵了,虽然之前看书时候都有浏览过四大组件的知识,但用得较多的就只有Activity、BroadcastReceiver,另外两个Content Provider 和Service没怎么在实际中接触过。木办法啊,一个人的软肋总是会被暴露出来的。所以这段时间都在恶补这些方面的知识。
服务---Service这东西可能对日常的用户来说会比较陌生,虽然我们也常按下Alt+Ctrl+Del来查看任务管理器,里面也有“服务”这项,但通常情况下,我们都只是看看而已,并没有真正操作。那么服务到底是个什么东西?作用是什么?我个人比较喜欢的一个定义是:能够在后台长时间运行操作并且不提供用户界面的应用程序组件。移动设备上常接触的有关服务的操作有:后台播放音乐、后台下载文件等。
简介
服务有以下两种状态:
1.Started:应用程序组件调用startService()方法启动服务,服务一旦启动,能在后台无限期运行。
2.Bound:应用程序组件调用bindService()方法绑定服务,被绑定的服务与该组件“同生共死”。
这两种状态的划分也不是绝对性的,已经启动了的服务也可以被绑定。另一方面,服务运行于管理它的进程的主进程,如果用户期望服务完成一些复杂工作,则需要在服务中创建新线程来完成操作,避免出现ANR异常。
Service中重要的方法有以下几个:
1.onStartCommand():当应用程序组件调用startService()方法时,系统调用该方法。
2.onBind():当应用程序组件调用bindService()方法时,系统调用该方法。
3.onCreate():当服务第一次创建时,系统调用该方法,如果服务已经在运行,该方法不被调用。
4.onDestroy():当服务调用stopSelf()或者组件调用stopService()或者服务从所有客户端解绑定,系统调用该方法。
启动服务(Started Service)
启动服务可以通过继承两个类来实现:
1.Service:这是所有服务的基类,需要创建新线程来执行服务的全部工作。
public class CurrentTimeService extends Service{ private MediaPlayer mediaPlayer; @Override public IBinder onBind(Intent arg0) { // TODO Auto-generated method stub return null; } @Override public int onStartCommand(Intent intent, int flags, int startId) { // TODO Auto-generated method stub Time time=new Time();//创建Time对象 time.setToNow();//设置时间为当前时间 String currentTime=time.format("%Y-%m-%d %H:%M:%S");//设置时间格式 Log.i("TimeIntentService", currentTime);//输出当前时间 return START_STICKY; }
其实,通过继承Service类创建服务,只需要在onStartCommand()方法中加入用户的操作便可,该方法必须返回一个整数,用来描述系统停止服务后如何继续服务。其中返回值为START_NOT_STICKY时代表系统停止服务后,不再重新创建服务;返回值为START_STICKY时表示系统停止服务后,重新创建服务并调用onStartCommand()方法;如果返回值为START_REDELIVER_INTENT:重新创建服务并使用发送给服务的最后Intent调用onStartCommand()方法。
继承Service类创建服务的一大好处是可以同时处理多个请求,即可以为每次请求创建一个新线程并且立即运行它们。(这点,我当下还是不能很好理解。)
2.IntentService:这是Service类的子类,使用一个工作线程处理全部启动请求,在不必同时处理多个请求时,这是最佳的选择。
public class TimeIntentService extends IntentService{ //实现IntentService仅需要两步操作: // 实现一个没有参数的构造方法 public TimeIntentService() { super("TimeIntentService"); // TODO Auto-generated constructor stub } // 实现onHandleIntent()方法,在该方法中实现用户的操作 @Override protected void onHandleIntent(Intent arg0) { // TODO Auto-generated method stub Time time=new Time();//创建Time对象 time.setToNow();//设置时间为当前时间 String currentTime=time.format("%Y-%m-%d %H:%M:%S");//设置时间格式 Log.i("TimeIntentService", currentTime);//输出当前时间 }
由上可见,通过继承IntentService类创建Service,仅需要实现一个无参构造方法和onHandleIntent(),在该方法中实现用户的操作。onStratCommand()方法会默认实现,它先将Intent发送到工作队列然后跳转到onHandleIntent()方法。
绑定服务(Bound Service)
客户端通过bindService()方法绑定到服务,多个客户端能同时连接到服务,但是仅当第一个客户端绑定到服务时调用onBind()方法获得IBinder对象。除此之外,开发人员还需要实现ServiceConnection接口的两个方法,进行连接监视。
同样,实现服务的绑定也有两种方法:
1.继承Binder类:如果服务进用户本地应用程序并且不必跨进程工作,则开发人员可以实现自己的Binder类来为客户端提供访问服务公共方法的方式。
public class LocalBinder extends Binder{ BindServiceByBinder getService(){ return BindServiceByBinder.this;//返回当前服务的实例 } } @Override public IBinder onBind(Intent arg0) { // TODO Auto-generated method stub Log.i("TEST", "return binder"); return binder;//返回IBinder对象 }
private ServiceConnection sc=new ServiceConnection(){ @Override public void onServiceConnected(ComponentName arg0, IBinder service) { // TODO Auto-generated method stub LocalBinder binder=(LocalBinder) service;//获得自定义的LocalBinder对象 binderService=binder.getService();//获得服务对象 Log.i("TEST", "service connecte"); bound=true; } @Override public void onServiceDisconnected(ComponentName arg0) { // TODO Auto-generated method stub bound=false; } };
由上可见,实现步骤可分为以下三步:
1.实现自己的Binder类 2.从onBind()方法中返回Binder类实例 3.在onServiceConnected()回调方法中接收Binder实例
2.继承Messenger类
如果开发人员需要服务与远程进程进行通信,则可以使用Messenger来为服务提供接口。
public class MessageService extends Service { public static final int CURRENT_TIME=0; public class InComingHandler extends Handler{ @Override public void handleMessage(Message msg){ if(msg.what==CURRENT_TIME){ Time time=new Time();//创建Time对象 time.setToNow();//设置时间为当前时间 String currentTime=time.format("%Y-%m-%d %H:%M:%S");//设置时间格式 Toast.makeText(MessageService.this, currentTime, Toast.LENGTH_SHORT).show(); } } } @Override public IBinder onBind(Intent intent) { // TODO Auto-generated method stub Messenger messenger=new Messenger(new InComingHandler()); return messenger.getBinder(); } }
private ServiceConnection connection=new ServiceConnection(){ @Override public void onServiceConnected(ComponentName arg0, IBinder service) { // TODO Auto-generated method stub messenger=new Messenger(service); boundMessage=true; } @Override public void onServiceDisconnected(ComponentName arg0) { // TODO Auto-generated method stub messenger=null; boundMessage=false; } };
messenger.send(message);
由此可见,通过继承Messenger类绑定服务的步骤为:
1.继承自己的Handler类
2.利用上一步创建的Handler类创建Messenger对象(该对象也是Handler的引用)
3.利用Messenger对象获取IBinder并返回到客户端
4.客户端利用IBinder实例化Messenger,并利用它来发送message对象到服务
5.服务通过handleMessage()方法接收并处理信息
生命周期