android是单线程的,在子线程中是不能修改UI线程的任何操作,所以要用一种方式让子线程中的信息返回到主线程中再做修改。这就要让主线程与子线程通信。
那如何让它们之间进行通信呢?我们用Handler这个类。Handler操作的是Message。在主线程中,消息队列是在程序启动时就自动生成的,而子线程要自己手动建立消息队列 ,Looper是用来管理消息队列的。
那么什么才是关键呢?首先,要明白Handler都是在主线程中的,也就是说,Handler类就都在主线程中运行,通俗的说就是“绑定”在主线程中。第二,Handler的触发是通过SendMessage()这个方法驱动的,注意,sendMessage 和 handleMessage这一对,一个负责发一个负责收。是哪个Handler发出的,就由哪个Handler去接收。这样msg 就不会混乱了。第三,开启一个线程唯一的方式就是执行start()方法。而只执行run()方法的,线程还是运行在主线程中。如图:
而我们要的是这样的,如图:
要让主线程与子线程通信,则用Handler 操作Message.如图:
好了看下代码吧,分享下:
MainActivity:
package com.bivin;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends Activity {
private Handler mMainHandler, mChildHandler;
private TextView tv;
private Button b;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
tv = (TextView) findViewById(R.id.tv);
b = (Button) findViewById(R.id.btn);
Log.i("tag",Thread.currentThread().getName());
mMainHandler= new Handler() {
@Override
public void handleMessage(Message msg) {
Log.i("tag",Thread.currentThread().getName());
//Log.i("TAG", "Got an incoming message from the child thread - "
//+ (String) msg.obj);
tv.setText((String) msg.obj);
super.handleMessage(msg);
}
};
newChildThread().start();
b.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (mChildHandler != null) {
Log.i("tag",Thread.currentThread().getName());
Message childmsg = mChildHandler.obtainMessage();
childmsg.obj = mMainHandler.getLooper().getThread()
.getName()
+ " hello!,This is mainactivity";
mChildHandler.sendMessage(childmsg);
Log.i("TAG", "Send a message to the child thread - "
+ (String) childmsg.obj);
}
}
});
}
@Override
protected void onDestroy() {
Log.i("TAG", "Stop looping the child thread's message queue");
mChildHandler.getLooper().quit();
super.onDestroy();
}
private class ChildThread extends Thread {
@Override
public void run() {
this.setName("childthread");
Looper.prepare();
mChildHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
Log.i("TAG",
"Got an incoming message from the main thread - "
+ (String) msg.obj);
try {
sleep(10000);
Message toMain = mMainHandler.obtainMessage();
toMain.obj = "this is"
+ this.getLooper().getThread().getName()
+ ". do you send me" + (String) msg.obj + "?";
mMainHandler.sendMessage(toMain);
Log.i("TAG", "Send a message to the main thread - "
+ (String) toMain.obj);
} catch (InterruptedException e) {
e.printStackTrace();
}
super.handleMessage(msg);
}
};
Log.i("TAG", "Child handler is bound to - "
+ mChildHandler.getLooper().getThread().getName());
Looper.loop();
}
}
}
andriod提供了 Handler 和 Looper
* 来满足线程间的通信。例如一个子线程从网络上下载了一副图片,当它下载完成后会发送消息给主线程,这个消息是通过绑定在主线程的Handler来传递的。
* 在Android
* ,这里的线程分为有消息循环的线程和没有消息循环的线程,有消息循环的线程一般都会有一个Looper,这个是android的新概念。我们的主线程
* (UI线程)就是一个消息循环的线程
* 。针对这种消息循环的机制,我们引入一个新的机制Handler,我们有消息循环,就要往消息循环里面发送相应的消息,自定义消息一般都会有自己对应的处理
* ,消息的发送和清除,把这些都封装在Handler里面,注意Handler只是针对那
* 些有Looper的线程,不管是UI线程还是子线程,只要你有Looper,我就可以往你的消息队列里面添加东西,并做相应的处理。
* 但是这里还有一点,就是只要是关于UI相关的东西,就不能放在子线程中,因为子线程是不能操作UI的,只能进行数据、系统等其他非UI的操作。
*
* 一个Handler的创建它就会被绑定到这个线程的消息队列中,如果是在主线程创建的,那就不需要写代码来创建消息队列了,默认的消息队列会在主线程被创建。
* 但是如果是在子线程的话,就必须在创建Handler之前先初始化线程的消息队列。