Android中的Handler, Looper, MessageQueue和Thread

来源:互联网 发布:win8 装 ubuntu 编辑:程序博客网 时间:2024/05/29 14:13
直接在UI线程中开启子线程来更新TextView显示的内容,运行程序我们会发现,错 误android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.翻译过来就是:只有创建这个控件的线程才能去更新该控件的内容。

要想修改UI都必须在主线程中去做,我们不能直接在UI线程中去创建子线程,要利用消息机制:handler.


1)Looper: 一个线程可以产生一个Looper对象,由它来管理此线程里的MessageQueue(消息队列)。 Looper类用来管理特定线程内对象之间的消息交换(Message Exchange)。
2)Handler: 你可以构造Handler对象来与Looper沟通,以便push新消息到MessageQueue里;或者接收Looper从Message Queue取出)所送来的消息。
3) Message Queue(消息队列):用来存放线程放入的消息。 
4)线程:UIthread 通常就是main thread,而Android启动程序时会替它建立一个MessageQueue。
 在Android开发中,为了UI线程能及时响应需要避免在其中执行耗时操作,以防止界面假死甚至ANR。我们一般把耗时操作如下载,查询放在一个单独的线程中。这之后再将结果更新到UI界面。android平台在非UI线程中更新界面大致有以下几种方式
 Handler的处理过程运行在创建Handler的线程里


 一个Looper对应一个MessageQueue
 一个线程对应一个Looper
 一个Looper可以对应多个Handler

 不确定当前线程时,更新UI时尽量调用post方法

<span style="color:#333333;">public class MainActivity extends Activity {private Button button;private Handler handler;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);handler = new TimerHandler();WorkerThread wt = new WorkerThread();wt.start();}class WorkerThread extends Thread{@Overridepublic void run(){while(true){try {Thread.sleep(1000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}//创建消息Message msg = handler.obtainMessage();msg.arg1 = 10;msg.arg2 = 20;msg.obj = "zhangsan";//发送消息handler.sendMessage(msg);}}}class TimerHandler extends Handler{@Overridepublic void handleMessage(Message msg) {//接收消息,此消息可以使对象int i = msg.arg1;int j = msg.arg2;String s = (String)msg.obj;Log.d("Handler", "收到消息:arg1:" + i +",arg2:" + j + ",s:" + s);}}}</span>
一些耗时间的操作放在线程中去,通过Handler传递消息

public class MainActivity extends Activity {private TextView textView;private Button button;private Handler handler;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);handler = new NetworkHandler();textView = (TextView)findViewById(R.id.textViewId);button = (Button)findViewById(R.id.buttonId);button.setOnClickListener(new ButtonListener());}class ButtonListener implements OnClickListener{@Overridepublic void onClick(View v) {NetworkThread nt = new NetworkThread();nt.start();}}class NetworkThread extends Thread{@Overridepublic void run(){String url = "http://192.168.105.129:8081/data.html";Log.d("Handler02", "准备访问网路");//得到从网上下载的数据String data = getStringFromNetwork(url);//textView.setText(data);该行代码引起错误的原因是,不能够在Worker Thread当中修改控件的值//把数据放到handler中要用handler.obtainMessage();Message msg = handler.obtainMessage();msg.obj = data;handler.sendMessage(msg);}}class NetworkHandler extends Handler{@Overridepublic void handleMessage(Message msg){//得到handler中数据把它赋给dataString data = (String)msg.obj;textView.setText(data);}}//新建一个类,类型是String urlpublic String getStringFromNetwork(String url){String result = "";        //建个Http客户端访问网络下载数据HttpClient httpClient = new DefaultHttpClient();HttpGet httpGet = new HttpGet(url);try {HttpResponse response = httpClient.execute(httpGet);if(response.getStatusLine().getStatusCode() == 200){HttpEntity entity = response.getEntity();//连接已建立数据在entity中从entity中开始读数据BufferedReader reader = new BufferedReader(new InputStreamReader(entity.getContent()));result = reader.readLine();Log.d("Handler02", "访问网络的结果是" + result);return result;}} catch (Exception e) {e.printStackTrace();}return result;}}

Looper的用法

class WorkerThread extends Thread{@Overridepublic void run(){//生成Looper对象,该对象与当前线程对象组成了对应关系Looper.prepare();//生成Handler对象,并将其与刚刚生成Looper对象建立对应关系handler = new Handler(){@Overridepublic void handleMessage(Message msg){Log.d("Handler", "收到来自主线程的消息");}};Looper.loop();}}

子线程中修改UI的方法

class WorkThread extends Thread{int i = 0 ;@Overridepublic void run() {while(true){try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}i++;handler.post(new Runnable() {@Overridepublic void run() {textView.setText(i + "");}});}



0 0
原创粉丝点击