Android:Handler二三事(一)简介

主要内容

  • 为什么要使用Handler
  • 什么是Handler
  • 如何使用Handler
  • 在子线程中创建Handler

为什么要使用Handler

子线程不允许访问UI,UI操作必须在UI线程,也就是主线程中执行。

Android UI是线程不安全的,要想在子线程中更新UI,必须通过线程间通信,可以使用Handler,AsyncTask,runonUiThread等来实现。

什么是Handler

Handler允许发送和处理与MessageQueue相关的Message和Runnable对象,每个Handler实例都与一个线程和这个线程的MessageQueue相关联。当你new一个Handler时,它将绑定到创建他的Thread/MessageQueue上,然后它将向MessageQueue上发送消息或Runnable对象,并在他们从MessageQueue中释放时执行他们。

它实际上是一种消息循环处理机制。其中Handler,Looper都是在当前线程,也就是创建Handler的线程。

如何使用Handler

常用用法

新写一个类继承Handler

 private static class MyHandler extends Handler {
        private Context context;

        private MyHandler(Context context) {
            this.context = context;
        }

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);

            switch (msg.what) {
                case 1:
                    Toast.makeText(context, "hha", Toast.LENGTH_SHORT).show();
                    break;
                default:
                    break;
            }
        }
    }

创建Handler实例

private MyHandler handler = new MyHandler(this);

这里需要注意的是:静态内部类只能访问外部类的静态属性和方法,非静态内部类会持有外部类的引用,可能会造成内存泄露。如果Handler在主线程中创建,那么它自动绑定主线程。Looper在哪个线程,Handler就在哪个线程处理消息。

模拟子线程发送消息

        new Thread(new Runnable() {
            @Override
            public void run() {
                Message message = Message.obtain();
                message.what = 1;    // 标志位,可以区分不同类型的消息,类比type
                message.obj = 2;     // 传递的对象
                handler.sendMessage(message);
            }
        }).run();

与Handler一样,这里Thread同样存在可能造成内存泄漏的问题,但是偷个懒,这里暂时不做处理。

Toast

因为在主线程中才可以展示Toast,为了防止代码中出现子线程展示Toast的情况,我们可以在工具类中对Toast做处理

    private static Handler handler;

    public static void showToast(final Context context, final String msg) {
        if (context == null || TextUtils.isEmpty(msg)) {
            return;
        }

        if (handler == null) {
            handler = new Handler(Looper.getMainLooper());
        }

        handler.post(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(context, msg, LENGTH_SHORT).show();
            }
        });
    }

在子线程中创建Handler?

上面是关于主线程的Handler,也就是子线程通知主线程,那么主线程如何通知子线程呢?

仿照子线程通知主线程,我们将子线程的Looper设置到Handler中去

private static class MyThread extends Thread {

        /**
         * 取出子线程的Looper
         */
        private Looper looper;

        public Looper getLooper() {
            return looper;
        }

        @Override
        public void run() {
            super.run();

            // 创建子线程的Looper
            Looper.prepare();
            // 取出该子线程的Looper
            looper = Looper.myLooper();
            // 只有调用下面的方法才可以循环取用消息
            Looper.loop();
        }
    }

初始化对象

    private MyThread thread;
    private Handler handler;

调用

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

        thread = new MyThread();
        thread.start();

        handler = new Handler(thread.getLooper()) {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
            }
        };
        handler.sendEmptyMessage(0);

    }

但是这样会报空指针异常,为什么呢?因为在OnCreate()方法中,子线程执行之后,下面的代码也会依此执行,可能出现的情况就是Looper还没来得及初始化,就直接在Handler中使用了,那么就会出现空指针异常。也可能不会出现异常,但这都是随机的。

我们可以使用这种方式在子线程中创建Handler

private static class LooperThread extends Thread {
        private Handler handler;

        public Handler getHandler() {
            return handler;
        }

        @Override
        public void run() {
            super.run();

            Looper.prepare();

            handler = new Handler() {
                @Override
                public void handleMessage(Message msg) {
                    super.handleMessage(msg);

                    // 处理消息
                    Log.i("TAG","hha");
                }
            };

            Looper.loop();
        }
    }

但是需要注意的是,Handler可能为空

HandlerThread

上面的这种方式过于麻烦,我们可以使用HandlerThread。

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

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

        Handler handler = new Handler(handlerThread.getLooper()) {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);

                // 这里是子线程,可以处理耗时操作
                // 处理消息
            }
        };
        handler.sendEmptyMessage(0);

    }
HandlerThread还可用于多任务下载

引用

https://www.jianshu.com/p/0a274564a4b1

https://blog.csdn.net/iispring/article/details/47115879

https://developer.android.com/reference/android/os/Handler

https://blog.csdn.net/chenxiaofeng_/article/details/51492764

https://www.cnblogs.com/lang-yu/p/6228832.html

https://blog.csdn.net/u011240877/article/details/72905631#handlerthread-%E7%AE%80%E4%BB%8B

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值