一、重要參考资料 

【參考资料】 

   眼下来看,以下的几个网址中的内容质量比較不错。基本不须要再读别的网址了。

1、android消息机制一 

   http://xtfncel.javaeye.com/blog/663517 

 Android消息机制(一) 

一、    角色描写叙述 

1.Looper: 一个线程能够产生一个Looper对象。由它来管理此线程里的Message Queue(消息队列)。 

2.Handler: 你能够构造Handler对象来与Looper沟通。以便push新消息到Message Queue里;或者接收Looper(从Message Queue取出)所送来的消息。

3. Message Queue(消息队列):用来存放线程放入的消息。

4.线程:UI thread 通常就是main thread,而Android启动程序时会替它建立一个Message Queue。 

每个线程里可含有一个Looper对象以及一个MessageQueue数据结构。在你的应用程序里。能够定义Handler的子类别来接收Looper所送出的消息。

在你的Android程序里。新诞生一个线程,或运行 (Thread)时,并不会自己主动建立其Message Loop。 

Android里并没有Global的Message Queue数据结构,比如,不同APK里的对象不能透过Massage
Queue来交换讯息(Message)。

比如:线程A的Handler对象能够传递消息给别的线程。让别的线程B或C等能送消息来给线程A(存于A的Message Queue里(//怎样理解?))。

线程A的Message Queue里的讯息,仅仅有线程A所属的对象能够处理。

使用Looper.myLooper能够取得当前线程的Looper对象。 

使用mHandler = new EevntHandler(Looper.myLooper()); 可用来构造当前线程的Handler对象;当中。EevntHandler是自已实现的Handler的子类别。

使用mHandler = new EevntHandler(Looper.getMainLooper());
可诞生用来处理main线程的Handler对象;当中。EevntHandler是自已实现的Handler的子类别。





这样描写叙述可能太抽像。以下举几个实际的样例来说明: 

二、    举例 

1.  同线程内不同组件间的消息传递 

Looper类用来管理特定线程内对象之间的消息交换(Message Exchange)。

你的应用程序能够产生很多个线程。

而一个线程能够有很多个组件,这些组件之间经常须要互相交换讯息。假设有这样的须要,您能够替线程构造一个Looper对象。来担任讯息交换的管理工作。

Looper对象会建立一个MessageQueue数据结构来存放各对象传来的消息(包含UI事件或System事件等)。例如以下图:



每个线程里可含有一个Looper对象以及一个MessageQueue数据结构。在你的应用程序里。能够定义Handler的子类别来接收Looper所送出的消息。

同线程不同组件之间的消息传递:

public class Activity1 extends Activity implements OnClickListener{
Button button = null;
TextView text = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity1);
button = (Button)findViewById(R.id.btn);
button.setOnClickListener(this);
text = (TextView)findViewById(R.id.content);
}
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn: //组件1
Looper looper = Looper.myLooper();//取得当前线程里的looper
MyHandler mHandler = new MyHandler(looper);//构造一个handler使之可与looper通信
//buton等组件能够由mHandler将消息传给looper后,再放入messageQueue中,同一时候mHandler也能够接受来自looper消息
mHandler.removeMessages(0);
String msgStr = "主线程不同组件通信:消息来自button";
Message m = mHandler.obtainMessage(1, 1, 1, msgStr);//构造要传递的消息
mHandler.sendMessage(m);//发送消息:系统会自己主动调用handleMessage方法来处理消息
break; }
}
private class MyHandler extends Handler{
public MyHandler(Looper looper){
super(looper);
}
@Override
public void handleMessage(Message msg) {//处理消息
text.setText(msg.obj.toString()); //组件2
}
}
}

说明: 

此程序启动时,当前线程(即主线程, main thread)已诞生了一个Looper对象。而且有了一个MessageQueue数据结构。 

    looper = Looper.myLooper ();  



调用Looper类别的静态myLooper()函数。以取得眼下线程里的Looper对象. 



mHandler = new MyHandler (looper); 



构造一个MyHandler对象来与Looper沟通。

Activity等对象能够藉由MyHandler对象来将消息传给Looper。然后放入MessageQueue里;MyHandler对象也扮演Listener的角色,可接收Looper对象所送来的消息。

Message m = mHandler.obtainMessage(1, 1, 1, obj); 



先构造一个Message对象,并将数据存入对象里。 

mHandler.sendMessage(m); 



就透过mHandler对象而将消息m传给Looper,然后放入MessageQueue里。

此时。Looper对象看到MessageQueue里有消息m,就将它广播出去。mHandler对象接到此讯息时。会呼叫其handleMessage()函数来处理,于是输出"This my message!"于画面上。







2、Android消息机制二 

   http://xtfncel.javaeye.com/blog/663518

Android消息处理机制(二)

角色综述(回想):

(1)UI thread 通常就是main thread,而Android启动程序时会替它建立一个MessageQueue。

(2)当然须要一个Looper对象,来管理该MessageQueue。

(3)我们能够构造Handler对象来push新消息到Message Queue里;或者接收Looper(从Message Queue取出)所送来的消息。

(4)线程A的Handler对象能够传递给别的线程。让别的线程B或C等能送讯息来给线程A(存于A的Message Queue里)。

(5)线程A的Message Queue里的消息。仅仅有线程A所属的对象能够处理。

子线程传递消息给主线程

publicclass Activity2extends Activityimplements OnClickListener{

       Button button =null;

       TextView text =null;

       MyHandler mHandler = null;

       Thread thread ;

       @Override

       protectedvoid onCreate(Bundle savedInstanceState) {

              super.onCreate(savedInstanceState);

              setContentView(R.layout.activity1);        

              button = (Button)findViewById(R.id.btn);

              button.setOnClickListener(this);

              text = (TextView)findViewById(R.id.content);

       }

       publicvoid onClick(View v) {

              switch (v.getId()) {

              case R.id.btn:

                     thread =new MyThread();

                     thread.start();

                     break;

              }            

       }     

       privateclass MyHandlerextends Handler{             

              public MyHandler(Looper looper){

                     super(looper);

              }

              @Override

              publicvoid handleMessage(Message msg) {//处理消息

                     text.setText(msg.obj.toString());

              }            

       }

       privateclass MyThreadextends Thread{

              @Override

              publicvoid run() {

                     Looper curLooper = Looper.myLooper();

                     Looper mainLooper = Looper.getMainLooper();

                     String msg ;

                     if(curLooper==null){

                            mHandler =new MyHandler(mainLooper);

                            msg = "curLooper is null";

                     }else{

                            mHandler =new MyHandler(curLooper);

                            msg = "This is curLooper";

                     }

                     mHandler.removeMessages(0);

                     Message m = mHandler.obtainMessage(1, 1, 1, msg);

                     mHandler.sendMessage(m);

              }            

       }

}

说明:

Android会自己主动替主线程建立Message Queue。在这个子线程里并没有建立Message Queue。

所以,myLooper值为null。而mainLooper则指向主线程里的Looper。于是。运行到:

mHandler = new MyHandler (mainLooper);

此mHandler属于主线程。

mHandler.sendMessage(m);

就将m消息存入到主线程的Message Queue里。mainLooper看到Message Queue里有讯息。就会作出处理,于是由主线程运行到mHandler的handleMessage()来处理消息。

3、Android线程间通信的message机制 

   http://www.javafun.cn/viewthread.php?tid=15174

在Android以下也有多线程的概念。在C/C++中,子线程能够是一个函数。一般都是一个带有循环的函数,来处理某些数据。优先线程仅仅是一个复杂的运算过程,所以可能不须要while循环,运算完毕,函数结束。线程就销毁。

对于那些须要控制的线程,一般我们都是和相互排斥锁相互关联,从而来控制线程的进度,一般我们创建子线程,一种线程是非经常见的,那就是带有消息循环的线程。

消息循环是一个非常实用的线程方式,以前自己用C在Linux以下实现一个消息循环的机制,往消息队列里加入数据。然后异步的等待消息的返回。

当消息队列为空的时候就会挂起线程,等待新的消息的加入。这是一个非常通用的机制。

在Android,这里的线程分为有消息循环的线程和没有消息循环的线程,有消息循环的线程一般都会有一个Looper。这个事android的新概念。

我们的主线程(UI线程)就是一个消息循环的线程。针对这样的消息循环的机制,我们引入一个新的机制Handle。我们有消息循环。就要往消息循环里面发送对应的消息,自己定义消息一般都会有自己对应的处理,消息的发送和清除。消息的的处理。把这些都封装在Handle里面。注意Handle仅仅是针对那些有Looper的线程,无论是UI线程还是子线程,仅仅要你有Looper,我就能够往你的消息队列里面加入东西,并做对应的处理。

可是这里另一点,就是仅仅要是关于UI相关的东西。就不能放在子线程中,由于子线程是不能操作UI的,仅仅能进行数据、系统等其它非UI的操作。

那么什么情况以下我们的子线程才干看做是一个有Looper的线程呢?我们怎样得到它Looper的句柄呢?

Looper.myLooper();获得当前的Looper

Looper.getMainLooper () 获得UI线程的Lopper

我们看看Handle的初始化函数,假设没有參数。那么他就默认使用的是当前的Looper,假设有Looper參数,就是用相应的线程的Looper。

假设一个线程中调用Looper.prepare(),那么系统就会自己主动的为该线程建立一个消息队列。然后调用 Looper.loop();之后就进入了消息循环,这个之后就能够发消息、取消息、和处理消息。

这个怎样发送消息和怎样处理消息能够再其它的线程中通过Handle来做,但前提是我们的Hanle知道这个子线程的Looper,可是你假设不是在子线程执行 Looper.myLooper(),通常是得不到子线程的looper的。

public void run() {
synchronized (mLock) {
Looper.prepare();
//do something
}
Looper.loop();
}

所以非常多人都是这样做的:我直接在子线程中新建handle,然后在子线程中发送消息。这种话就失去了我们多线程的意义了。

class myThread extends Thread{
private EHandler mHandler ;
public void run() {
Looper myLooper, mainLooper;
myLooper = Looper.myLooper ();
mainLooper = Looper.getMainLooper ();
String obj;
if (myLooper == null ){
mHandler = new EHandler(mainLooper);
obj = "current thread has no looper!" ;
}
else {
mHandler = new EHandler(myLooper);
obj = "This is from current thread." ;
}
mHandler .removeMessages(0);
Message m = mHandler .obtainMessage(1, 1, 1, obj);
mHandler .sendMessage(m);
}
}

能够让其它的线程来控制我们的handle,能够把
private EHandler mHandler ;放在外面。这样我们的发消息和处理消息都能够在外面来定义,这样添加程序代码的美观,结构更加清晰。

对如不论什么的Handle,里面必需要重载一个函数

public void handleMessage(Message msg)

这个函数就是我们的消息处理。怎样处理。这里全然取决于你。然后通过 obtainMessage和 sendMessage等来生成和发送消息, removeMessages(0)来清除消息队列。

Google真是太智慧了,这样的框架的产生,我们写代码更加轻松了。

有的时候,我们的子线程想去改变UI了,这个时候千万不要再子线程中去改动,获得UI线程的Looper,然后发送消息就可以。

我们看看Goole Music App的源码。

在MediaPlaybackActivity.java中,我们能够看一下再OnCreate中的有这种两句:

mAlbumArtWorker = new Worker("album art worker");
mAlbumArtHandler = new AlbumArtHandler(mAlbumArtWorker.getLooper());

非常明显这两句。是构建了一个子线程。

而且这个子线程还是Looper的子线程,这里非常牛逼的使用了 mAlbumArtWorker.getLooper()这个函数,由于我们知道,我们可以得到子线程的Looper的途径仅仅有一个:就是在子线程中调用 Looper.myLooper (),而且这个函数还要在我们perpare之后调用才干得到正确的Looper,可是他这里用了一个这种什么东东
getLooper。不知道它是怎样实现的?

这里有一个大概的思路,我们在子线程的的prepare之后调用 myLooper ()这种方法,然后保存在一个成员变量中,这个getLooper就返回这个东西,可是这里会碰到多线程的一个非常突出的问题,同步。我们在父线程中调用 mAlbumArtWorker.getLooper(),可是想要这个返回正确的looper就必需要求我们的子线程执行了prepare,可是这个东西实在子线程执行的,我们怎样保证呢?

我们看Google是怎样实现的?

private class Worker implements Runnable {
private final Object mLock = new Object();
private Looper mLooper; /**
* Creates a worker thread with the given name. The thread
* then runs a [email=%7B@link]{@link[/email] android.os.Looper}.
* @param name A name for the new thread
*/
Worker(String name) {
Thread t = new Thread(null, this, name);
t.setPriority(Thread.MIN_PRIORITY);
t.start();
synchronized (mLock) {
while (mLooper == null) {
try {
mLock.wait();
} catch (InterruptedException ex) {
}
}
}
} public Looper getLooper() {
return mLooper;
} public void run() {
synchronized (mLock) {
Looper.prepare();
mLooper = Looper.myLooper();
mLock.notifyAll();
}
Looper.loop();
} public void quit() {
mLooper.quit();
}
}

我们知道。一个线程类的构造函数是在主线程中完毕的。所以在我们的 Worker的构造函数中我们创佳一个线程。然后让这个线程执行,这一这个线程的创建是指定一个
Runnabl,这里就是我们的Worker本身,在主线程调用 t.start();,这后,我们子线程已经创建,而且開始运行work的run方法。然后以下的代码非常艺术:

synchronized (mLock) {
while (mLooper == null) {
try {
mLock.wait();
} catch (InterruptedException ex) {
}
}
}

我们開始等待我们的子线程给mLooper赋值,假设不赋值我们就继续等,然后我们的子线程在执行run方法之后,在给 mLooper赋值之后,通知worker够着函数中的wait。然后我们的构造函数才干完毕,所以我们说:

mAlbumArtWorker = new Worker("album art worker");

这句本身就是堵塞的,它创建了一个子线程,开启了子线程,而且等待子线程给mLooper赋值,赋值完毕之后,这个函数才返回,这样才干保证我们的子线程的Looper的获取绝对是正确的,这个构思非常有创意。

值得借鉴<!--++ plugin_code qcomic begin--> <!--++ plugin_code qcomic end-->

4、Android中Handler的用法-在子线程中更新界面

http://blog.csdn.net/chaoyu168/article/details/50914021

二、知识要点 

一、知识点 

1、handler应该由处理消息的线程创建。 



2、handler与创建它的线程相关联,并且也仅仅与创建它的线程相关联。handler执行在创建它的线程中,所以,假设在handler中进行耗时的操作。会堵塞创建它的线程。

【来源】以上来自: 

二、一些知识点 

1、Android的线程分为有消息循环的线程和没有消息循环的线程。有消息循环的线程一般都会有一个Looper。主线程(UI线程)就是一个消息循环的线程。



2、 

Looper.myLooper();      //获得当前的Looper 

Looper.getMainLooper () //获得UI线程的Lopper 



3、Handle的初始化函数(构造函数),假设没有參数。那么他就默认使用的是当前的Looper,假设有Looper參数,就是用相应的线程的Looper。



4、假设一个线程中调用Looper.prepare(),那么系统就会自己主动的为该线程建立一个消息队列。然后调用 Looper.loop();之后就进入了消息循环。这个之后就能够发消息、取消息、和处理消息。【来源】以上来自:http://www.javafun.cn/viewthread.php?tid=1517



三、应用实例 

3.1 handler传递message【应用演示样例一】

package com.android.tutor;
import java.util.Timer;
import java.util.TimerTask;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
public class HandlerDemo extends Activity { //title为setTitle方法提供变量,这里为了方便我设置成了int型
private int title = 0; private Handler mHandler = new Handler(){
public void handleMessage(Message msg) {
switch (msg.what) {
case 1:
updateTitle();
break;
}
};
};
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main); Timer timer = new Timer();
timer.scheduleAtFixedRate(new MyTask(), 1, 5000);
} private class MyTask extends TimerTask{
@Override
public void run() { Message message = new Message();
message.what = 1;
mHandler.sendMessage(message);
}
} public void updateTitle(){ setTitle("Welcome to Mr Wei's blog " + title);
title ++;
}
}

上面的代码,直接在主线程中定义Handler成员。在子线程中通过主线程的handler向主线程发送消息。其使用过程例如以下: 

1、在主线程中定义handler,并为这个handler实现handleMessage方法。 

2、在子线程中调用主线程的handler。通过其sendMessage方法发送消息。 



3.2 handler传递runnable对象还有第二种用Handler来进行线程间通信的方式。那就是用Handler来传递一个runnable对象。而不是一个message。

【应用实例三】 



使用步骤 

1、在主线程中定义Handler对象 

2、构造一个runnable对象,为该对象实现runnable方法,在该方法中进行一些你想做的耗时操作。 

3、在子线程中使用Handler对象post(runnable)对象.

最新文章

  1. Java开发环境搭建——Tomcat配置
  2. JSP - 9大内置对象及其API
  3. angularjs之插件ngRoute和ngAnimate
  4. js动态切换图片
  5. cocos2d-x中Node中重要的属性
  6. Google实习面试归来
  7. MVC的Model层中的一些便签
  8. MapReduce调度与执行原理之任务调度(续)
  9. VS2010,原来还有这些快捷键,果断记下来!
  10. 使用(Drawable)资源———ClipDrawable资源
  11. Visual Studio 2015创建ASP.NET5项目“DNX SDK version &#39;dnx-clr-win-x86.1.0.0-beta5&#39; 无法安装的错误
  12. docker~Dockerfile优化程序的部署
  13. Spring Data 整合 ElasticSearch搜索服务器
  14. mysql进阶(二十六)MySQL 索引类型(初学者必看)
  15. hive启用压缩
  16. Putty查看生产环境下程序后台日志
  17. keepalive高可用
  18. ECharts柱状图添加点击事件
  19. java System.arraycopy()
  20. 6.简单提取小红书app数据保存txt-2

热门文章

  1. 2015 UESTC 数据结构专题A题 秋实大哥与小朋友 线段树 区间更新,单点查询,离散化
  2. VS2015启动拷贝过来的项目无法启动IIS Express
  3. 提示框框架KVNProgress介绍
  4. linux基础命令学习 (十)Vi
  5. linux基础命令学习(五)目录或文件权限
  6. PHP 基础函数(三)数组和变量之间的转换
  7. MYSQL DBA大牛
  8. Unity接入谷歌支付
  9. 深入理解Apache Flink核心技术
  10. OpenCV特征点检测