直接在UI线程中开启子线程来更新TextView显示的内容,运行程序我们会发现,如下错 误:android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.翻译过来就是:只有创建这个控件的线程才能去更新该控件的内容。
所有的UI线程要去负责View的创建并且维护它,例如更新冒个TextView的显示,都必须在主线程中去做,我们不能直接在UI线程中去创建子线程,要利用消息机制:handler,如下就是handler的简单工作原理图:

Android的消息机制(一)
1.Looper:(相当于隧道) 一个线程可以产生一个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 对象。
每一个线程里可含有一个Looper 对象以及一个MessageQueue 数据结构。在你的应用程序里,可以定义Handler 的子类别来接收Looper所送出的消息。
public class Activity1 extends Activity implements OnClickListener{
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 );
Looper looper = Looper.myLooper (); // 取得当前线程里的looper
MyHandler mHandler = new MyHandler(looper); // 构造一个handler 使之可与looper 通信
//buton 等组件可以由mHandler 将消息传给looper 后, 再放入messageQueue 中, 同时mHandler 也可以接受来自looper 消息
String msgStr = " 主线程不同组件通信: 消息来自button" ;
Message m = mHandler.obtainMessage(1, 1, 1, msgStr); // 构造要传递的消息
mHandler.sendMessage(m); // 发送消息: 系统会自动调用handleMessage 方法来处理消息
private class MyHandler extends Handler{
public MyHandler(Looper looper){
public void handleMessage(Message msg) { // 处理消息
text .setText(msg. obj .toString());
此程序启动时,当前线程( 即主线程, main thread) 已诞生了一个Looper 对象,并且有了一个MessageQueue 数据结构。
调用Looper 类别的静态myLooper() 函数,以取得目前线程里的Looper 对象.
mHandler = new MyHandler (looper);
Message m = mHandler.obtainMessage(1, 1, 1, obj);
就透过mHandler 对象而将消息m 传给Looper ,然后放入MessageQueue 里。
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 所属的对象可以处理。
public class Activity2 extends Activity implements OnClickListener{
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 );
private class MyHandler extends Handler{
public MyHandler(Looper looper){
public void handleMessage(Message msg) { // 处理消息
text .setText(msg. obj .toString());
private class MyThread extends Thread{
Looper curLooper = Looper.myLooper ();
Looper mainLooper = Looper.getMainLooper ();
mHandler = new MyHandler(mainLooper);
mHandler = new MyHandler(curLooper);
Message m = mHandler .obtainMessage(1, 1, 1, msg);
mHandler = new MyHandler (mainLooper);
用Android线程间通信的Message机制
Android中Handler的使用方法——在子线程中更新界面
1. 用Message更新界面与Runnable更新界面类似,只是需要修改几个地方。
○ 实现自己的Handler,对消息进行处理
private class MyHandler extends Handler
{
本文详细介绍了Android中UI更新的正确方式与Handler的工作机制,包括Handler如何在主线程与子线程间传递消息,以及如何利用Handler实现跨线程更新UI。

739

被折叠的 条评论
为什么被折叠?



