Handler系列——HandlerThread(四)

1. 如何在线程中实现当前线程的Handler

当我们需要在在线程里面里使用线程自己的handler的时候,需要新建一个当前线程的Looper,但是必须要初始化Looper.prepare(),同时要调用Loop.loop()。代码如下:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        MyThread myThread = new MyThread();
        myThread.start();
        try {
        	// 主线程休眠一秒,否则会报错
        	// 空指针异常Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.os.Handler.sendEmptyMessage(int)' on a null object reference
            Thread.sleep(1000);
            myThread.mHandler.sendEmptyMessage(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    class MyThread extends Thread {
        Handler mHandler;
        @Override
        public void run() {
            super.run();
            // 创建线程的looper
            Looper.prepare();
            
            mHandler = new Handler(){
                @Override
                public void handleMessage(@NonNull Message msg) {
                    super.handleMessage(msg);
                    Log.e("MainActivity","handleMessage " + Thread.currentThread().getName());
                }
            };

            // 开启线程looper的循环
            Looper.loop();
        }
    }
}

打印结果如下,可以看到是线程中的handler在处理消息:
> MainActivity: handleMessage Thread-4

2. 向主线程的Handler传递子线程Looper

当我们尝试在主线程的Handler中传入子线程的Looper时,程序可能会报错,因为存在多线程并发的问题,当程序运行到主线程中handler的创建时,传入了子线程的Looper,如果此时子线程中的Looper还没有创建出来,传递的就是null,所以会抛出空指针异常。

public class MainActivity extends AppCompatActivity {


    private Handler mainHandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            Log.e("MainActivity","main111 ==  " + Thread.currentThread().getName());
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        MyThread myThread = new MyThread();
        myThread.start();
//        try {
//            Thread.sleep(1000);
//            myThread.mHandler.sendEmptyMessage(1);
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        }

        mainHandler.sendEmptyMessage(1);

        // 此处handler中传入myThread.threadLooper可能会报错,因为多线程中,当程序运行到此处时,Mythread中的looper可能还没有创建,是null
        // 报错 Attempt to read from field 'android.os.MessageQueue android.os.Looper.mQueue' on a null object reference
        mainHandler = new Handler(myThread.threadLooper){
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                Log.e("MainActivity","main222 ==  " + Thread.currentThread().getName());

            }
        };
        mainHandler.sendEmptyMessage(2);
    }

    class MyThread extends Thread {
        Handler mHandler;
        Looper threadLooper;
        @Override
        public void run() {
            super.run();
            // 创建线程的looper
            Looper.prepare();
            // 取到当前线程Looper的实例
            threadLooper = Looper.myLooper();

            mHandler = new Handler(){
                @Override
                public void handleMessage(@NonNull Message msg) {
                    super.handleMessage(msg);
                    Log.e("MainActivity","MyThread ===  " + Thread.currentThread().getName());
                }
            };

            // 开启线程looper的循环
            Looper.loop();
        }
    }
}

错误日志如下:
错误日志

而上面的问题,HandlerThread已经帮我们解决了。
HandlerThread是Thread的子类,严格意义上来说就是一个线程,只是它在自己的线程里面帮我们创建了Looper。

HandlerThread的用法:

public class HandlerThreadTest extends AppCompatActivity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        HandlerThread handlerThread = new HandlerThread("my HandlerThread");
        handlerThread.start();

        Handler handler = new Handler(handlerThread.getLooper()){
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                Log.e("HandlerThreadTest","Handler ==  " + Thread.currentThread().getName());
            }
        };
        handler.sendEmptyMessage(1);
    }
}

打印日志:
在这里插入图片描述

3. HandlerThread实现原理

我们再来看看HandlerThread的源码

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

getLooper方法中可以看到,当mLooper为空的时候,进入等待状态,那什么时候唤醒呢?接下来看run方法

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

在run方法中可以看到,和我们自己在线程中用Looper一样,也需要调用prepare初始化和loop开启轮询。
当然我们把重点放在这段代码上:

synchronized (this) {
    mLooper = Looper.myLooper();
    notifyAll();
}

通过Looper.myLooper()方法,把值给mLooper,再通过notifyAll()方法唤醒在等待的当前线程的对象,这时handler就能拿到looper对象,就不会再报空指针异常的问题。

4. HandlerThread 存在的意义如下:

  1. 方便使用:a. 方便初始化,b. 方便获取线程Looper
  2. 保证了线程安全
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值