核心技术篇:2.“四大天王”之Service

前言

  记得有一次面试,面试题里有一题是:请说说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()方法接收并处理信息

生命周期

  

原文地址:https://www.cnblogs.com/dream550/p/3919577.html