HandlerThread和IntentService理解及源码分析

HandlerThread和IntentService,使用场景较少,但有些特定的场景会比较好用。

顾名思义HandlerThread,本质上是一个Thread,IntentService,本质上是一个Service,只是继承了Thread和Service类之后,它们内部做的一些动作使得这两个类不太一样,接下来我们来分析一下具体用法和源码:

一、HandlerThread

1、使用

 HandlerThread handlerThread = new HandlerThread("MyHandlerThread");
 handlerThread.start();
 Handler handler = new Handler(handlerThread.getLooper()) {
    @Override
    public void handleMessage(Message msg) {
        Log.d(TAG,"what : " + msg.what);
        Log.d(TAG,"thread : " + Thread.currentThread());
        super.handleMessage(msg);
    }
 };
 Message message = handler.obtainMessage();
 message.what = 1;
 handler.sendMessage(message);

首先创建一个HandlerThread的实例,并传入一个String类型的参数,作为线程的名字,然后新建一个Handler,把handlerThread.getLooper()作为参数传入Handler的构造参数。我们知道Handler需要一个Looper来构建消息循环,主线程的Handler使用的是sMainLooper,而如果我们要在子线程里面使用Handler,就要自己构建Looper,进行Looper.prepare()以及Looper.Loop(),这里HandlerThread正是起了一个创建Looper环境的作用,通过打印也可以看到:

12:55:00.905 4045-4062/com.optoma.imagetest D/MainActivity: what : 1
    					thread : Thread[MyHandlerThread,5,main]

当前线程是HandlerThread创建的MyHandlerThread线程。

2、源码分析
HandlerThread的源码较为简单,首先有两个构造参数,可以传入线程名,以及线程优先级,线程名不用赘述,线程优先级是给CPU调度线程的运行顺序的一个参考。往下看,我们能看到一个onLooperPrepared()方法:

	/**
     * Call back method that can be explicitly overridden if needed to execute some
     * setup before Looper loops.
     */
    protected void onLooperPrepared() {
    }

通过注释可以看到,这个方法是给我们继承HandlerThread,然后在loop()之前做的一些操作,比如一些数据的初始化等。再往下看,重写了run()方法:

	@Override
    public void run() {
        mTid = Process.myTid();
        Looper.prepare();//Looper准备
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();//这里是为了避免getLooper()在没初始化之前就调用,得到一个空值
        }
        Process.setThreadPriority(mPriority);//设置进程优先级
        onLooperPrepared();//
        Looper.loop();//开始循环
        mTid = -1;
    }

里面就是一个Looper的准备以及循环过程,getLooper()方法的代码如下:

	public Looper getLooper() {
        if (!isAlive()) {
            return null;//线程不在活动状态,返回空
        }
        
        // If the thread has been started, wait until the looper has been created.
        synchronized (this) {
            while (isAlive() && mLooper == null) {
                try {
                    wait();//一直等到mLooper不为空才notify()
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;
    }

HandlerThread代码较少,有些时候可以用到,比如需要在子线程处理数据,然后再发信息到主线程更新UI等。

二、IntentService

1、使用
IntentService作为一个Service,有着独特的使用场景。一般使用需要继承IntentService这个抽象类:
然后重写onHandleIntent()方法即可。
IntentService的特点是:在onHandleIntent()方法执行完毕之后,会销毁Service,即StopSelf(),所以我们可以在一些类似于文件扫描等场景下使用,不需要关注它的生命周期,文件扫描完成之后会自动关闭

2、源码分析
IntentService的代码内部,我们可以看到HandlerThread的影子
首先从构造函数,IntentService接受一个String类型的name,其实也是作为线程的名字:
我们可以看到一个Handler

	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的onCreate方法里面,有对这个Handler的调用:

	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);
    }

这下就很清楚了,传入的name,作为"IntentService[" + mName + "]"来给线程命名,这里使用到了HandlerThread来创建Looper,并构建Handler,然后在onStart方法中传递消息:

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

onStart里面只有几行代码,即传输startId和intent到ServiceHandler,ServiceHandler开始调用onHandleIntent()方法,startId用来stopSelf,而intent则用来传递给onHandleIntent()。
从这里不难看出,IntentService的onHandleIntent方法,其实也是运行在子线程的,所以可以做一些占内存的事而不用担心主线程被阻塞,这也是使用HandlerThread的原因。

三、拓展

多个IntentService的情况:

我们写一个简单的例子,在MainActivity中启动多次Service,然后重写Service的方法,看最终的打印:

	Handler handler = new Handler();
        for (int i = 0; i < 5; i++) {
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    Intent intent = new Intent(MainActivity.this,MyIntentService.class);
                    startService(intent);
                }
            }, 100);
        }
	public class MyIntentService extends IntentService {

    private static final String TAG = MyIntentService.class.getSimpleName();
    private int count = 0;

    public MyIntentService() {
        super("MyIntentService");
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        Log.d(TAG, "onHandleIntent : " + count++);
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "onCreate");
    }

    @Override
    public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
        Log.d(TAG, "onStartCommand : " + startId);
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onStart(@Nullable Intent intent, int startId) {
        Log.d(TAG, "onStart : " + startId);
        super.onStart(intent, startId);
    }
	@Override
    public void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "onDestroy");
    }
}

最终得出的结果:

10-09 13:34:34.914 23354-23354/? D/MyIntentService: onCreate
10-09 13:34:34.915 23354-23354/? D/MyIntentService: onStartCommand : 1
    onStart : 1
10-09 13:34:34.932 23354-23354/? D/MyIntentService: onStartCommand : 2
    onStart : 2
10-09 13:34:34.933 23354-23354/? D/MyIntentService: onStartCommand : 3
    onStart : 3
10-09 13:34:34.934 23354-23354/? D/MyIntentService: onStartCommand : 4
    onStart : 4
10-09 13:34:34.935 23354-23354/? D/MyIntentService: onStartCommand : 5
10-09 13:34:34.952 23354-23354/? D/MyIntentService: onStart : 5
10-09 13:34:35.917 23354-23391/com.optoma.imagetest D/MyIntentService: onHandleIntent : 0
10-09 13:34:36.918 23354-23391/com.optoma.imagetest D/MyIntentService: onHandleIntent : 1
10-09 13:34:37.919 23354-23391/com.optoma.imagetest D/MyIntentService: onHandleIntent : 2
10-09 13:34:38.920 23354-23391/com.optoma.imagetest D/MyIntentService: onHandleIntent : 3
10-09 13:34:39.980 23354-23391/com.optoma.imagetest D/MyIntentService: onHandleIntent : 4
10-09 13:34:39.980 23354-23391/com.optoma.imagetest D/MyIntentService: onDestroy

可以看出onCreate只会调用一次,但是onStartCommand以及onStart会调用多次,onHandleIntent则会一一执行,直到所有都执行完毕,最终调用onDestroy方法。上面看到的onHandleIntent之后调用的stopSelf(int startId)没有终止服务的原因是:stopSelf()会立即停止服务,而stopSelf(int startId)会等待所有消息都处理完后才终止服务。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值