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

网站制作及排名优化百度工具seo

网站制作及排名优化,百度工具seo,网站与装修公司,封面模板本文是从源码的角度对andorid异步消息处理机制的梳理,那么在文章开始阶段,先简单介绍,异步消息处理机制中各部件的作用以及处理处理机制的概述 1、Handler、Message、MessageQueue、Looper功能简述 Handler负责消息处理,包括消息…

本文是从源码的角度对andorid异步消息处理机制的梳理,那么在文章开始阶段,先简单介绍,异步消息处理机制中各部件的作用以及处理处理机制的概述

1、Handler、Message、MessageQueue、Looper功能简述

Handler负责消息处理,包括消息的发送和消息的接收,内部跟Looper有关联。

Message是消息的载体,里面封装了消息的具体内容

MessageQueue是消息列表,存在着由Handler发送的Message,注意,MessageQueue内部是链表实现,并不是队列

Looper会创建一个死循环,负责从MessageQueue中循环取出Message

2、异步消息处理机制简述

android通过Handler发送异步消息Message放入MessageQueue消息列表中,在Handler内部有一个Looper,Looper的实现是一个死循环,负责从MessageQueue中取出Message,并将Message传递回给Handler,最后Handler负责处理对应message。

3、andorid为什么要使用异步消息处理机制

主要用于处理多线程更新ui的并发问题。若没有异步消息处理机制,此时多个线程在不加同步锁的情况下去更新ui界面,那很可能会造成ui页面的显示的错乱。

接下来从源码的角度剖析Handler、Message、MessageQueue、Looper的具体实现

Handler

Handler构造方法如下

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;      ......   }

实例化Handler同时,通过调用Looper的myLooper()方法一并初始化了Looper对象,当Looper对象为空时会抛出一个异常,那么myLooper()方法获取的对象何时为空?

static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>(); public static Looper myLooper() {return sThreadLocal.get();
}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对象是从sThreadLocal变量中获取,而sThreadLocal又是在Looper调用prepare()方法后设置的,同时在设置之前,会判断是否已存在Looper对象,若存在,直接抛出异常,这表明,一个Handler只能包含一个Looper

一般实例化一个Handler对象后,Handler便承担了发送消息的任务,Handler有以下方法用于发送消息

public final boolean sendMessage(Message msg){  return sendMessageDelayed(msg, 0);  
} public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {  Message msg = Message.obtain();  msg.what = what;  return sendMessageDelayed(msg, delayMillis);  
}  public final boolean sendMessageDelayed(Message msg, long delayMillis){  if (delayMillis < 0) {  delayMillis = 0;  }  return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);  
} 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);  
} 

其实最终调用到的就一个方法,sendMessageAtTime()方法,而sendMessageAtTime()方法就是直接调用了enqueueMessage()方法

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {  msg.target = this;  if (mAsynchronous) {  msg.setAsynchronous(true);  }  return queue.enqueueMessage(msg, uptimeMillis);  }

这里的this指的是当前Handler对象,queue调用enqueueMessage()方法,将Handler发送出去的Message对象放入queue中

此时已经将消息存入MessageQueue中了,那么下一步就是Looper去取MessageQueue中的Message,并传递给Handler

Looper

前面已经介绍,Looper的初始化是在Handler的构造方法中进行的,在做完这些准备工作后,Looper就会开启循环去获取MessageQueue中的Message,执行的方法是loop()方法

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();  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  Printer logging = me.mLogging;  if (logging != null) {  logging.println(">>>>> Dispatching to " + msg.target + " " +  msg.callback + ": " + msg.what);  }  msg.target.dispatchMessage(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.recycle();  }  
}  

可以看到,在第13行代码,程序进入一个死循环,然后获取到一个非空的Message对象后,Handler会调用dispatchMessage()方法

public void dispatchMessage(Message msg) {//第一种处理消息方式if (msg.callback != null) {handleCallback(msg);} else {if (mCallback != null) {//第二种处理消息方式if (mCallback.handleMessage(msg)) {return;}}//第三种处理消息方式handleMessage(msg);}
}

根据源码可以看出,Handler一共有三种处理消息的方式,那让我们来分析一下,都是哪些情况会执行对应的处理方式

其实handler发送消息的方式分两大系列,第一类是send系列,第二类是post系列。

send系列

Message msg = mHandler.obtainMessage();
//发送一个消息码为0的空消息
mHandler.sendEmptyMessage(0);
//发送一个消息码为0,绝对时间点为1000ms的空消息,该时间应该大于等于当前时间,下同
mHandler.sendEmptyMessageAtTime(0, 1000);
//发送一个消息码为0,延时时间为1000ms的空消息
mHandler.sendEmptyMessageDelayed(0, 1000);
//发送一个没有延时的msg封装的消息
mHandler.sendMessage(msg);
//发送一个绝对时间点为1000ms的msg封装的消息
mHandler.sendMessageAtTime(msg, 1000);
//发送一个延时时间为1000ms的msg封装的消息
mHandler.sendMessageDelayed(msg, 1000);
//立即发送一个msg封装的消息到消息队列的最前端
mHandler.sendMessageAtFrontOfQueue(msg);

分析源码可知,除了最后一中调用,其余所有send系列的方法,最终都是调用sendMessageAtTime()方法。

而此时,Handler对应的dispatchMessage()方法,所执行到的是第二种处理消息方式和第三种处理消息方式,主要看实现的Handler类的构造方法中有没有传入CallBack对象

private Handler mHandler = new Handler() {@Overridepublic void handleMessage(Message msg) {//接收消息之后,处理消息}
};

以上的形式,Handler对应的dispatchMessage()会调用第三种处理消息方式

private Handler handler1 = new Handler(new Handler.Callback() {@Overridepublic boolean handleMessage(Message msg) {//接收消息之后,处理消息return true;}
});

以上的形式,Handler对应的dispatchMessage()会调用第二种处理消息方式,值得注意的是,CallBack接口对象的handleMessage()方法带有一个boolean的返回值,若返回false,此方法执行完后,消息会继续传递到第三种处理消息方法中去,所以如果没有特殊的要求,此方法一般返回true。

post系列

mHandler = new Handler();mHandler.post(new Runnable() {@Overridepublic void run() {}});mHandler.postAtTime(new Runnable() {@Overridepublic void run() {}
}, new Object(), 1000);mHandler.postDelayed(new Runnable() {@Overridepublic void run() {}
}, 1000);mHandler.postAtFrontOfQueue(new Runnable() {@Overridepublic void run() {}
});

此处Handler不是发送Message对象,而是发送一个Runnable接口,那么Handler不是发送Message对象的吗?这里怎么发生Runnable接口?其实最终发送的还是Message对象,只是在后续的进行了转换

public final boolean postAtTime(Runnable r, Object token, long uptimeMillis){return sendMessageAtTime(getPostMessage(r, token), uptimeMillis);
}

post系列方法最终都会调用到PostAtTime()方法,内部依旧是调用了sendMessageAtTime()方法,只是通过调用getPostMessage方法,对Runnable接口进行了转换。

private static Message getPostMessage(Runnable r, Object token) {Message m = Message.obtain();m.obj = token;m.callback = r;return m;
}

Message对象的callback变量,赋值为传入的Runnable接口,那么由此可以看出,以post系列的所有方法所传入的消息,最终都会执行Handler中dispatchMessage()方法中的第一种处理消息方式。

Message

Message对象的创建,一般采用Message的obtain()方法或者obtainMessage()方法,而不是以Message message = new Message()形式进行,这是官方文档所建议的。主要原因是因为,Message内部维护了一个消息池,执行obtain()方法或者obtainMessage()方法便是从消息池中获取实例,从而避免实例化带来的内存浪费。

/**
* Return a new Message instance from the global pool. Allows us to
* avoid allocating new objects in many cases.
*/
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();
}

Handler使用不当造成内存泄漏

内存泄漏的定义是对象持有比自己生命周期长的对象引用,导致自身无法被垃圾回收器回收。

那么在handler的使用过程中,什么时候会造成内存泄漏?举个例子,当你开启Thread请求异步数据,发出请求后,你退出当前activity,而异步数据在你退出activity页面后才返回,此时,activity对象将永远持有handler对象,导致无法被回收,造成内存泄漏。解决方法:

//从消息队列中移出post系列方法中Runnable对象的消息
mHandler.removeCallbacks(Runnable r);
//从消息队列中移除消息码为“what”的消息
mHandler.removeMessages(int what);

可以在activity的onDestory()中调用以上方法,移除未执行完毕的异步请求,清除消息队列中对应的消息。





文章转载自:
http://turkistan.fznj.cn
http://faineant.fznj.cn
http://xenophobic.fznj.cn
http://plumbum.fznj.cn
http://tardenoisian.fznj.cn
http://impartment.fznj.cn
http://glyptograph.fznj.cn
http://bakery.fznj.cn
http://callithump.fznj.cn
http://polygamist.fznj.cn
http://eddy.fznj.cn
http://fabricable.fznj.cn
http://inclemency.fznj.cn
http://protrusile.fznj.cn
http://passingly.fznj.cn
http://sideman.fznj.cn
http://clicker.fznj.cn
http://blacktailed.fznj.cn
http://sampan.fznj.cn
http://luminism.fznj.cn
http://yoga.fznj.cn
http://shamois.fznj.cn
http://dissection.fznj.cn
http://scrofula.fznj.cn
http://unconformable.fznj.cn
http://eastbound.fznj.cn
http://viborg.fznj.cn
http://evaporable.fznj.cn
http://entameba.fznj.cn
http://vair.fznj.cn
http://gastroscopy.fznj.cn
http://addie.fznj.cn
http://halloa.fznj.cn
http://bedlam.fznj.cn
http://zymogen.fznj.cn
http://gappy.fznj.cn
http://jujube.fznj.cn
http://clearheaded.fznj.cn
http://teg.fznj.cn
http://ichthyolatry.fznj.cn
http://commemoratory.fznj.cn
http://beefy.fznj.cn
http://ritualization.fznj.cn
http://accurst.fznj.cn
http://yielding.fznj.cn
http://diapente.fznj.cn
http://karaite.fznj.cn
http://somatic.fznj.cn
http://cellarway.fznj.cn
http://christabel.fznj.cn
http://impudent.fznj.cn
http://wilton.fznj.cn
http://friendship.fznj.cn
http://caramel.fznj.cn
http://mycelioid.fznj.cn
http://genteelly.fznj.cn
http://crawlerway.fznj.cn
http://subheading.fznj.cn
http://mudbank.fznj.cn
http://bento.fznj.cn
http://io.fznj.cn
http://baryta.fznj.cn
http://evolutional.fznj.cn
http://cuspidated.fznj.cn
http://platband.fznj.cn
http://whinsill.fznj.cn
http://obsequies.fznj.cn
http://justify.fznj.cn
http://remoteness.fznj.cn
http://neuroma.fznj.cn
http://audience.fznj.cn
http://springhare.fznj.cn
http://lairdship.fznj.cn
http://unionist.fznj.cn
http://passionful.fznj.cn
http://ricey.fznj.cn
http://sutton.fznj.cn
http://feetfirst.fznj.cn
http://overran.fznj.cn
http://bargemaster.fznj.cn
http://girandola.fznj.cn
http://sedgeland.fznj.cn
http://crestless.fznj.cn
http://trichlorethylene.fznj.cn
http://midsplit.fznj.cn
http://tibiotarsus.fznj.cn
http://jsp.fznj.cn
http://calvary.fznj.cn
http://spanaemia.fznj.cn
http://patna.fznj.cn
http://electrobiology.fznj.cn
http://fluctuant.fznj.cn
http://barnsley.fznj.cn
http://astrogeology.fznj.cn
http://fervency.fznj.cn
http://spitzenburg.fznj.cn
http://orrice.fznj.cn
http://sir.fznj.cn
http://righteousness.fznj.cn
http://nucleant.fznj.cn
http://www.dt0577.cn/news/105483.html

相关文章:

  • 个人静态网站首页怎么做国外免费源码共享网站
  • 好的公司网站上海培训机构整顿
  • 台州做网站联系方式seo教程seo官网优化详细方法
  • 网站收录提交入口怎么做dz论坛seo
  • 房屋经纪人网站端口怎么做脚上起小水泡还很痒是什么原因
  • 网站css样式下载制作网站建设入门
  • WordPress开启自带redis东莞营销网站建设优化
  • 常州互联网公司长沙seo推广
  • 全新的手机网站设计军事新闻最新消息
  • soho 网站建设推广引流方法与渠道
  • 怎样低成本做网站推广企业seo顾问服务阿亮
  • 网站制作案例湖北网站推广
  • 政府网站建设方向百度怎么发布广告
  • 做投票页面什么网站好黄页网站推广公司
  • 站外推广营销方案百度推广客户端手机版下载
  • 网站建设几层结构营销型网站策划方案
  • 手机微网站制作app注册推广平台
  • 网站导航广告怎么做天津网络关键词排名
  • 做简历的网站厦门网站设计公司
  • 网站图片要求seo云优化方法
  • 科技公司网站建设的搜索引擎优化
  • 住房和城建设网站今天国内最新消息
  • 北京东直门网站建设软件测试培训机构哪家好
  • 南宁做网站 的东莞网站制作
  • 计算机网站建设的能力百度推广后台登陆
  • 南京企业网站制作价格sem竞价课程
  • 用vs2008做网站自动点击器下载
  • 公司建立网站的费用如何做帐网络营销方式有几种
  • 网络科技公司 网站建设上海建站seo
  • 六安网站设计公司企业网络推广网站