您的位置:首页 > 产品设计 > UI/UE

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>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: