IntentService 从使用到源码分析

来源:互联网 发布:mac系统电脑玩英雄联盟 编辑:程序博客网 时间:2024/06/07 13:54

1. 基本使用

1.1 什么是IntentService

IntentService是继承于Service并处理异步请求的一个类,在IntentService内有一个工作线程来处理耗时操作,启动IntentService的方式和启动传统Service一样,同时,当任务执行完后,IntentService会自动停止,而不需要我们去手动控制。另外,可以启动IntentService多次,而每一个耗时操作会以工作队列的方式在IntentService的onHandleIntent回调方法中执行,并且,每次只会执行一个工作线程,执行完第一个再执行第二个,以此类推。
所有请求都在一个单线程中,不会阻塞应用程序的主线程(UI Thread),同一时间只处理一个请求。

1.2 IntentService 的好处

  • 自动开启线程处理耗时任务.
  • 操作完成时自动销毁Service.

1.3 基本使用

  • 创建 IntentService 的子类.
/** * @author : Brian */public class MyIntentService extends IntentService {    private static final String TAG = "MyIntentService";    /**     * 默认构造     */    public MyIntentService(){        this("MyIntentService");    }    /**     * 父类构造方法     */    public MyIntentService(String name) {        super(name);    }    @Override    protected void onHandleIntent(@Nullable Intent intent) {        Log.d(TAG, "onHandleIntent: ");        String opType = intent.getExtras().getString("param");        // 分辨任务        Log.d(TAG, "任务 : " + opType);        // 延时 3s        SystemClock.sleep(3 * 1000);    }    /**     * Unless you provide binding for your service,     * you don't need to implement this method,     * because the default implementation returns null.     */    @Nullable    @Override    public IBinder onBind(Intent intent) {        Log.d(TAG, "onBind: ");        return super.onBind(intent);    }    /**     * Called by the system when the service is first created.     */    @Override    public void onCreate() {        Log.d(TAG, "onCreate: ");        super.onCreate();    }    /**     * Called by the system to notify a Service that     * it is no longer used and is being removed.     */    @Override    public void onDestroy() {        Log.d(TAG, "onDestroy: ");        super.onDestroy();    }    /**     * You should not override this method for your IntentService.     */    @Override    public int onStartCommand(@Nullable Intent intent, int flags, int startId) {        Log.d(TAG, "onStartCommand: ");        return super.onStartCommand(intent, flags, startId);    }    /**     * Sets intent redelivery preferences.     */    @Override    public void setIntentRedelivery(boolean enabled) {        Log.d(TAG, "setIntentRedelivery: ");        super.setIntentRedelivery(enabled);    }}
  • AndroidMenifest.xml 中注册Service
<!-- 注册Intent Service --><service android:name="com.brain.interview.intent_service.MyIntentService">    <intent-filter>        <action android:name="com.brain.intentservice"/>    </intent-filter></service>
  • 编写测试代码
/** * 启动 */public void startIntentService1() {    // 操作一    Intent intent = new Intent();    intent.setAction("com.brain.intentservice");    intent.setPackage(getPackageName());    Bundle bundle = new Bundle();    bundle.putString("param", "打球");    intent.putExtras(bundle);    startService(intent);    // 操作二    Intent intent2 = new Intent();    intent2.setAction("com.brain.intentservice");    intent2.setPackage(getPackageName());    Bundle bundle2 = new Bundle();    bundle2.putString("param", "吃饭");    intent2.putExtras(bundle2);    startService(intent2);}
  • 输出
onCreate: onStartCommand: onStartCommand: onHandleIntent: 任务 : 打球onHandleIntent: 任务 : 吃饭onDestroy: 

从输出可以看出, 在执行完所有的任务后, 销毁了Service.

2. 源码分析

IntentService 源码并不复杂其实, 就是封装了 Handler + ThreadHandler

2.1 HandlerThread

普通的Thread主要用于进行耗时操作.HandlerThread内部常见了消息队列,外界需要通过Handler的消息方式通知HandlerThread来执行一个任务.由于HandlerThread的run() 是一个无限循环(Looper.loop()),因此当明确不需要时需要主动调用,quit() 或者 quitSafely() 来终止线程的执行.

HandlerThread 的run方法的源码如下 :

@Overridepublic void run() {    mTid = Process.myTid();    // 创建和当前线程绑定的Looper对象    Looper.prepare();    // 保存当前线程的Looper的一个引用    synchronized (this) {        mLooper = Looper.myLooper();        notifyAll();    }    Process.setThreadPriority(mPriority);    // 使用者,可以重写这个方法进行消息循环开启前的设置.    onLooperPrepared();    // 开启消息循环    Looper.loop();    mTid = -1;}

HandlerThread的好处就是他带有Looper, 不用我们手动开启Looper, 有了Looper我们就可以绑定Handler了

2.2 IntentService

  • 首先在来看 onCreate() 方法
@Overridepublic void onCreate() {    // TODO: It would be nice to have an option to hold a partial wakelock    // during processing, and to have a static startService(Context, Intent)    // method that would launch the service & hand off a wakelock.    super.onCreate();    // 创建一个 HandlerThread 并启动, HandlerThread 内部维护这一个Looper.    // 可以利用这个Looper来使用Handler机制..    HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");    thread.start();    // 保存Looper的引用, 便于在Service退出时.退出Looper    mServiceLooper = thread.getLooper();    // 创建Handler    mServiceHandler = new ServiceHandler(mServiceLooper);}
  1. 首先创建了一个HandlerThread对象, 并且启动了该对象.
  2. 然后保存了HandlerThread中的Looper对象的一个引用, 便于在IntentService销毁时对出Looper. 否则该子线程将会一直运行.
  3. 创建了一个Handler和创年的HandlerThread绑定在一起.

通过上面的三步就实现了. 一个可以接收msg的Handler, 并且在绑定的子线程中执行消息处理.之后我们只需要通过Handler发送消息, 通过Intent传送数据就可以实现在子线程中处理数据了.


  • 再看,Service每次启动都会调用的onStartCommand()和onStart()方法,主要看onStart
@Overridepublic void onStart(@Nullable Intent intent, int startId) {    // 发送消息.切换线程执行, 将Service的startId 发送过去, 便于stop Service    Message msg = mServiceHandler.obtainMessage();    msg.arg1 = startId;    msg.obj = intent;    mServiceHandler.sendMessage(msg);}

我们可以看出在onStart() 中的实现也是十分简单, 就是通过之前创建的Handler发送了一个消息.将intent数据发送过去, 同时还携带了一个参数startId . 之所以要携带这个id是因为在Handler中需要调用stopSelf()方法来停止Service, (下面的话有点通俗) 只有当所有的startdid都stop了, Service才会真正的退出.


  • 再来看, Handler的实现
private final class ServiceHandler extends Handler {    public ServiceHandler(Looper looper) {        super(looper);    }    @Override    public void handleMessage(Message msg) {        // 这个方法需要使用者实现.字节的逻辑, 在子线程中执行        onHandleIntent((Intent)msg.obj);        // 这个方法不会立即将Service结束掉, 会等到所有的onStart        // 注意1 : msg.arg1中保存的Service的startId        stopSelf(msg.arg1);    }}
  1. 首先会调用 onHandleIntent(intent)方法,并将数据传送进去.onHandleIntent(intent)方发是一个虚方法需要子类实现, 使用者的业务逻辑也是写在这个方法中的, 前面说过改Handler是和创建的HandlerThread对象的Looper绑定在一起的因此,次方法在子线程中执行.
  2. onHandleIntent(intent)方法执行完后, 就会调用 stopSelf(msg.arg1), 通过前面的分析可知msg.arg1 中存放给的是startId. 当所有的startId都被stop后Service也就结束了.

  • 继续 onDestroy()方法
@Overridepublic void onDestroy() {    // Service 烧毁时, 退出线程    mServiceLooper.quit();    super.onDestroy();}

Service结束后, 对于Service中启动的子线程是没有影响的.在这HandlerThread中有Looper因此不会自动退出, 需要手动调用quit方法.

IntentService注释版本代码如下

/** * @author : Brian * @date : 2017/6/29 */public abstract class IntentService extends Service {    private static final String TAG = "IntentService";    /**     * HandlerThread中获取的Looper, 便于在Service销毁时,退出线程.     */    private volatile Looper mServiceLooper;    /**     * 该Handler和HandlerThread的Looper线程绑定在一起,     * 也就是说会在那个线程中执行消息处理.     */    private volatile ServiceHandler mServiceHandler;    /**     * 线程名称     */    private String mName;    private boolean mRedelivery;    /**     * Handler     */    private final class ServiceHandler extends Handler {        public ServiceHandler(Looper looper) {            super(looper);        }        @Override        public void handleMessage(Message msg) {            // 这个方法需要使用者实现.字节的逻辑, 在子线程中执行            onHandleIntent((Intent)msg.obj);            // 这个方法不会立即将Service结束掉, 会等到所有的onStart            // 注意1 : msg.arg1中保存的Service的startId            stopSelf(msg.arg1);        }    }    /**     * 子类构造方法调用     */    public IntentService(String name) {        super();        mName = name;    }    /**     *     */    public void setIntentRedelivery(boolean enabled) {        mRedelivery = enabled;    }    @Override    public void onCreate() {        // TODO: It would be nice to have an option to hold a partial wakelock        // during processing, and to have a static startService(Context, Intent)        // method that would launch the service & hand off a wakelock.        super.onCreate();        // 创建一个 HandlerThread 并启动, HandlerThread 内部维护这一个Looper.        // 可以利用这个Looper来使用Handler机制..        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");        thread.start();        // 保存Looper的引用, 便于在Service退出时.退出Looper        mServiceLooper = thread.getLooper();        // 创建Handler        mServiceHandler = new ServiceHandler(mServiceLooper);    }    @Override    public void onStart(@Nullable Intent intent, int startId) {        // 发送消息.切换线程执行, 将Service的startId 发送过去, 便于stop Service        Message msg = mServiceHandler.obtainMessage();        msg.arg1 = startId;        msg.obj = intent;        mServiceHandler.sendMessage(msg);    }    /**     * 每次启动Service都会调用这个方法.     */    @Override    public int onStartCommand(@Nullable Intent intent, int flags, int startId) {        onStart(intent, startId);        return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;    }    @Override    public void onDestroy() {        // Service 烧毁时, 退出线程        mServiceLooper.quit();    }    /**     * Unless you provide binding for your service, you don't need to implement this     * method, because the default implementation returns null.     * @see android.app.Service#onBind     */    @Override    @Nullable    public IBinder onBind(Intent intent) {        return null;    }    /**     * 这个方法在子线程中被调用, 同一时刻只会有一个Intent请求被处理. 在逻辑上处理过程     * 在一个独立的子线程中执行.一次如果这个方法中的处理时间太长就会阻塞在同一个IntentService     * 发起的其他请求. 当所有的请求都处理结束后,IntentService会自动销毁. 因此不需要调用者     * 手动调用stopSelf()方法     */    @WorkerThread    protected abstract void onHandleIntent(@Nullable Intent intent);}
原创粉丝点击