Android--Handler+Looper+MessageQueue+Thread线程之间的通信
2015-09-13 23:44
746 查看
几个关键概念:(参考网络相关博客)
1、MessageQueue:是一种数据结构,见名知义,就是一个消息队列,存放消息的地方;
每一个线程最多只可以拥有一个MessageQueue数据结构;
一个线程存在MessageQueue才能接收消息;
通常使用一个Looper象对该线程的MessageQueue进行管理;
主线程创建时,会创建一个默认的Looper对象和MessageQueue;
其他非主线程,不会自动创建Looper,要需要的时候,通过调用prepare()函数来实现创建和某个线程关联的Looper,创建了关联的Looper就会自动创建一个MessageQueue。
2、Message:
消息对象,Message Queue中的存放的对象; 一个Message Queue中包含多个Message;
Message实例对象的取得,通常使用Message类里的静态方法obtain(),该方法有多个重载版本可供选择;它的创建并不一定是直接创建一个新的实例,而是先从MessagePool(消息池)中看有没有可用的Message实例,存在则直接取出返回这个实例。如果MessagePool中没有可用的Message实例,则才用给定的参数创建一个Message对象。调用removeMessages()时,将Message从MessageQueue中删除,同时放入到Message Pool中;
除了上面这种方式,也可以通过Handler对象的obtainMessage()获取一个Message实例。
3、Looper:
是MessageQueue的管理者;
每一个MessageQueue都不能脱离Looper而存在,Looper对象的创建是通过prepare函数来实现的;
同时每一个Looper对象和一个线程关联;
通过调用Looper.myLooper()可以获得当前线程的Looper对象;
创建一个Looper对象时,会同时创建一个MessageQueue对象;
除了主线程有默认的Looper,其他线程默认是没有MessageQueue对象的,所以,不能接受Message。如需要接受,自己定义一个Looper对象(通过Looper.prepare()函数),这样该线程就有了自己的Looper对象和MessageQueue数据结构了;
Looper从MessageQueue中取出Message然后,交由Handler的handleMessage进行处理;
处理完成后,调用Message.recycle()将其放入Message Pool中。
4、Handler:
消息的处理者,handler负责将需要传递的信息封装成Message,通过调用handler对象的obtainMessage()来实现;
将消息传递给Looper,这是通过handler对象的sendMessage()来实现的;
继而由Looper将Message放入MessageQueue中;
当Looper对象看到MessageQueue中含有Message,就将其广播出去;该handler对象收到该消息后,调用相应的handler对象的handleMessage()方法对其进行处理。
具体代码如下所示:
主线程(UI线程)
package com.longshun.HandlerLooperHomework; import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.view.View; import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; //1.主线程,向子线程发消息; // 2.子线程接收主线程的消息, // 子线程根据主线程发过来的消息访问网络,得到数据后发送给主线程; public class MainActivity extends Activity { //主线程有默认的Looper private EditText txtUiMsg; private TextView txtRes; private Handler cHandler; private ChildThread childThread; //主线程要得到子线程的消息,先创建一个Handler Handler fHandler = new Handler() { @Override public void handleMessage(Message msg) { int what = msg.what; Object obj = msg.obj; switch (what) { case 0: txtRes.setText(obj.toString());//设置ui内容 break; } } }; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); txtUiMsg = (EditText) findViewById(R.id.txt_ui_msg); txtRes = (TextView) findViewById(R.id.txt_return_msg); //得到子线程任务对象,把主线程传给子线程,因为如果子线程要发消息给主线程,必须要有主线程的handler childThread = new ChildThread(fHandler); //启动子线程,子线程处于等待主线程发消息的状态 Thread thread = new Thread(childThread); thread.start(); } //点击按钮 主线程获取输入框内容 发送给子线程 public void btnSendMsg(View view) { //获取输入框内容,去除前后空格 String UiMsg = String.valueOf(txtUiMsg.getText()).trim().replace(" ", ""); if (UiMsg != null && UiMsg.length() > 0) { //得到与子线程关联的Handler,向子线程发消息 cHandler = childThread.getcHandler(); Message message = cHandler.obtainMessage(1); message.obj = UiMsg; cHandler.sendMessage(message);//发送消息给子线程 Toast.makeText(this, "send success and wait response!", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(this, "请输入你想对小黄鸡说的话!", Toast.LENGTH_SHORT).show(); } } @Override protected void onDestroy() { if (cHandler != null) { cHandler.getLooper().quit();//得到和子线程相关的Looper,并且终止MessageQueue运行; } super.onDestroy(); } }
子线程:
package com.longshun.HandlerLooperHomework; import android.os.Handler; import android.os.Looper; import android.os.Message; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.DefaultHttpClient; import org.json.JSONException; import org.json.JSONObject; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; /** * Created by LongShun on 2015/9/7. * Author:LongShun * Email:1261972397@qq.com */ //子线程任务对象 public class ChildThread implements Runnable { private Handler cHandler; private Handler fHandler; //子线程要向主线程发消息,所以要得到与主线程绑定的fHandler, // 通过这个fHandler才能给主线程发消息。 public ChildThread(Handler fHandler) { this.fHandler = fHandler; } @Override public void run() { Looper.prepare();//!!!!!!!!创建一个和当前线程绑定的Looper,自动创建一个MessageQueue对象, // !!!!!!!!!!!有了MessageQueue对象就能接收Message对象--消息 //和子线程绑定的cHandler,用来处理主线程发过来的消息。 //等待主线程发消息,有消息就处理,没消息就处于等待状态 cHandler = new Handler(){ @Override public void handleMessage(Message msg) { int what = msg.what; switch (what){ case 1: //1得到主线程发过来的消息 String uiMsg = msg.obj.toString(); //2根据消息,联网访问,得到结果 String res = getResponse(uiMsg); //3.通过主线程fHandler ,把响应结果发送给主线程。 Message message = fHandler.obtainMessage(0); message.obj = res; fHandler.sendMessage(message); break; } } }; Looper.loop();//用于不断循环地从MessageQueue中取消息 } //得到与子线程绑定的cHandler public Handler getcHandler(){ return cHandler; } //解析json字符串 public String parserResult(String jsonString){ String result=null; if (jsonString!=null){ try { JSONObject jsonObject = new JSONObject(jsonString); result = jsonObject.getString("res"); } catch (JSONException e) { e.printStackTrace(); } } return result; } //联网获取json结果 private String getResponse(String uiMsg) { //访问网络 String result = null; if (uiMsg != null && uiMsg.length() > 0) { String basePath = "http://www.simsimi.com/requestChat?lc=zh&ft=1.0&req="; String path = basePath + uiMsg; HttpGet get = new HttpGet(path); HttpClient client = new DefaultHttpClient(); InputStream in = null; ByteArrayOutputStream baos = null; try { HttpResponse response = client.execute(get); if (response.getStatusLine().getStatusCode() == 200) { in = response.getEntity().getContent(); baos = new ByteArrayOutputStream(); byte[] b = new byte[1024]; int len; while ((len = in.read(b)) != -1) { baos.write(b, 0, len); } result = parserResult(new String(baos.toByteArray(), "utf-8")); } } catch (IOException e) { e.printStackTrace(); } finally { if (baos != null) { try { baos.close(); } catch (IOException e) { e.printStackTrace(); } } if (in != null) { try { in.close(); } catch (IOException e) { e.printStackTrace(); } } } } return result; } }
main.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="28sp" android:text="我问小黄鸡:" /> <EditText android:id="@+id/txt_ui_msg" android:layout_width="match_parent" android:layout_height="wrap_content" android:textSize="28sp" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center" android:gravity="center" > <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="主线程发送消息给子线程" android:onClick="btnSendMsg" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:orientation="vertical" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="28sp" android:text="小黄鸡回复:" /> <TextView android:id="@+id/txt_return_msg" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="28sp" /> </LinearLayout> </LinearLayout>
相关文章推荐
- UIView 类
- UITableView cell的重复使用
- JSP中 request.getRealPath("/xx/yy") 方法提示已经过时的替代方法
- android开发---ndk-build不自动删除外部库
- easyui datagrid使用
- 将Fresco源码导入到Android Studio,Build失败的解决办法
- 百度UEditor本地化配置 笔记
- hashmap先按照value从大到小排序,value相等时按照key从小到大排序
- 32/64位平台printf uint64的方法
- iOS开发之有趣的UI —— 自定义不等高cell
- Wndows UI设计官方文档
- UI优化技巧:使用layoutopt进行布局优化
- UIPageViewController使用示例
- UI优化技巧:使用ViewStub
- 定义Iterator遍历器取出set中的key,然后通过key的值在map中取出对应value值
- IOS每天15个注意点系列之UI-帧动画与图片浏览
- StringBuffer和StringBuilder
- UVALive 5031 Graph and Queries (Treap)
- CF #296 (Div. 1) B. Clique Problem 贪心(构造)
- Implement Stack using Queues -- leetcode