Handler的多重用法 自动播放图片 进度条实例 与Looper MessageQueue关系

handler主要用法有两各

  1. 在新启动的线程中发送消息
  2. 在主线程中获取 处理消息

Android的消息传递机制是另一种形式的"事件处理" 这种机制主要是为了处理android的多线程问题——android只允许UI线程(当一个程序第一次启动时创建Main线程)修改activity中的UI组件 这样会导致新启动的线程无法动态改变界面组件的属性值。

如采用下图创建线程方式修改textview的值

在这里插入图片描述
会报如下错

在这里插入图片描述

注意:旧的API版本可以直接new Handler(MainActivity中 子线程不行) 在新版本中该使用方法被废弃了 需要重写一个类继承Handler 然后去使用自己写的handler 如果想在子线程里new一个handler 需要先调用Looper.prepare() 再去创建 并且调用 Looper.loop();接收信息

 new Thread(new Runnable() {
            @Override
            public void run() {
                Looper.prepare();
                new Handler(){
                    @Override
                    public void handleMessage(Message msg) {
                        super.handleMessage(msg);
                    }
                };
                Looper.loop();
            }
        })

在实际android开发中 尤其时涉及动画的游戏开发 需要让新启动的线程周期性的改变界面组件的属性值 这就需要Handler的消息传递机制
如下修改即可在这里插入图片描述
在此处修改textview
在这里插入图片描述

实现方法

  1. 延迟跳转 postDelayed方法 如图设置3s钟后跳转到另一个页面
    在这里插入图片描述
  2. 线程间通信 通过重写handleMessage方法处理消息在这里插入图片描述
  3. 使用hasMessages(int what)检查消息队列中是否包含what属性为指定值的消息
  4. 使用hasMessages(int what,Object object)检查消息队列中是否包含what属性为指定值且object属性为指定对象的消息
  5. 多个重载的Message obtainMessage():获取消息
  6. sendMessage(Message msg)立即发送消息(还有其他类似方法如发送空消息 指定多少毫秒后发送消息)

实例 自动播放动画

public ImageView mContentVideo = itemView.findViewById(R.id.im_video);
{
// onCreat或者其他处理数据的方法里
        MyHandler handler = new MyHandler();
        // 定义一个计时器 让该计时器周期性执行任务
        new Timer().schedule(new TimerTask() {
            @Override
            public void run() {
                // 发送空消息 0x:代表十六进制
                handler.sendEmptyMessage(0x1233);
            }
        },0,3000);

    }


    class MyHandler extends Handler{
        // 定义周期性显示的图片
        int[] imageIds = {R.drawable.im_v6,
                R.drawable.im_v2, R.drawable.im_v1, R.drawable.im_v4, R.drawable.im_v3};
        int currentImageId = 0;
        @Override
        public void handleMessage(@NonNull Message msg) {

            // 如果该消息是本程序发送的
            if (msg.what == 0x1233) {
                // 动态修改显示的图片
                mContentVideo.setImageResource(imageIds[(currentImageId++) % imageIds.length]);
            }
        }
    }

实例 使用handler实时更新进度条

点击此处跳转

与Looper MessageQueue关系

在这里插入图片描述

MessageQueue: 消息队列 采用先进先出的方式来管理Message 程序创建Looper对象时会在他的构造器中创建MessageQueue对象(private修饰 表名无法通过构造器创建Looper对象)

Message:Handler接受和处理的消息对象
其自身属性在这里插入图片描述
创建方式:在这里插入图片描述

Looper:每个线程只能拥有一个Looper 他的loop方法负责读取MessageQueue中的消息 读到消息后就把消息交给发送该消息的Handler进行处理

Handler:发送消息和处理消息 使用Handler发送的消息必须被送到指定的MessageQueue 也就是说当前线程必须要有一个MessageQueue对象 否则就没有地方保存消息
并且MessageQueue是由Looper负责管理的 也就是说线程中必须也要有个Looper对象 为了保证此状态 可分如下两种情况:

  1. 在主UI线程中 系统已经初始化了一个Looper对象 因此程序直接创建Handler即可
  2. 在子线程中创建Looper的步骤
    1. 调用Looper中的prepare()方法为当前线程创建Looper对象 其构造器会创建与之配套的MessageQueue
    2. 有了Looper之后创建Handler子类实例 重写handleMessage()方法 该方法负责处理来自其他线程的消息
    3. 调用Looper的loop()方法启动Looper在这里插入图片描述

prepare()该方法保证了每个线程只有一个Looper对象 如果有多个会抛出一个RuntimeException

    //这是第一个开始使用的地方
    public static void prepare() {
        prepare(true);
    }
    //主要创建了Looper对象,MessageQueue对象,指定了创建的线程
    private static void prepare(boolean quitAllowed) {
        //只能调用一次,第二次就抛异常了
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper(quitAllowed));
    }

调用Looper的静态loop()方法启动它 该方法采用一个死循环 不断取出MessageQueue中的消息 并将取出来的消息分给对应的Handler处理


    //开始循环分发MessageQueue中的消息到Handler
    public static void loop() {
        final Looper me = myLooper();
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        final MessageQueue queue = me.mQueue;

        // Make sure the identity of this thread is that of the local process,
        // and keep track of what that identity token actually is.
        Binder.clearCallingIdentity();
        final long ident = Binder.clearCallingIdentity();

        // Allow overriding a threshold with a system prop. e.g.
        // adb shell 'setprop log.looper.1000.main.slow 1 && stop && start'
        final int thresholdOverride =
                SystemProperties.getInt("log.looper."
                        + Process.myUid() + "."
                        + Thread.currentThread().getName()
                        + ".slow", 0);

        boolean slowDeliveryDetected = false;

        for (;;) {
            //获取消息队列中的消息
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }

            // This must be in a local variable, in case a UI event sets the logger
            final Printer logging = me.mLogging;
            if (logging != null) {
                logging.println(">>>>> Dispatching to " + msg.target + " " +
                        msg.callback + ": " + msg.what);
            }

            final long traceTag = me.mTraceTag;
            long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
            long slowDeliveryThresholdMs = me.mSlowDeliveryThresholdMs;
            if (thresholdOverride > 0) {
                slowDispatchThresholdMs = thresholdOverride;
                slowDeliveryThresholdMs = thresholdOverride;
            }
            final boolean logSlowDelivery = (slowDeliveryThresholdMs > 0) && (msg.when > 0);
            final boolean logSlowDispatch = (slowDispatchThresholdMs > 0);

            final boolean needStartTime = logSlowDelivery || logSlowDispatch;
            final boolean needEndTime = logSlowDispatch;

            if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
                Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
            }

            final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
            final long dispatchEnd;
            try {
                //然后分发消息到Handler的处理中
                msg.target.dispatchMessage(msg);
                dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
            if (logSlowDelivery) {
                if (slowDeliveryDetected) {
                    if ((dispatchStart - msg.when) <= 10) {
                        Slog.w(TAG, "Drained");
                        slowDeliveryDetected = false;
                    }
                } else {
                    if (showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery",
                            msg)) {
                        // Once we write a slow delivery log, suppress until the queue drains.
                        slowDeliveryDetected = true;
                    }
                }
            }
            if (logSlowDispatch) {
                showSlowLog(slowDispatchThresholdMs, dispatchStart, dispatchEnd, "dispatch", msg);
            }

            if (logging != null) {
                logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
            }

            // Make sure that during the course of dispatching the
            // identity of the thread wasn't corrupted.
            final long newIdent = Binder.clearCallingIdentity();
            if (ident != newIdent) {
                Log.wtf(TAG, "Thread identity changed from 0x"
                        + Long.toHexString(ident) + " to 0x"
                        + Long.toHexString(newIdent) + " while dispatching to "
                        + msg.target.getClass().getName() + " "
                        + msg.callback + " what=" + msg.what);
            }
            //释放消息
            msg.recycleUnchecked();
        }
    }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值