HandlerThread与IntentService原理解析

前面我们讲到了Looper和Handler,只是为了写这篇文章做铺垫,其实在前面的使用中,我们已经可以感觉到了一些局限性,我们怎样来自己写两个线程是它们直接进行通信呢?在看这篇文章之前,可以先看看Looper与Handler解析这篇文章。
实现通信也很简单,只是要使用Handler的另一个构造函数,在Handler中有另一个比较有用的构造函数:Handler(Looper looper),这样自己来指定Looper对象,那么Looper对象就可以在另一个线程中定义好,然后给Handler使用,就可以实现了,直接来看Handler源码:

    public Handler(Looper looper) {
        this(looper, null, false);
    }

    public Handler(Looper looper, Callback callback, boolean async) {
        mLooper = looper;
        mQueue = looper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

我们可以为Handler指定Looper,也就是说我们可以为Handler发送的消息指定线程,我们可以单独的开一个线程A来进行消息队列的循环,在另一个线程B中或者其他的任何地方进行操作后,统一通过handler把消息发往线程A,来进行其他的一些操作,这样就可以把消息的处理统一用一个线程A来管理。而且这个线程是我们自己写的,也不影响主线程的运行。
下面直接给出一个小样例,这个小样例没有考虑内存泄漏的问题,暂且先忽略,关于内存泄漏的问题后面再单独讨论:

public class MainActivity extends Activity {
    private Handler mHandler;
    private MyThread mThread1;

    //这个线程是专门用来处理消息队列里的消息的
    //这个就是后面说的HandlerThread的精简版
    class MyThread extends Thread{
        Looper mLooper;

        @Override
        public void run() {
            //它会创建一个Looper对象
            Looper.prepare();
            //这里可以直接得到这个Looper对象
            mLooper = Looper.myLooper();
            //进行消息队列循环
            Looper.loop();
        }

        public Looper gerLooper(){
            return mLooper;
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mThread1 = new MyThread();
        mThread1.start();

        //在Handler中自己来指定前面开启的线程里的Looper
        //这样就可以使用到上面那个线程里的消息队列
        //如果还不明白就看我的上一篇文章:Looper与Handler解析
        //这个直接定义了一个匿名类,也可以单独把它定义称一个类,后面IntentService里面就是单独定义了一个类
        mHandler = new Handler(mThread1.gerLooper()){
            @Override
            public void handleMessage(Message msg) {
                //接受消息进行处理
                super.handleMessage(msg);
            }
        };

        //在线程B执行完了,就可以发一条消息给线程A
        Thread thread2 = new Thread(){
            @Override
            public void run() {
                //执行耗时操作
                //执行完后就发生消息
                mHandler.sendEmptyMessage(0);
            }
        };

    }

    public void operate1(){
        //执行操作
        mHandler.sendEmptyMessage(0);
    }
}

哈哈,说了这么多,其实只是为了说明HandlerThread的实现原理,因为早就有这样一个类来专门处理Handler消息,从名字HandlerThread也可以看出它是一个处理handler消息的线程。下面我就直接把HandlerThread的主要源码贴出来,基本跟上面MyThread一致,就是在这个基础上又加了点东西,主要原理都就这样,对照这看看,应该就明白了。

public class HandlerThread extends Thread {
    int mPriority;
    int mTid = -1;
    Looper mLooper;

    public HandlerThread(String name) {
        super(name);
        mPriority = Process.THREAD_PRIORITY_DEFAULT;
    }


    protected void onLooperPrepared() {
    }

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

    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();
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;
    }

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


    public int getThreadId() {
        return mTid;
    }
}

下面我们把上面的样例进行改动,直接使用HandlerThread替换我们写的MyYhread:

public class MainActivity extends Activity {
    private Handler mHandler;
    private HandlerThread mThread1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mThread1 = new HandlerThread("demo");
        mThread1.start();

        //在Handler中自己来指定前面开启的线程里的Looper
        //这样就可以使用到上面那个线程里的消息队列
        //这个直接定义了一个匿名类,也可以单独把它定义称一个类,后面IntentService里面就是单独定义了一个类
        //这里先不考虑内存泄漏的问题
        mHandler = new Handler(mThread1.gerLooper()){
            @Override
            public void handleMessage(Message msg) {
                //接受消息进行处理
                super.handleMessage(msg);
            }
        };

        //在线程B执行完了,就可以发一条消息给线程A
        Thread thread2 = new Thread(){
            @Override
            public void run() {
                //执行耗时操作
                //执行完后就发生消息
                mHandler.sendEmptyMessage(0);
            }
        };

    }

    public void operate1(){
        //执行操作
        mHandler.sendEmptyMessage(0);
    }
}

接下来我们要看的就是IntentService,大家都知道,虽然Service允许在后台,但是我们的耗时操作却并不能在Service中执行,因为Service和Activity一样都是运行在主线程,当然这样不考虑单独为它们指定进程。另外,当多次启动服务的时候,第一次启动会执行onCreate–onStartCommand,后面启动就会直接执行onStartCommand,这些都是基本知识。
下面有个测试代码:

public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.i("MainActivity", "activity onCreate() : " + Thread.currentThread().getId());
    }

    public void startMyService(View view){
        Intent intent = new Intent(this,MyService.class);
        startService(intent);
    }
}

public class MyService extends Service {
    public MyService() {
    }

    @Override
    public void onCreate() {
        Log.i("MyService","onCreate");
        super.onCreate();
    }

    @Override
    public IBinder onBind(Intent intent) {
        throw new UnsupportedOperationException("Not yet implemented");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i("MyService", "onBind() : " + Thread.currentThread().getId());
        Log.i("MyService","onStartCommand");
        return super.onStartCommand(intent, flags, startId);
    }
}

废话好像说的有点多,既然Service不能执行耗时操作,那么如果我们需要在Service里面执行耗时操作怎么办,那就可以使用IntentService,它是一个异步处理Service,本身继承自Service,然后在内部加了个线程罢了。它的内部原理又离不开Looper和Handler:
当启动IntentService的时候,首先执行的当然就是onCreate操作:

@Override
    public void onCreate() {
        super.onCreate();
        //看到没有,一上来就创建了一个HandleThread,对于HandleThread应该不陌生吧,上面刚刚讲过
        //简单说就是一个线程里面定义了一个Looper对象,并且循环处理消息队列
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();

        //得到上面HandlerThread线程中的Looper对象
        mServiceLooper = thread.getLooper();
        ServiceHandler就是一个handler,上面小样例我们定义的是一个匿名类,这里单独定义了一个类
        mServiceHandler = new ServiceHandler(mServiceLooper);
    }

这里把ServiceHandler也拿出来看看:

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

在上面的小样例中,我是这样定义的,

mHandler = new Handler(mThread1.gerLooper()){
            @Override
            public void handleMessage(Message msg) {
                //接受消息进行处理
                super.handleMessage(msg);
            }
        };

对照看看,它们其实是一样的,另外需要注意的是,它在handleMessaage中执行了一个onHandleIntent((Intent)msg.obj),而onHandleIntent是我们需要重载的函数,我们在创建一个MyIntentService来继承IntentService的时候,需要重载这个方法来执行我们的耗时操作,也就是说,我们的耗时操作是在HandleThread这线程中执行的。下面要解决的就是什么时候会执行这个函数,这点想必你已经清楚了,就是必须让handler发一个消息过来,从handleMessage这个函数来看,消息msg的obj对象里存放的是Intent,接着往下看,下面执行的就是onStart了。

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

看到没有,在onStart里面直接把intent放到消息里面,发送出去了,这样我们的耗时操作就放在了另一个线程中,Service做的就是通知HandlerThread线程来进行处理。

因为Service可以多次被启动,每次被启动都会执行onStart方法,这样每次startService都会往HandlerThread线程里面发一个消息,让线程了执行相应的操作,多么完美的设计。

下面我就提供一个小例子程序吧:

public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public void startMyService1(View view){
        Intent intent = new Intent(this,MyService.class);
        intent.setAction("Operator_A");
        startService(intent);
    }

    public void startMyService2(View view){
        Intent intent = new Intent(this,MyService.class);
        intent.setAction("Operator_B");
        startService(intent);
    }

}

public class MyService extends IntentService {

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

    @Override
    protected void onHandleIntent(Intent intent) {
        String action = intent.getAction();
        if(action.equals("Operator_A")){
            Log.i("MyService","Operator_A");
        }else if(action.equals("Operator_B")){
            Log.i("MyService","Operator_B");
        }
    }
}

程序很简单,但看到这个程序之后,应该知道了它内部是怎样实现的吧,这样就可以大胆的来使用了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值