zoukankan      html  css  js  c++  java
  • 异步处理老司机:IntentService 源码分析

    IntentService 介绍

    IntentService 是一种特殊的 Service,它继承了 Service 并且它是一个抽象类,因此必须创建它的子类才能够使用 IntentService。它可用于执行后台耗时任务,当任务执行完成后它会自动停止,在资源不足时,系统会对一些被认为时无用的资源给清理掉,由于它是 Service 的原因,它的优先级比单纯的线程的优先级高很多,不容易被系统杀死(清理掉),所以它适合执行一些高优先级的后台任务。在实现上,IntentService 封装了 Handlerhread 和 Handler。

    HandlerThread 继承了 Thread,它是一种可以使用 Handler 的 Thread。它的实现是通过在run()方法中通过Looper.prepare()来创建消息队列,并通过Looper.loop()方法来开启消息循环, 它的内部对Thread 的 run 方法进行重写,通过Handler的消息方式(Looper循环)来通知HandlerThread执行一个具体的任务。

    @Override
    public void run() {
        mTid = Process.myTid();
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();
        mTid = -1;
    }
    

    在明确了不需要使用HandlerThread的时,可以通过它的quit或者quitSafely方法来终止线程的执行

    public boolean quit() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quit();
            return true;
        }
        return false;
    }
    
    public boolean quitSafely() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quitSafely();
            return true;
        }
        return false;
    }
    

    这两个方法的区别是:

    quit()
    使用此方法可能是不安全的,因为在Looper队列终止之前可能无法传递某些消息。

    quitSafely()
    使用此方法可能是安全的,因为一旦已经传递消息,队列中的所有剩余消息被处理,方法就会终止。然而,在循环终止之前,延迟的消息将在未来的到期时间内不传递。

    从源码来分析 IntentService 的执行顺序

    在onCreate()初始化HandlerThread和ServiceHandler,用于在后面调用onStart后来发送消息。

    @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 thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();
    
        mServiceLooper = thread.getLooper();
        mServiceHandler = new ServiceHandler(mServiceLooper);
    }
    

    每次启动服务都会调用一次onStartCommand()方法,并且它会调用onStart()

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

    在onStart()中发送消息

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

    后台任务是顺序执行的
    因为 Handler 中的 Looper 是顺序处理消息。

    任务执行完成之后结束服务:

    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); 而不使用 stopSelf();
            // 是因为 stopSelf() 会立即停止服务,
            // 而 stopSelf(msg.arg1); 在停止服务前会先判断最近启动服务的次数是否和 startId 相等
            // 如果相等就历经停止服务,不想动则不停止服务
            stopSelf(msg.arg1);
        }
    }
    

    IntentService 使用

    创建一个实例继承自 IntentService

    public class TestIntentService extends IntentService {
        private static final String TAG = "TestIntentService";
    
        public TestIntentService() {
            super(TAG);
            Log.e(TAG, "TestIntentService: " );
        }
    
        @Override
        public void onCreate() {
            super.onCreate();
            Log.e(TAG, "onCreate: " );
        }
    
        @Override
        protected void onHandleIntent(@Nullable Intent intent) {
            String taskAction = intent.getStringExtra("task_action");
            SystemClock.sleep(3000);
            Log.e(TAG, "onHandleIntent: "+taskAction);
        }
    
        @Override
        public void onDestroy() {
            Log.e(TAG, "onDestroy: service destory" );
            super.onDestroy();
        }
    }
    

    注册服务
    在AndroidMainfest.xml中注册服务

    <service android:name=".thread.TestIntentService"/>
    

    开启服务

    Intent intent = new Intent(CallBackTestActivity.this, TestIntentService.class);
    intent.putExtra("task_action","com.dx.action.TASK1");
    // 开启第一个服务
    startService(intent);
    intent.putExtra("task_action","com.dx.action.TASK2");
    // 开启第二个服务
    startService(intent);
    intent.putExtra("task_action","com.dx.action.TASK3");
    // 开启第三个服务
    startService(intent);
    

    输出结果是:

    从截图中的时间,以及输出顺序正好验证了上面的叙述!ok,完工~

    原创作者:龙衣袭,原文链接:https://www.jianshu.com/p/92c8a4451bb0

  • 相关阅读:
    Java线程同步synchronized的理解
    MySQL基础操作(二)
    MySQL基础操作(一)
    MySQL备份--xtrabackup与mysqldump工具使用
    MySQL主从复制以及在本地环境搭建
    生活在长大——第一次冲刺小任务
    现代软件工程之敏捷开发
    入门github
    我的编程人生
    Java线程
  • 原文地址:https://www.cnblogs.com/hejunlin/p/12669162.html
Copyright © 2011-2022 走看看