android系统中的多线程(一): 关于在android中启动线程以及线程间的交互
在android中,一个应用开始运行的时候,系统将创建一个线程名为main,同时也称作UIthread.同一进程中的所有组件都在main线程中创建,并且接收用户的操作.如果阻塞该线程超过5s将弹出ANR对话框。同时android的UI工具包是非线程安全的。
因而有两点必须注意:
1.不要阻塞UIthread
2.不要在其它线程中操作UI
也因此推导出两个知识块:
1.对于需要长时间执行的任务需要启动workthread,在android中启动workthread的方法是什么?
2.在workthread如何对UI进行更新和设置
Java传统方法Thread/Runnable继承Thread实现run
创建Runnable,实现run,实例作为参数创建Thread
使用Handler进行线程间交互
每一个Handler的实例都与唯一的线程以及该线程的messagequeue相关联。
默认情况下handler与创建它的线程相关联,但是也可以在构造函数中传入Looper实例,以绑定到其它线程。
Handler的作用就是将message或runnable对象发送到与之相关联的messagequeue中,并且从queue中获取他们进行处理。
这就起到了将数据在线程中传递的目的,实现了线程间的交互。
o对于Handler启动runnable在下面的关于定时和周期性执行中进行详细介绍
o关联于main线程的handler,实现了帮助workthread更新UI的目的,在关于在workthread中对UI进行更新和设置中详细介绍
o为了使handler关联于workthread而非main线程,需要在构造函数时给定Looper实例
Looper用于执行一个线程的message循环。通过它handler可以关联上相应的thread及其messagequeue。默认情况下,thread是没有Looper对象的,需要自己在thread中添加该对象,并调用其prepare()和loop()方法。不考虑同步的情况下简单实现一个有Loop的thread.
其中有2点值得注意:
1.Looper在调用prepare()之后才指向当前thread,之前是指向mainthread的
2.handler必须在thread调用start方法(运行run)之后才能获取looper,否则为空,因为prepare需要在run方法中调用
o为了方面使用带有Looper的Thread,android实现了HandlerThread
LoopThreadthread1;
publicWifiSettings(){
mFilter=newIntentFilter();
mFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
mFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
mFilter.addAction(WifiManager.NETWORK_IDS_CHANGED_ACTION);
mFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION);
mFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
mFilter.addAction(WifiManager.RSSI_CHANGED_ACTION);
mReceiver=newBroadcastReceiver(){
@Override
publicvoidonReceive(Contextcontext,Intentintent){
handleEvent(intent);
}
};
thread1=newLoopThread("loopThread");
thread1.start();
mScanner=newScanner(thread1.MyLooper);
}
classLoopThreadextendsThread{
publicLooperMyLooper;
publicLoopThread(Stringname){
super(name);
MyLooper=Looper.myLooper();
Log.w(TAG,"inthreadinit:loop"
+MyLooper.getThread().getName());//main
}
publicvoidrun(){
Log.w(TAG,"inthread:"+Thread.currentThread().getName());//main
Looper.prepare();
MyLooper=Looper.myLooper();
Log.w(TAG,"inthreadrun:loop"+MyLooper.getThread().getName());//name
Looper.loop();
}
}