• 核心技术篇: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()方法接收并处理信息

    生命周期

      

  • 相关阅读:
    排序算法七:选择排序之堆排序
    排序算法七:选择排序之堆排序
    排序算法六:选择排序之直接选择排序
    排序算法六:选择排序之直接选择排序
    贝叶斯网络
    web 开发之js---js 中的数组操作
    web 开发之js---JS变量也要注意初始化
    web 开发之js---理解并解决IE的内存泄漏方式
    web 开发之js---巧用iframe实现jsp无刷新上传文件
    web 开发之js---js获取select标签选中的值
  • 原文地址:https://www.cnblogs.com/dream550/p/3919577.html
Copyright © 2020-2023  润新知