Hanlder的使用方式一:

 private static Handler mHandler =  new Handler(){
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case ONE: break; default:
break;
}
};
};

Handler的使用方式二:

     public void startHandlerThread(){
HandlerThread mHandlerThread = new HandlerThread("TestHandler");
mHandlerThread.start();
Handler mHandler = new Handler(mHandlerThread.getLooper()){
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
super.handleMessage(msg);
}
};
}

第二种比较通用,为什么这么说类,原因就是HandlerTrehad是个Thread,在run方法内部已经完成了Looper.prepare()的方法的调用,所以即使在子线程中也不会有任何问题

基本的使用就暂时说这些!!!!!

进入咱们今天的正题,深入裙内分析Handler源码:

 /**
* Sends a Message containing only the what value.
*
* @return Returns true if the message was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting.
*/
public final boolean sendEmptyMessage(int what)
{
return sendEmptyMessageDelayed(what, 0);
}

关于sendMessage就暂时拿这个进入问题内部;

Line10:说的很明确,调用delay方法,传入delay事件零毫秒,在跟进一步

  /**
* Sends a Message containing only the what value, to be delivered
* after the specified amount of time elapses.
* @see #sendMessageDelayed(android.os.Message, long)
*
* @return Returns true if the message was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting.
*/
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageDelayed(msg, delayMillis);
}

  这个方法为每个Handler消息进行封装一个Message对象,然后继续调用delay方法,但是这个方法的参数和之前的不一样,不通点就是接受一个Mesage对象,和一个延迟的时间。

  Line11:从缓存中读取Mesage对象,如果没有则直接创建;

  Line12,绑定What,回头再handlerMessage()方法中要用到;充当Swith的case;

  继续深入:

 public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}

  该出进行了容错处理防止你瞎传值;

  然后调用方法sendMessageAtTime这里的参数需要说明下:为什么SystemClock.uptimeMillis() + delayMillis这块的意思是加当当前系统时间,其实意思很明显如果你的延迟时间是一秒,那么这个一一秒的起始点,自然就是从当前算起,不然你仅仅说一秒,那么从什么时候开始那,这里就是这个意思了!!!

  来继续看方法sendMessageAtTime

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

  这个是Message入队的操作,看代码,既然说到入队,那么自然就少不了需要队列来存储这个Message,Line4,得到这个消息队列。然后准备入队;

  Line6:这个操作很重要,为什么要交付这个Targe,因为这里在出队列的时候要用到,出队后要调用handlermessge方法,进行消息处理,如何调用handlemessge方法,在Android的世界里基本就是指对象,很显然这里targe指向了当前对象this;(不懂没关系,后边会在补充讲解)

  Line7:进行入队操作,返回入队的最终结果,如果是true则代表成功入队,否则为失败;

 final boolean enqueueMessage(Message msg, long when) {
if (msg.when != 0) {
throw new AndroidRuntimeException(msg
+ " This message is already in use.");
}
if (msg.target == null && !mQuitAllowed) {
throw new RuntimeException("Main thread not allowed to quit");
}
final boolean needWake;
synchronized (this) {
if (mQuiting) {
RuntimeException e = new RuntimeException(
msg.target + " sending message to a Handler on a dead thread");
Log.w("MessageQueue", e.getMessage(), e);
return false;
} else if (msg.target == null) {
mQuiting = true;
} msg.when = when;
//Log.d("MessageQueue", "Enqueing: " + msg);
Message p = mMessages;
if (p == null || when == 0 || when < p.when) {
msg.next = p;
mMessages = msg;
needWake = mBlocked; // new head, might need to wake up
} else {
Message prev = null;
while (p != null && p.when <= when) {
prev = p;
p = p.next;
}
msg.next = prev.next;
prev.next = msg;
needWake = false; // still waiting on head, no need to wake up
}
}
if (needWake) {
nativeWake(mPtr);
}
return true;
}

  Line2 Line6很显然如果这两个对象为Null则直接就是throw exception;为什么这样那????因为这handler必须的两个字段。

  时间:标记何事处理这个Message;

  Target:应该由谁来处理;

  两者缺一不可,否则Handler就不是Handler了。。。。。。。

 核心代码Line20--36

 ................
msg.when = when;
//Log.d("MessageQueue", "Enqueing: " + msg);
Message p = mMessages;
if (p == null || when == 0 || when < p.when) {
msg.next = p;
mMessages = msg;
needWake = mBlocked; // new head, might need to wake up
} else {
Message prev = null;
while (p != null && p.when <= when) {
prev = p;
p = p.next;
}
msg.next = prev.next;
prev.next = msg;
needWake = false; // still waiting on head, no need to wake up
}
...................

  Line5的判断是拿当前即将进行出队的Message的when做对比,如果你的时间小(也就是你应该被优先出队),那么久交换当前的出队对象,很显然,现在Message就在事队列的最前端,等出队的时间到了就执行出队操作。

  Line9,这是入队操作不同点就是需要执行插入的操作,为什么要插入哪?因为Message的排序是按照When来排序的谁的When小谁在前边,这样出队就不会出错,保证出队的有序性。首先声明一个temp变量prev,然后从队列的首位置开始,根据时间when的大小进行比较,如果找到合适的就交换交换类似C中的指针方式。建议大家绘制个草图,可以很明显的看出交换过程!

  到了这里Message就完成了入队的操作,在整个入队的操作大家是否注意到一个问题,MessageQueu怎么出现的!!!!!

<:>讲述Message的初始化代码:

  说先追根溯源,第一次使用的地方就是Handler中,很好咱们就从这里入手吧!!!

 public Handler() {
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
} 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 = null;
}

  Line 16进行赋值 的操作,很显然最初的创建位置并不是这里,这里只是通过looper对象得到的改队列的引用,而并不是在这里进行了Create.

  Line 11这里有说道搞Looper对象的获取,既然咱们是通过Looper对象获取的队列对象,那么是不是咱们可以进入这个类看下原因为几何???

  private Looper() {
mQueue = new MessageQueue();
mRun = true;
mThread = Thread.currentThread();
}

  Line2说明这个问题,Looper对象创建的时候,初始化了这个MessageQueue.

<>><>到这里基本咱们说完了怎么入队,以及队列的由来,那么接下来就看怎么出队的操作!!!!

 说道出队,自然就说到咱们的《Looper,轮询器》

 既然Looper是轮询器,那么根据java面向对象的思想,这里自然就会偶轮训的方法loop;

  <<<<<果不其然>>>>>

    /**
* Run the message queue in this thread. Be sure to call
* {@link #quit()} to end the loop.
*/
public static final void loop() {
Looper me = myLooper();
MessageQueue queue = me.mQueue;
while (true) {
Message msg = queue.next(); // might block
//if (!me.mRun) {
// break;
//}
if (msg != null) {
if (msg.target == null) {
// No target is a magic identifier for the quit message.
return;
}
if (me.mLogging!= null) me.mLogging.println(
">>>>> Dispatching to " + msg.target + " "
+ msg.callback + ": " + msg.what
);
msg.target.dispatchMessage(msg);
if (me.mLogging!= null) me.mLogging.println(
"<<<<< Finished to " + msg.target + " "
+ msg.callback);
msg.recycle();
}
}
}

  代码484很少,哈哈哈哈,开森死人了、、、、、

  直奔主题走;Line22;这个Targe大家还记得不,(忘了去前边再去复习,真都比)上边说到这个是Handler对象,那么这里调用的方法dispatchMessage进行的Message的分发操作,自然分发最后还是交给了Handler,一起看下咱们说的队不对吧,去Handler找下这个方法????

  /**
* Handle system messages here.
*/
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}

  机会就是给准备的人,麻痹我终于还是给我找到了。。。。

  看方法Line13,这里干嘛了,前边的对于咱们的简单实用的时候尽管放心,没用,因为你没指定callback,所以自然就会走handleMessage方法中来,这个方法熟悉不!!!!!

  那个谁》》》》》你说啥不熟悉,奶奶的脚丫子滚蛋,,,,初始化Handler的时候 ,大家重载的那个方法就是这个了。。。

  

  哟,貌似忘记了啥,哦对了,子线程new handler crash问题,,,,,走看看去,报错的位置以及log484这。。。。

  

  mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}

  这里是要looper的时候,发现木有,,,,,Why,,,思考下咯,为啥没,那就看看哪里new Looper》???????

  查源码发现还是在Looper类中new类。。。

  

 /** Initialize the current thread as a looper.
* This gives you a chance to create handlers that then reference
* this looper, before actually starting the loop. Be sure to call
* {@link #loop()} after calling this method, and end it by calling
* {@link #quit()}.
*/
public static final void prepare() {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper());
}

额,这就是prepare方法了,也是就是大家禅说的子线程初始化的时候为啥调用这个方法,原因就是这了????

先这样,6666666666

Handle源码分析,深入群内了解风骚的Handle机制的更多相关文章

  1. Dubbo 源码分析 - 集群容错之 LoadBalance

    1.简介 LoadBalance 中文意思为负载均衡,它的职责是将网络请求,或者其他形式的负载"均摊"到不同的机器上.避免集群中部分服务器压力过大,而另一些服务器比较空闲的情况.通 ...

  2. Dubbo 源码分析 - 集群容错之 Cluster

    1.简介 为了避免单点故障,现在的应用至少会部署在两台服务器上.对于一些负载比较高的服务,会部署更多台服务器.这样,同一环境下的服务提供者数量会大于1.对于服务消费者来说,同一环境下出现了多个服务提供 ...

  3. Dubbo 源码分析 - 集群容错之 Router

    1. 简介 上一篇文章分析了集群容错的第一部分 -- 服务目录 Directory.服务目录在刷新 Invoker 列表的过程中,会通过 Router 进行服务路由.上一篇文章关于服务路由相关逻辑没有 ...

  4. Dubbo 源码分析 - 集群容错之 Directory

    1. 简介 前面文章分析了服务的导出与引用过程,从本篇文章开始,我将开始分析 Dubbo 集群容错方面的源码.这部分源码包含四个部分,分别是服务目录 Directory.服务路由 Router.集群 ...

  5. spark 源码分析之五 -- Spark内置RPC机制剖析之一创建NettyRpcEnv

    在前面源码剖析介绍中,spark 源码分析之二 -- SparkContext 的初始化过程 中的SparkEnv和 spark 源码分析之四 -- TaskScheduler的创建和启动过程 中的C ...

  6. MXNet源码分析 | KVStore进程内通信

    本文主要基于MXNet1.6.0版本进行分析. MXNet的KVStore模块下有几个比较重要的类.KVStore是一个抽象类,提供了一些通用的API,例如Init.Push和Pull等.因为KVSo ...

  7. dubbo源码分析- 集群容错之Cluster(一)

    1.集群容错的配置项 failover - 失败自动切换,当出现失败,重试其他服务器(缺省),通常用于读操作,但重试会带来更长的延时. failfast - 快速失效,只发起一次调用,失败立即报错.通 ...

  8. spark 源码分析之十二 -- Spark内置RPC机制剖析之八Spark RPC总结

    在spark 源码分析之五 -- Spark内置RPC机制剖析之一创建NettyRpcEnv中,剖析了NettyRpcEnv的创建过程. Dispatcher.NettyStreamManager.T ...

  9. Fabric2.2中的Raft共识模块源码分析

    引言 Hyperledger Fabric是当前比较流行的一种联盟链系统,它隶属于Linux基金会在2015年创建的超级账本项目且是这个项目最重要的一个子项目.目前,与Hyperledger的另外几个 ...

随机推荐

  1. 你也可以用java的swing可以做出这么炫的mp3播放器_源码下载

    I had published the blog : 你用java的swing可以做出这么炫的mp3播放器吗? and to display some screenshots about this M ...

  2. Android控件属性大全(转)

    http://blog.csdn.net/pku_android/article/details/7365685 LinearLayout         线性布局        子元素任意: Tab ...

  3. 《自制编程语言》笔记:使用yacc与lex制作简单计算器

    1.代码 1.1)test.l 1.2)test.y 1.3)Makefile (因为是在linux环境下,所以使用了Makefile) 2.编译与运行 2.1)编译 2.2)运行 1.代码(也可以在 ...

  4. Node.js 手册查询-3-Mongoose 方法

    Mongoose 参考手册 标签(空格分隔): MongoDB Mongoose 是什么? 一般我们不直接用MongoDB的函数来操作MongoDB数据库 Mongose就是一套操作MongoDB数据 ...

  5. bootstrap如何给.list-group加上序号

    在bootstrap中,我们可以使用不带任何class的<ol>跟<li>来创建一个有序列表,但是如果加上list-group类,样式有了,但列表前面的数字却没了. Boots ...

  6. js中return,this,arguments,currentStyle和getComputedStyle小析

    一.return返回值:1.函数名+括号:fn()==>return 后面的值2.所有函数默认返回值:未定义3.return后面的任何代码都不会执行二.this:当前对象1.当某个对象后边加事件 ...

  7. inconfont 字体库应用

    先去注册个号码,好像只可以用新浪微博登录哈,搞一个微博去. 第一就是点上面图标库,选择官方和所有都行. 恩接着点一个图标,他就自己跑到 第二个按钮哪里去了,在点第二个按钮,会出来一个创建项目,随便创建 ...

  8. php继承后构造函数的特性

    在5.x版本的php中: 如果父类有构造函数,它的子类也有构造函数,那么在运行子类时就“不会执行父类的构造函数”. 要想执行父类的构造函数,需要在子类的构造函数中加上: parent::__const ...

  9. xshell的快捷键(非常实用)

    删除 ctrl + d      删除光标所在位置上的字符相当于VIM里x或者dl ctrl + h      删除光标所在位置前的字符相当于VIM里hx或者dh ctrl + k      删除光标 ...

  10. 温故而知新 OOP

    设计原则1: 找出应用中可能需要发生改变的地方,把它们独立出来,不要和那些不需要变化的代码混在一起换句话说,如果每次新的需求一来,都会使某方面的代码发生变化,此时你就可以确定,这部分代码属于不稳定代码 ...