美文网首页
关于Service,IntentService的理解

关于Service,IntentService的理解

作者: wayDevelop | 来源:发表于2019-05-09 10:21 被阅读0次

    1. 生命周期 常用方法

    • 官方说明图
    image

    在Service的生命周期里,常用的有:

    4个手动调用的方法

    手动调用方法 作用
    startService() 启动服务
    stopService() 关闭服务
    bindService() 绑定服务
    unbindService() 解绑服务

    内部自动调用的方法 作用
    onCreat() 创建服务
    onStartCommand() 开始服务
    onDestroy() 销毁服务
    onBind() 绑定服务
    onUnbind() 解绑服务

    使用

    • startService
    public class MyService extends Service {
        /**
         * 创建参数
         */
    
        int count;
    
        @Override
        public void onCreate() {
            super.onCreate();
            Log.w("TAG", "---onCreate");
        }
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            /** 创建一个线程,每秒计数器加一,并在控制台进行Log输出 */
            //耗时操作  不用再单独的开启线程
            new Thread(new Runnable() {
                public void run() {
                    while (true) {
                        try {
                            Thread.sleep(1000);
                            count++;
                            Log.w("TAG", "Count is" + count);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
    
                    }
                }
            }).start();
            return super.onStartCommand(intent, flags, startId);
    
    
        }
    
        @Override
        public void onDestroy() {
            super.onDestroy();
            Log.w("TAG", "---onDestroy");
    
        }
    
        @Override
        public IBinder onBind(Intent intent) {
            return null;
        }
    }
    
    

    Intent intent = new Intent(MainActivity.this, MyService.class);
    startService(intent);
    在需要停止的時候調用stopService

    • bindService (一定要记着这个是要获得,链接的对象) 可用于和Activity之間的通訊,BindService可以在Activity里面获得Service的实例,绑定获取实例是异步的过程

    bindService启动流程

    context.bindService() ——> onCreate() ——> onBind() ——> Service running ——> onUnbind() ——> onDestroy() ——> Service stop

    onBind()将返回给 客户端一个IBind接口实例,IBind允许客户端回调服务的方法,比如得到Service的实例、运行状态或其他操作。这个时候把调用者 (Context,例如Activity)会和Service绑定在一起,Context退出了,Srevice就会调用 onUnbind->onDestroy相应退出。

    所以调用bindService的生命周期为:onCreate --> onBind(只一次,不可多次绑定) --> onUnbind --> onDestory。

    在Service每一次的开启关闭过程中,只有onStart可被多次调用(通过多次startService调用),其他onCreate,onBind,onUnbind,onDestory在一个生命周期中只能被调用一次。

    
    /** 通过bindService和unBindSerivce的方式启动和结束服务 */
    public class MyBindService extends Service {
        /**
         * 进度条的最大值
         */
        public static final int MAX_PROGRESS = 100;
        /**
         * 进度条的进度值
         */
        private int progress = 0;
    
        /**
         * 更新进度的回调接口
         */
        private OnProgressListener onProgressListener;
    
        public interface OnProgressListener {
            void onProgress(int progress);
        }
    
        /**
         * 注册回调接口的方法,供外部调用
         *
         * @param onProgressListener
         */
        public void setOnProgressListener(OnProgressListener onProgressListener) {
            this.onProgressListener = onProgressListener;
        }
    
        /**
         * 增加get()方法,供Activity调用
         *
         * @return 下载进度
         */
        public int getProgress() {
            return progress;
        }
    
        /**
         * 模拟下载任务,每秒钟更新一次
         */
        public void startDownLoad() {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    while (progress < MAX_PROGRESS) {
                        progress += 5;
                        //进度发生变化通知调用方,需要和切换到主线程
                        if (onProgressListener != null) {
                            Log.w("TAG", "---thread"+Thread.currentThread().getName());
                            onProgressListener.onProgress(progress);
                        }
    
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
    
                    }
                }
            }).start();
        }
    
    
        /**
         * 返回一个Binder对象
         */
        @Override
        public IBinder onBind(Intent intent) {
            Log.w("TAG", "---onBind");
            return new MsgBinder();
        }
    
        //此方法是为了可以在Acitity中获得服务的实例   
        public class MsgBinder extends Binder {
            /**
             * 获取当前Service的实例
             *
             * @return
             */
            public MyBindService getService() {
                return MyBindService.this;
            }
        }
    
        @Override
        public void onCreate() {
            super.onCreate();
            Log.w("TAG", "---onCreate");
        }
    
        @Override
        public void onDestroy() {
            super.onDestroy();
            /** 服务停止时 */
            Log.w("TAG", "---onDestroy");
    
        }
    
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            Log.w("TAG", "---onStartCommand");
            return super.onStartCommand(intent, flags, startId);
        }
    }
    

    在Activity使用

    /** 进入Activity开始服务 */
      Intent intent = new Intent(MainActivity.this, MyBindService.class);
               bindService(intent, conn, Context.BIND_AUTO_CREATE);
    
    
    ServiceConnection conn = new ServiceConnection() {
            @Override
            public void onServiceDisconnected(ComponentName name) {
    
            }
    
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                Log.w("TAG", "onServiceConnected---------");
                //返回一个MsgService对象
                msgService = ((MyBindService.MsgBinder) service).getService();
                // 绑定成功后获取到服務开始下载
    
                msgService.startDownLoad();
                //注册回调接口来接收下载进度的变化
                msgService.setOnProgressListener(new MyBindService.OnProgressListener() {
                    @Override
                    public void onProgress(int progress) {
                        Log.w("TAG", "progress---------" + progress);
                        Log.w("TAG", "---thread----" + Thread.currentThread().getName());
    
                    }
                });
    
            }
        };
    
        protected void onDestroy() {
            super.onDestroy();
            this.unbindService(conn);
            Log.v("MainStadyServics", "out");
        }
    
    
    IntentService
    
    public class MyIntentService extends IntentService {
        private static final String TAG = "TAG";
    
        public MyIntentService() {
            super("MyIntentService");
            Log.d(TAG, "MyIntentService: " + Thread.currentThread().getName());
    
        }
    
    
        @Override
        public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
            Log.d(TAG, "onStartCommand: ");
            return super.onStartCommand(intent, flags, startId);
        }
    
        @Override
        public void onStart(@Nullable Intent intent, int startId) {
    
            Log.d(TAG, "onStart: ");
            super.onStart(intent, startId);
        }
    
        @Override
        protected void onHandleIntent(@Nullable Intent intent) {
            //耗时操作  不用再单独的开启线程
            Log.d(TAG, "MyIntentService: " + Thread.currentThread().getName());
            String path = intent.getStringExtra("path");
            downloadTask(path);
    
        }
    
        private void downloadTask(String path) {
            Log.d(TAG, "downloadTask: ");
            try {
                Thread.sleep(3 * 1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
        }
    
        /**
         * 当某个请求需要处理时,这个方法会在工作者线程被调用
         * 一次仅仅会有一个请求被处理,但是处理过程会运行在工作者线程(独立于其他应用程序逻辑运行)。
         * 因此,如果某段代码需要执行很长时间,它会阻塞住其他提交到该IntentService的请求
         * ,但是不会阻塞住其他任何东西。当所有的请求被处理完成之后,IntentService会停止它自身,
         * 因此你不应该手动调用stopSelf()方法。
         */
    
        @Override
        public void onDestroy() {
            Log.d(TAG, "onDestroy: ");
            super.onDestroy();
        }
    
    }
    
    

    使用

      Intent intent = new Intent(MainActivity.this, MyIntentService.class);
                    intent.putExtra("path", "http://www:xxx.xxx");
                    startService(intent);
                    startService(intent);
                    startService(intent);
    
    //执行结果
    D/TAG: MyIntentService: main
    
    D/TAG: onStartCommand: 
    D/TAG: onStart: 
    D/TAG: MyIntentService: IntentService[MyIntentService
    D/TAG: downloadTask: 
    
    D/TAG: onStartCommand: 
    D/TAG: onStart: 
    D/TAG: onStartCommand: 
    D/TAG: onStart: 
    D/TAG: MyIntentService: IntentService[MyIntentService
    D/TAG: downloadTask: 
    D/TAG: MyIntentService: IntentService[MyIntentService
    D/TAG: downloadTask: 
    
    D/TAG: onDestroy: 
    

    若启动IntentService 多次,那么 每个耗时操作 则 以队列的方式 在 IntentService的 onHandleIntent回调方法中依次执行,所有任务执行完自动结束回调onDestroy

    IntentService的onHandleIntent方法是一个抽象方法,所以我们在创建IntentService时必须实现该方法,
    通过上面一系列的分析可知,onHandleIntent方法也是一个异步方法。这里要注意的是如果后台任务只有一个的 话,onHandleIntent执行完,服务就会销毁,但如果后台任务有多个的话,onHandleIntent执行完最后一个任务时,服务才销毁。最后我们要知道每次执行一个后台任务就必须启动一次IntentService,而IntentService内部则是通过消息的方式发送给HandlerThread的,然后由Handler中的Looper来处理消息,而Looper是按顺序从消息队列中取任务的,也就是说IntentService的后台任务时顺序执行的,当有多个后台任务同时存在时,这些后台任务会按外部调用的顺序排队执行,我们前面的使用案例也很好说明了这点。


    image.png

    接下来,我们将通过 源码分析 解决以下问题:

    • IntentService 如何单独开启1个新的工作线程
      主要分析内容 = IntentService源码中的 onCreate()方法
    @Override
    public void onCreate() {
        super.onCreate();
        
        // 1. 通过实例化andlerThread新建线程 & 启动;故 使用IntentService时,不需额外新建线程
        // HandlerThread继承自Thread,内部封装了 Looper
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();
      
        // 2. 获得工作线程的 Looper & 维护自己的工作队列
        mServiceLooper = thread.getLooper();
    
        // 3. 新建mServiceHandler & 绑定上述获得Looper
        // 新建的Handler 属于工作线程 ->>分析1
        mServiceHandler = new ServiceHandler(mServiceLooper); 
    }
    
    
       /** 
         * 分析1:ServiceHandler源码分析
         **/ 
         private final class ServiceHandler extends Handler {
    
             // 构造函数
             public ServiceHandler(Looper looper) {
             super(looper);
           }
    
            // IntentService的handleMessage()把接收的消息交给onHandleIntent()处理
            @Override
             public void handleMessage(Message msg) {
      
              // onHandleIntent 方法在工作线程中执行
              // onHandleIntent() = 抽象方法,使用时需重写 ->>分析2
              onHandleIntent((Intent)msg.obj);
              // 执行完调用 stopSelf() 结束服务
              stopSelf(msg.arg1);
    
        }
    }
    
       /** 
         * 分析2: onHandleIntent()源码分析
         * onHandleIntent() = 抽象方法,使用时需重写
         **/ 
          @WorkerThread
          protected abstract void onHandleIntent(Intent intent);
    
    • IntentService 如何通过onStartCommand() 将Intent 传递给服务 & 依次插入到工作队列中
    
    /** 
      * onStartCommand()源码分析
      * onHandleIntent() = 抽象方法,使用时需重写
      **/ 
      public int onStartCommand(Intent intent, int flags, int startId) {
    
        // 调用onStart()->>分析1
        onStart(intent, startId);
        return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
    }
    
    /** 
      * 分析1:onStart(intent, startId)
      **/ 
      public void onStart(Intent intent, int startId) {
    
        // 1. 获得ServiceHandler消息的引用
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
    
        // 2. 把 Intent参数 包装到 message 的 obj 发送消息中,
        //这里的Intent  = 启动服务时startService(Intent) 里传入的 Intent
        msg.obj = intent;
    
        // 3. 发送消息,即 添加到消息队列里
        mServiceHandler.sendMessage(msg);
    }
    
    

    总结
    从上面源码可看出:IntentService本质 = Handler + HandlerThread:
    1、 onCreate()方法,通过HandlerThread 单独开启1个工作线程:IntentService
    创建1个内部 Handler :ServiceHandler
    2,通过 onStartCommand() 传递服务intent 到ServiceHandler 、依次插入Intent到工作队列中 & 逐个发送给 onHandleIntent()

    若一个任务正在IntentService中执行,此时你再发送1个新的任务请求,这个新的任务会一直等待直到前面一个任务执行完毕后才开始执行、

    原因:

    • 由于onCreate()只会调用一次 = 只会创建1个工作线程;
    • 当多次调用 startService(Intent)时(即 onStartCommand()也会调用多次),其实不会创建新的工
    • 作线程,只是把消息加入消息队列中 & 等待执行。
      所以,多次启动 IntentService 会按顺序执行事件

    相关文章

      网友评论

          本文标题:关于Service,IntentService的理解

          本文链接:https://www.haomeiwen.com/subject/aupioqtx.html