当前位置: 首页 > news >正文

做垂直网站/新浪微博指数查询

做垂直网站,新浪微博指数查询,信誉好的手机网站建设,集团企业网站建设方案Android版本:8.1 我们知道MainActivity里面是不能做耗时操作的,几秒钟就会导致ANR,Application Not Responding应用无响应报错。于是我们会把耗时操作代码放在异步任务里AsyncTask,比如用异步任务从网上下载一个图片。下载完了我们…

Android版本:8.1


  • 我们知道MainActivity里面是不能做耗时操作的,几秒钟就会导致ANR,Application Not Responding应用无响应报错。
  • 于是我们会把耗时操作代码放在异步任务里AsyncTask,比如用异步任务从网上下载一个图片。
  • 下载完了我们就需要显示图片到Imageview上,而如果我们直接用imageview去更新图片,就会报错,提示你非主线程无法直接操作UI
CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
  • 这时我们通常就会调用Handler对象,去发送一个Message,在Handler的handleMessage方法里,就能直接去更新Imageview了。

当初我在学习的时候就一下子就冒出了一些问题,

  1. 为什么UI线程会ANR?
  2. 为什么子线程不能访问主线程的UI?
  3. AsyncTask是怎么使用的?
  4. Handler是怎么使用的?
    。。。

到了现在,当初的答案也都知道了,这里就写写关于Handler我知道的这一部分。


AsyncTask异步任务在使用的时候创建了一个新的Thread子线程,而主线程的view在初始化的时候都含有一个主线程对象,当然是ViewrootImpl那里,直接操作view的时候,都会先去检查是否是创建的时候的同一个线程,很明显,子线程不是那个创建的时候的线程,于是就会抛异常。在使用Handler的时候,发送Message,实现了跨线程通信,Message传到了主线程,再操作view更新,就不会异常了。
因为耗时,选择异步任务,因为子线程不能操作主线程UI,选择了Handler。


Hander在使用的时候
直接Handler handler = new Handler()就可以了,或者通常还会写一个匿名内部类方式。

  private final Handler mHandler = new Handler(){@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);}}

然后看看Handler源码,才知道handleMessage是handler的内部接口的方法

    public interface Callback {public boolean handleMessage(Message msg);}

在Handler的里面有几个成员变量

    final Looper mLooper; final MessageQueue mQueue;final Callback mCallback;IMessenger mMessenger;

Handler把利用Messenger把Message发送到MessageQueue,然后Looper不断从队列里取出Message,这就是Handler处理信息的流程。


Handler的构造

    public Handler() {this(null, false);}public Handler(Callback callback) {this(callback, false);}public Handler(Looper looper) {this(looper, null, false);}public Handler(Looper looper, Callback callback) {this(looper, callback, false);}public Handler(boolean async) {this(null, async);}public Handler(Looper looper, Callback callback, boolean async) {mLooper = looper;mQueue = looper.mQueue;mCallback = callback;mAsynchronous = async;}public Handler(Callback callback, boolean async) {...mLooper = Looper.myLooper();if (mLooper == null) {throw new RuntimeException("Can't create handler inside thread that has not called Looper.prepare()");}mQueue = mLooper.mQueue;mCallback = callback;mAsynchronous = async;}

在构造的时候如果传Looper对象,需要在Handler初始化之前调用Looper.prepare(),不然会异常。
其余的一般会使用无参或者带回调这两种方法。
于是可以理解前面的的匿名内部类写法了。

  private final Handler mHandler = new Handler(){@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);}}---private final Handler mHandler = new Handler(new Handler.Callback() {@Overridepublic boolean handleMessage(Message msg) {return false;}});

Handler的Message构造方式

    public final Message obtainMessage(){return Message.obtain(this);}public final Message obtainMessage(int what){return Message.obtain(this, what);}public final Message obtainMessage(int what, Object obj){return Message.obtain(this, what, obj);}public final Message obtainMessage(int what, int arg1, int arg2){return Message.obtain(this, what, arg1, arg2);}public final Message obtainMessage(int what, int arg1, int arg2, Object obj){return Message.obtain(this, what, arg1, arg2, obj);}

看看Message.obtain

    public static Message obtain(Handler h, int what,int arg1, int arg2, Object obj) {Message m = obtain();m.target = h;m.what = what;m.arg1 = arg1;m.arg2 = arg2;m.obj = obj;return m;}---public static Message obtain() {synchronized (sPoolSync) {if (sPool != null) {Message m = sPool;sPool = m.next;m.next = null;m.flags = 0; // clear in-use flagsPoolSize--;return m;}}return new Message();}

这就是别人常说的消息池,先从消息池里获取已经存在的对象,如果没有才创建,降低内存泄漏,重复利用。
所以我们平时在sendmessage的时候,应该不要直接new Message, 而是用Message.obtain 或者Handler.obtainMessage


Handler的sendMessage

    public final boolean sendMessage(Message msg){return sendMessageDelayed(msg, 0);}public final boolean sendEmptyMessage(int what){return sendEmptyMessageDelayed(what, 0);}public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {Message msg = Message.obtain();msg.what = what;return sendMessageDelayed(msg, delayMillis);}

发送message可以用的方法还有

sendEmptyMessageAtTime(int what, long uptimeMillis)
sendMessageDelayed(Message msg, long delayMillis)
sendMessageAtTime(Message msg, long uptimeMillis)
sendMessageAtFrontOfQueue(Message msg)

最后我们看看它到底怎么发送Message的

    public boolean sendMessageAtTime(Message msg, long uptimeMillis) {MessageQueue queue = mQueue;if (queue == null) {RuntimeException e = new RuntimeException(this + " sendMessageAtTime() called with no mQueue");Log.w("Looper", e.getMessage(), e);return false;}return enqueueMessage(queue, msg, uptimeMillis);}private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {msg.target = this;if (mAsynchronous) {msg.setAsynchronous(true);}return queue.enqueueMessage(msg, uptimeMillis);}

这里的mQueue就是在构造Handler的时候的Looper的MessageQueue,

boolean enqueueMessage(Message msg, long when) {//代码省略Message prev;for (;;) {prev = p;p = p.next;if (p == null || when < p.when) {break;}if (needWake && p.isAsynchronous()) {needWake = false;}}msg.next = p; // invariant: p == prev.nextprev.next = msg;//代码省略
}

当message被发送给MessageQueue的时候,会有个无限循环查找当前队列的message,如果有就把msg传给prev,然后Looper里面,还在循环cha

public static void loop() {final Looper me = myLooper();final MessageQueue queue = me.mQueue;Binder.clearCallingIdentity();final long ident = Binder.clearCallingIdentity();for (;;) {Message msg = queue.next(); // might blockif (msg == null) {// No message indicates that the message queue is quitting.return;}try {msg.target.dispatchMessage(msg);end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();} finally {if (traceTag != 0) {Trace.traceEnd(traceTag);}}msg.recycleUnchecked();}}

Looper无限从MessageQueue 里面next()获取下一个msg.
然后调用msg.target.dispatchMessage(msg);
msg的target就是Handler,

    public static Message obtain(Handler h, int what,int arg1, int arg2, Object obj) {Message m = obtain();m.target = h;  <---m.what = what;m.arg1 = arg1;m.arg2 = arg2;m.obj = obj;return m;}

于是回去看Handler的dispatchMessage

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

先检查msg是否含有回调,如果有就处理回调内容
如果没有则会检测当前Handler是否有回调对象,如果有就处理回调内容
如果没有回调,则直接处理msg
至此msg从handler发送出去,又回到handler来处理,好像没什么特别的。

其实这里忽略了一个点,msg是从子线程发送的,发出去之后它走到了主线程里,因为Looper是主线程里的Looper

在framework里,ActivityThread的Main方法里,Looper.prepareMainLooper();就是在Activity里构造了Looper对象,所以这里Looper是主线程的,那msg是什么时候从子线程传到主线程里的呢?

答案在MessageQueue的enqueueMessage里,做了一次传递

boolean enqueueMessage(Message msg, long when) {//代码省略
synchronized (this) {if (mQuitting) {IllegalStateException e = new IllegalStateException(msg.target + " sending message to a Handler on a dead thread");Log.w(TAG, e.getMessage(), e);msg.recycle();return false;}msg.markInUse();msg.when = when;Message p = mMessages;   //就是这里,从子线程达到主线程boolean needWake;if (p == null || when == 0 || when < p.when) {msg.next = p;mMessages = msg;needWake = mBlocked;} else {needWake = mBlocked && p.target == null && msg.isAsynchronous();Message prev;for (;;) {prev = p;p = p.next;if (p == null || when < p.when) {break;}if (needWake && p.isAsynchronous()) {needWake = false;}}msg.next = p; // invariant: p == prev.nextprev.next = msg;}// We can assume mPtr != 0 because mQuitting is false.if (needWake) {nativeWake(mPtr);}}//代码省略
}

所以,Message对象是跨过了线程,达到了主线程,所以提示信息可以更新,只需要根据msg的信息来更新不同的view就可以了。

然后关于Message对象,可以看到

public final class Message implements Parcelable {

Message实现了序列化接口Parcelable,这个标志表示这个对象可以实现跨进程传输,在不同进程传输的时候其实不是直接把对象给赋值过去,而是copy过去,把对象的所以属性都复制给一个新的另一个进程的对象,这就是实现序列化的意义。既符合不同进程对象不可直接传输,又实现了赋值对象间接的实现传输。

如此一来,发现其实Handler也很简单。

http://www.jmfq.cn/news/5145427.html

相关文章:

  • 中等职业学校网站建设模块/智能营销系统开发
  • 中国菲律宾商会/广州网站优化步骤
  • 贵州做网站公司/站长工具seo综合
  • 论坛推广网站/网络营销课程实训总结
  • 做网站的结论/真正永久免费网站建设
  • 做设计一般用的素材网站是什么/哪个好用?
  • 百合怎么doi怎么做网站/外贸网站建站平台
  • 做网站公司能赚钱吗/和生活app下载安装最新版
  • 成都网站建设app开发/百度图片搜索网页版
  • 怎么样制作一个公司网站/网络推广策划案
  • 杨凯做网站/友链互换平台推荐
  • 专做皮鞋销售网站/整合营销传播的方法包括
  • 做色情灰色网站怎么判刑/美国今天刚刚发生的新闻
  • 工控人如何做自己的网站/免费建立个人网站申请
  • 番禺制作网站设计/重庆网站页面优化
  • 可以自己做视频网站吗/百度推广一年大概多少钱
  • 珠海市企业网站制作服务机构/百度关键词搜索引擎
  • 单位网站建设的优势/百度推广要多少钱
  • 做网站发违规内容 网警抓不抓/b站视频推广网站400
  • 怎么做卖橘子的网站/天津百度搜索排名优化
  • 网站建设yu/有效获客的六大渠道
  • 7黄页网站建设/建站平台
  • 工信部网站实名认证怎么做/微信引流被加软件
  • 自己怎样制作网站/业务推广公司
  • 云服务器 能用来做网站吗/关键词制作软件
  • 有没有在家做的兼职网站/福州短视频seo推荐
  • 安吉网站建设/推广平台排行榜app
  • 笔记本电脑做网站比较畅快/百度指数 移民
  • 网站怎么做自己站长/搭建一个网站需要多少钱?
  • 济阳县做网站公司/seo软件开发