Android Handler总结2-子线程中的Handler和HandlerThread的使用

为子线程创建Handler

Handler和线程通过Looper挂钩;所有在UI线程中创建的Handler不需要指定Looper,默认设置了MainLooper;所有在子线程中创建的Handler需要通过Loop.prepare()和Loop.loop()来设置子线程的Looper;一个线程只有一个Looper。

创建一个子线程的Handler示例代码如下:

public class MainActivity extends AppCompatActivity {

    private String TAG = "testHandler";
    private Button testBtn;

    class MyThread extends Thread {

        public Handler myThreadHandler;

        @Override
        public void run() {
            super.run();
            Looper.prepare();
            myThreadHandler = new Handler() {
                @Override
                public void handleMessage(Message msg) {
                    super.handleMessage(msg);
                    Log.e(TAG, "msg.what:" + msg.what);
                }
            };
            Looper.loop();
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        testBtn = (Button) findViewById(R.id.sample_text);

        //创建子线程并启动
        final MyThread myThread = new MyThread();
        myThread.start();

        testBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                for (int i = 0; i < 60; i++) {
                    //使用子线程中的Handler发送消息
                    myThread.myThreadHandler.sendEmptyMessageDelayed(i, i * 1000);
                }
            }
        });
    }
}

HandlerThread的作用和使用

先看如下代码:

public class MainActivity extends AppCompatActivity {

    private String TAG = "testHandler";
    private Handler myHandler;

    class MyThread extends Thread {
        public Looper myThreadLooper;
        @Override
        public void run() {
            super.run();
            Looper.prepare();
            myThreadLooper = Looper.myLooper();
            Looper.loop();
        }
    }

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

        //创建子线程并启动
        final MyThread myThread = new MyThread();
        myThread.start();
        //将子线程的Looper对象赋给myHandler
        myHandler = new Handler(myThread.myThreadLooper) {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                Log.e(TAG, "msg what:" + msg.what);
            }
        };
        myHandler.sendEmptyMessage(2);
    }
}

在上述代码中涉及到两个线程:UI线程和一个子线程;在UI线程中试图将子线程的Looper对象赋给Handler对象,在子线程运行的时候获取自己的Looper对象。

上述代码运行的时候会报如下错误:

 Caused by: java.lang.NullPointerException: Attempt to read from field 'android.os.MessageQueue android.os.Looper.mQueue' on a null object reference
        at android.os.Handler.<init>(Handler.java:236)
        at android.os.Handler.<init>(Handler.java:140)
        at com.cloudecg.jgc.test.androidrestudy.MainActivity$1.<init>(MainActivity.java:46)
        at com.cloudecg.jgc.test.androidrestudy.MainActivity.onCreate(MainActivity.java:46)
        at android.app.Activity.performCreate(Activity.java:6910)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1123)

即Looper对象为空。

产生上述错误的原因在于多线程并发,当UI线程执行到赋值操作的时候,子线程中的Looper对象还没有创建成功。

使用HandlerThread可以很方便的避免上述多线程并发带来的问题。

将上述代码改为HandlerThread的方式,如下:

public class MainActivity extends AppCompatActivity {

    private String TAG = "testHandler";
    private Handler myHandler;

    private HandlerThread myThread;

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

        //创建子线程并启动
        myThread = new HandlerThread("MyThreadHandler");
        myThread.start();

        //将子线程的Looper对象赋给myHandler
        myHandler = new Handler(myThread.getLooper()) {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                Log.e(TAG, "msg what:" + msg.what);
            }
        };
        myHandler.sendEmptyMessage(2);
    }
}

将Thread改为HandlerThread之后就不会产生之前的多线程并发问题了。
原因是在HandlerThread的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();
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;
    }

在HandlerThread中如果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的run方法中如果Looper对象创建成功,则唤醒所有等待线程。







我的视频课

下面是我录制的一些视频课,欢迎大家围观~

《Android性能优化参考》

本课程包含了Android中的App启动优化、UI优化、内存优化、图片优化、耗电量等常见的性能优化场景,通过学习此课程,你将对整个Android性能优化体系有清晰的认识。

性能优化作为Android高级开发的必备技能,也是大厂面试必考的题目,是体现一个人技术深度最好的试金石。

《面试之排序算法》

排序算法是我们面试被问到最多的基础算法,本课程详细介绍了七种排序算法,包括插入排序、选择排序、冒泡排序、谢尔排序、快速排序、堆积排序和二路并归排序。每种算法都详细介绍了核心思想、详细步骤、时间复杂度和代码实现,希望帮助大家深入理解排序算法,搞定面试!

《Android混合App开发实战》

本课程为Android HyBrid App开发实战课程,由浅入深,从三种App的历史和特点开始,介绍了Android WebView的使用、Java和JS交互的原生方式、著名的WebView安全漏洞、JSBridge的原理和使用,最后通过一个网上商城的实战综合全部内容,让同学们掌握并深入理解Android HyBrid App开发。

《AI导论》

介绍人工智能AI的诞生历史和到现在为止的不同发展阶段;介绍了AI领域中常见的名词概念和其关系,包括机器学习、深度学习、神经网络结构搜索 NAS、生成对抗网络 GAN等;最后对AI发展做出展望。
本课程属于导论课程,旨在帮助同学们从宏观层面把握AI,建立AI的知识体系。

《Java注解精讲》

本课程详细介绍了Java中的注解机制,包括注解的定义和分类,注解的使用和自定义,注解的源码和架构分析;
本课程语言简单凝练,视频短小精悍,让你一次彻底搞懂Java注解!

《Java反射精讲》

反射是Java中重要的也是较难理解的内容;
本课程从反射的定义、作用、原理和使用出发,全方位帮你彻底搞定反射;

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不死鸟JGC

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值