(一)如何使用Handler

大家好, 这是我第一次写博客,这次简单的介绍一下如何使用Handler完成线程之间的通信。
先说明一下为什么会用到线程之间的通信,这是因为Android中像关于网络这些比较费时的操作必须要在子线程中进行,而UI这种操作则是在主线程中进行(毕竟重活不能给老大干嘛,而子线程就是小弟)。但是问题来了,我在子线程拿到了资源了怎么跳到主线程中更新UI呢?所以今天介绍多线程中通信的其中一种方法——使用Handler进行通信。

//这是在主线程中更新UIHandler handler = new Handler() {            @Override            public void handleMessage(Message msg) {                Bitmap bitmap = (Bitmap) msg.obj;                urlImg.setImageBitmap(bitmap);            }        };    //子线程中的网络操作,这里面用的是okhttp开源框架获取图片的     new Thread(new Runnable() {                @Override                public void run() {                    try {                        Request request = new Request.Builder()                                .url("https://www.baidu.com/img/bdlogo.png")                                .build();                        Response response = client.newCall(request).execute();                        InputStream inputStream = response.body().byteStream();                        Bitmap bitmap = BitmapFactory.decodeStream(inputStream);                        Message message = Message.obtain();                        message.obj=bitmap;                        handler.sendMessage(message);                    } catch (IOException e) {                        e.printStackTrace();                    }                }            }).start();

来看一下上面的代码,想要建立Handler通信就需要new 一个Handler了,在子线程中我们已经获取到了bitmap这个资源了,我们需要一个Message对象用以发送,这个对象你可以直接new当然最好是像我上面那样使用Message.obtain(),用这种方法它会判断有没有Messeage对象,如果有就不会创建了,对于内存是会优化的。然后通过message.obj=bitmap将资源放到了Message里去了(这个obj你想放啥都可以),在子线程中handler.sendMessage(message),这是通过Handler发送了消息。

而在主线程中通过了Handler中的handleMessage(Message msg)我们拿到了消息,并获取了消息中的对象,并更新了UI。

(二)简谈Handler机制

知道了怎么用了以后,我们再来简单的了解一下Handler的机制,至少知道它流程是啥样的。

这是在下手画的,觉得丑的同学就多担待点吧。
接下来分析这个流程图,在子线程中的Handler将消息发送出去了,而在主线程中消息队列则是收到了message并放到它这个队列里,而在主线中有一个叫Looper的东东是消息循环器,它可以不断循环的读取消息队列中的消息并获取,在下面的Looper类中的loop方法里可以看到有一个死循环在不断地读取,而读取的对象就是MessageQueue.

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

在读取过后拿到了message,而在Looper类里面有这么一段代码msg.target.dispatchMessage(msg);那么这个msg.target是什么呢?
我们在Message这个类里面可以找到

/*package*/ Handler target;

定义了一个Handler类的target,这说明了Looper拿到了消息以后是要给主线程中的Handler来处理的,然后我们继续找后面的dispatchMessage(msg),在Handler类中有这么一段代码

public void dispatchMessage(Message msg) {        if (msg.callback != null) {            handleCallback(msg);        } else {            if (mCallback != null) {                if (mCallback.handleMessage(msg)) {                    return;                }            }            handleMessage(msg);        }    }

这说明了消息被Handler接受后需要实现handleMessage(msg),在这个方法中我们可以拿到了message同时拿到了它所承载的对象并更新我们的UI。
大致的流程跟我上面手画的流程图是差不多的。

更多相关文章

  1. Handler学习
  2. Android(安卓)一个可以自由定制外观、支持拖拽消除的MaterialDes
  3. Android(安卓)Handler 四个使用实例 及HandlerThread的使用
  4. android 进程与线程 相关
  5. Android异步任务处理之Thread线程
  6. 在Android中为啥建议你用Message.obtain()方法获取Message对象,而
  7. android中,由于图像处理不当而引起的OOM问题及其解决方案(一)
  8. 在ListView中增加HeaderView和FootView
  9. 线程对象Android(安卓)开发之多线程处理、Handler 详解

随机推荐

  1. Android RGB颜色查询对照表
  2. Exoplayer - HDCP test on Android
  3. Android:关于Configurations
  4. Unpack/repack ext4 Android system imag
  5. android bounceScrollView
  6. Android快速入门
  7. Android属性动画
  8. android开机动画
  9. android 开源项目汇总
  10. Android获取系统时间