对Android稍有了解的都知道Handle机制,然而我学了一段时间后,发现如果不看书,就是自己敲,连一个简单的demo都搞不定。不爽。这个暑假决定Android中几大机制和四大组件可以随意就写出来一些简单或复杂的demo来。
书归正传。
(1)现在想实现一个简单的demo,就是在子线程中更改UI线程,只是单次修改。示例代码如下:
public class MainActivity extends Activity {
private TextView info;
private static int sum = 0;
ChildThread childThread = null;
private Handler mMainHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
info.setText(mMainHandler.getLooper().getThread().getName()
+ "的Handler收到了消息,消息内容是:"
+ msg.obj);
}
};
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.activity_main);
info = (TextView) findViewById(R.id.info);
childThread = new ChildThread();
childThread.setName("childThread");
childThread.start();
}
private class ChildThread extends Thread {
public void run() {
try {
sum++;
sleep(2000);//模拟一个耗时操作,sum是计算结果
} catch (InterruptedException e) {
e.printStackTrace();
}
//这里产生message调用obtainMessage直接从接收消息对象的Hanler的消息池中获得而不是new Message,效率高
Message message = mMainHandler.obtainMessage(0x11, 0, 0, Thread.currentThread().getName() + "发送了" + sum + "给主线程");
message.sendToTarget();//将消息发送给主线程
}
}
}
这一段代码实现的功能非常简单,就是创建了一个子线程来完成耗时计算,然后将结果显示在主界面的TextView里,最后输出结果如图所示:
本程序实现的功能就是在子线程中动态修改UI线程,但是只能更新一次。(2)接下来我们实现一个可以循环动态更新UI线程的demo,使用的不仅仅是Message.sendToTarget(),还有Handler.post(Runnable)方法。
示例代码如下:
public class MainActivity extends Activity {
private TextView info;
private static int sum = 0;
private Handler mMainHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
info.setText(mMainHandler.getLooper().getThread().getName()
+ "的Handler收到了消息,消息内容是:"
+ msg.obj);
System.out.println("Handler属于-----" + mMainHandler.getLooper().getThread().getName()
+ "传递的sum值是:" + msg.obj);
mMainHandler.postDelayed(runnable, 1000);//处理消息1秒后再次执行run()方法,从而实现循环更新TextView
}
};
Runnable runnable = new Runnable() {
@Override
public void run() {
Message message = mMainHandler.obtainMessage(0x11, 0, 0, sum++);
message.sendToTarget();
System.out.println("执行run()方法的线程是---" + Thread.currentThread().getName());
}
};
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.activity_main);
info = (TextView) findViewById(R.id.info);
mMainHandler.postDelayed(runnable, 2000);//第一次启动run()方法延时较长
}
}
这样主线程的handler就会每隔一秒处理run()方法中的发送的消息,根据发送的消息来更新TextView,输出如下:
我们会发现虽然相比第一个demo,实现了动态循环更新,但是执行run()方法的却变成了main线程,这样虽然迁就了Handle机制,但是却阻塞主线程,不是我们要的结果。
(3)所以我们再改改程序功能,就是实现动态循环子线程执行耗时操作,将结果交给main线程Handler,从而实现UI更新。
示例代码如下:
public class MainActivity extends Activity {
private TextView info;
private static int sum = 0;
ChildThread childThread;
private Handler mMainHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
info.setText(mMainHandler.getLooper().getThread().getName()
+ "的Handler收到了消息,消息内容是:"
+ msg.obj);
System.out.println("Handler属于-----" + mMainHandler.getLooper().getThread().getName()
+ "传递的sum值是:" + msg.obj);
}
};
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.activity_main);
info = (TextView) findViewById(R.id.info);
childThread = new ChildThread("childThread");
childThread.start();
}
private class ChildThread extends Thread {//将耗时的操作放在子线程中完成
public ChildThread(String name) {//参数是Runnable和线程名字的构造函数
super(name);
}
public void run() {
for (int i = 0; i < 10; i++) {
Message message = mMainHandler.obtainMessage(0x11, 0, 0, sum++);
message.sendToTarget();
System.out.println("执行run()方法的线程是---" + Thread.currentThread().getName());
try {
sleep(1000);//每次更新停顿一下
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
输出如下:
我们可以看到Handler属于main线程,而执行run()方法的是childThread,并且实现了动态更新。那么,可能有同学会问,为什么不能使用new Thread(Runnable)使得执行run()方法的是子线程??其实这也是可以的,我们可以这样实现:
public class MainActivity extends Activity {
private TextView info;
private static int sum = 0;
ChildThread childThread;
private Handler mMainHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
info.setText(mMainHandler.getLooper().getThread().getName()
+ "的Handler收到了消息,消息内容是:"
+ msg.obj);
System.out.println("Handler属于-----" + mMainHandler.getLooper().getThread().getName()
+ "传递的sum值是:" + msg.obj);
}
};
Runnable runnable = new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
Message message = mMainHandler.obtainMessage(0x11, 0, 0, sum++);
message.sendToTarget();
System.out.println("执行run()方法的线程是---" + Thread.currentThread().getName());
try {
Thread.sleep(1000);//每次更新停顿一下
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.activity_main);
info = (TextView) findViewById(R.id.info);
childThread = new ChildThread(runnable, "childThread");//将定义好操作的Runnable作为参数传给子线程构造函数
childThread.start();
}
private class ChildThread extends Thread {//将耗时的操作放在子线程中完成
public ChildThread(Runnable target, String name) {//参数是Runnable和线程名字的构造函数
super(target, name);
}
}
}
输出如下:
ok~~我们发现输出和上面的demo是没差的~.
总结一下:
1.如果使用Handler来定时修改界面,就可以使用post的方法,但是执行该post方法的只能是Main线程,因为只有Main线程才可以动态修改UI
2.如果想要传数据给UI线程,可以使用sendMessage的方法。将数据传给Main线程的handler。