zoukankan      html  css  js  c++  java
  • IntentService使用以及源码分析

    一 概述

    我们知道,在Android开发中,遇到耗时的任务操作时,都是放到子线程去做,或者放到Service中去做,在Service中开一个子线程来执行耗时操作。
    那么,在Service里面我们需要自己管理Service的生命周期,何时开启何时关闭,还是很麻烦的,还好Android给我们提供了一个这样的类,叫做IntentService

    那么IntentService是做什么用的呢?
    IntentService: 是继承于Service的一个类,用来处理异步请求。可以直接通过startService(Intent intent)来提交请求,Service的创建,关闭,开子线程等工作,IntentService内部都帮我们封装好了,我们只需要发请求处理请求就行了。
    如此简单

    我们先来看一下IntentService的用法

    二 IntentService用法

    假如我们现在有一个下载文件的需求,我们需要开启一个Service并在里面开启一个子线程中去下载文件。

    1 先继承IntentService实现一个类,我们叫做 DownloadService如下

    public class DownloadService extends IntentService {
    
         //重写无参的构造方法
        public DownloadService(){
            super("DownloadService");
        }
    
        @Override
        protected void onHandleIntent(Intent intent) {
            String url = intent.getStringExtra("url");
            downloadFile(url);
        }
    
        //下载文件
        private void downloadFile(String url){
            try {
                Log.e("DownloadService","当前线程名:" + Thread.currentThread().getName());
                Log.e("DownloadService","文件开始下载... url="+url);
          
                //模拟下载文件操作
                Thread.sleep(3000);
    
                Log.e("DownloadService","文件下载完成...");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    

    继承IntentService类,实现onHandleIntent(Intent intent)方法
    注意,不要忘了DownloadService需要在清单文件中注册

    2 我们在界面上的按钮的点击事件中,来下载一个文件,如下

      findViewById(R.id.tv_hello).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Log.e("DownloadService","当前线程名:"+Thread.currentThread().getName());
                
                    //像平时启动service方式一样,没有任何区别
                    Intent intent = new Intent(MainActivity.this,DownloadService.class);
                    intent.putExtra("url","http://xx/test.apk");
                    startService(intent);
                }
            });
    

    点击按钮,输出
    E/DownloadService: 当前线程名:main
    E/DownloadService: 当前线程名:IntentService[DownloadService]
    E/DownloadService: 文件开始下载... url=http://xx/test.apk
    E/DownloadService: 文件下载完成...

    通过输出日志,可以看到,开启任务是在主线程中,而执行下载文件的耗时任务,是在子线程中,使用的时候,只需要startService(Intent intent),并通过intent把所需要的数据带过去就行了。是不是很简单。

    下面来分析IntentService是如何做到的?

    三 IntentService源码分析

    1 看下IntentService的类定义

    public abstract class IntentService extends Service {
       private volatile Looper mServiceLooper;
       private volatile ServiceHandler mServiceHandler;
       private String mName;
       private boolean mRedelivery;
    
       private final class ServiceHandler extends Handler {
           public ServiceHandler(Looper looper) {
               super(looper);
           }
    
           @Override
           public void handleMessage(Message msg) {
               onHandleIntent((Intent)msg.obj);
               stopSelf(msg.arg1);
           }
       }
       
       
       ......
    }
    

    可以看到,IntentService有几个需要注意的地

    1. IntentService是一个Service也是一个抽象类,子类只需要实现void onHandleIntent(@Nullable Intent intent)并在里面添加自己的业务即可

    2. IntentService类中有一个 Looper mServiceLooper以及一个ServiceHandler mServiceHandler,

    3. ServiceHandler继承Handler,并在handleMessage()中调用了外部类的onHandleIntent方法

    4. ServiceHandlerhandleMessage()方法中,执行完onHandleIntent((Intent)msg.obj),调用了stopSelf(msg.arg1)来关闭这个Service

    所以IntentService不用去管怎么创建的,怎么关闭的,怎么开启线程的,我们只需要继承IntentService,实现onHandleIntent()方法并在里面执行我们的逻辑就行了,执行完任务之后,自动会把Service关闭。这一切都是IntentService帮我们封装好了的。

    2 startService之后,会走Service的生命周期方法,onCreate()源码如下

       @Override
        public void onCreate() {
            super.onCreate();
            
            //还记得上一篇讲的HandlerThread源码分析吗
            //创建一个HandlerThread对象,并调用start()方法
            //使之成为一个looper线程
            HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
            thread.start();
                
            //拿到上面创建的looper线程对应的looper
            //并传给ServiceHandler
            mServiceLooper = thread.getLooper();
            mServiceHandler = new ServiceHandler(mServiceLooper);
        }
    

    很明显,在onCreate中创建了一个线程而且是一个looper线程,又创建了一个Handler对象,并把这个线程的looper传给了这个Handler,那么这个Handler发送的任务消息都会由这个ServiceHandler处理了

    再看看 onStart()方法和onStartCommand()方法,如下

    onStart()方法

        @Override
        public void onStart(@Nullable Intent intent, int startId) {
            Message msg = mServiceHandler.obtainMessage();
            msg.arg1 = startId;
            msg.obj = intent;
            mServiceHandler.sendMessage(msg);
        }
    

    onStartCommand()方法

      @Override
        public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
            onStart(intent, startId);
            return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
        }
    

    startService方法启动的时候,第一次会调用onCreate() -> onStart() -> onStartCommand()方法
    而且之后再次调用startService方法启动的时候,不会再调用onCreate()方法了,而是会调用onStandCommand()方法

    而在IntentService中,onStartCommand()方法中又会调用onStart()方法,所以,我们只需要分析onStart()方法即可

    onStart()方法源码

       @Override
        public void onStart(@Nullable Intent intent, int startId){
            //使用mServiceHandler获取一个消息
            Message msg = mServiceHandler.obtainMessage();
            msg.arg1 = startId;
            msg.obj = intent;
            
            //发送这个消息
            mServiceHandler.sendMessage(msg);
        }
    
    

    通过上面可知,我们调用startService方法启动service的时候,会调用onStart()方法,在这个方法里面,把intent和startId赋值给了 msg ,并发送消息。这时候会调用Handler的handleMessag()方法,ServiceHandler的源码如下:

    public abstract class IntentService extends Service {
        private volatile Looper mServiceLooper;
        private volatile ServiceHandler mServiceHandler;
        private String mName;
        private boolean mRedelivery;
    
        private final class ServiceHandler extends Handler {
            public ServiceHandler(Looper looper) {
                super(looper);
            }
    
            @Override
            public void handleMessage(Message msg) {
                onHandleIntent((Intent)msg.obj);
                stopSelf(msg.arg1);
            }
        }
     
        ......
    }
    

    可以看到ServiceHandler是IntentService的内部类,而且在handleMessage中会调用IntentService的 onHandleIntent()方法,并把 intent 参数也传过去。

    我们来看下 onHandleIntent()方法
    protected abstract void onHandleIntent(@Nullable Intent intent);
    是一个抽象方法,这时候就需要子类去实现这个方法并在里面做耗时的操作即可。

    经过上面的分析可知,IntentService使用也非常方便,原理就是利用HandlerThread开启了一个looper线程,并在onStart中把intent通过msg发送出去,并在handleMessage中又调用了onHandleIntent方法,子类实现即可

  • 相关阅读:
    Java API操作 上传文件
    在火狐中button标签与a标签冲突事件
    谷歌地图集成步骤
    遇到Error:Execution failed for task ':app:transformClassesWithDexForDebug'的解决方案
    05-IntentFilter的匹配规则
    如何将自己在github写的android library开源,让大家依赖使用
    AS中将module转成library的步骤
    https如何进行加密传输
    对货币数据进行转换——新浪面试
    Android下的缓存策略
  • 原文地址:https://www.cnblogs.com/start1225/p/10012322.html
Copyright © 2011-2022 走看看