这是困扰我很久的一个问题。现在做一下总结。
出于性能优化角度考虑,Android UI操作并不是线程安全的,意味着如果有多个线程并发操作UI组件可能导致线程安全问题。因而,只允许UI线程修改Activity里的UI组件。当程序第一次启动时,Android会同时启动一条Main Thread(主线程),Main Thread主要负责处理与UI相关的事件,比如按键触屏及屏幕绘图,并将相关事件分发到对应的组件进行处理。因此Main Thread称为UI线程。
Android 的消息传递机制是另一种形式的“事件处理”,这种传递机制主要为了解决Android 应用多线程的问题——新启动的线程无法动态改变界面组件的属性值。实际开发中,需让新启动的线程周期性改变界面组件的属性值,需要借助Handle消息传递机制来实现。
————————————————————————————
Handle,作用有二:在新启动的线程里发送消息;在主线程中获取处理消息。为了使主线程能适时处理新线程所发动的消息,显然只能通过回调的方式——重写Handle类中处理消息的办法,当启动新线程发送消息时,消息会发生到与之关联的MessageQuene,Handle会不断从MessageQueue获取并处理消息——这将导致Handle类中处理消息方法回调。
Message:Handle接受处理的消息;
Looper:每个线程只有一个。它的loop方法负责读取 MessageQueue中的消息,读到后将消息给Handle处理;
MessageQueue:消息队列,采用先进先出得方式管理Message。程序创建Looper对象时会在其构造器中创建MessageQueue对象。
在线程中调用Handle步骤:调用Looper的prepare(),为当前线程创建Looper对象,构造器与此同时创建配套MessageQueue;创建Handle子类实例,重写handleMessage();调用Looper的loop方法启动。
package ustb.sk.iotintelligence.activity;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.JsonObjectRequest;
import com.android.volley.toolbox.Volley;
import com.iflytek.cloud.RecognizerResult;
import com.iflytek.cloud.SpeechConstant;
import com.iflytek.cloud.SpeechError;
import com.iflytek.cloud.SpeechUtility;
import com.iflytek.cloud.ui.RecognizerDialog;
import com.iflytek.cloud.ui.RecognizerDialogListener;
import org.json.JSONException;
import org.json.JSONObject;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import ustb.sk.iotintelligence.R;
import ustb.sk.iotintelligence.speech.util.JsonParser;
public class ChatTogether extends Activity {//回答没有显示在listview中
private Button btChat;
private ListView lvChat;
String TAG = ChatTogether.class.getSimpleName();
private RequestQueue mRequestQueue;
private String baseUrl="http://apis.baidu.com/turing/turing/turing";
private HashMap<String,String> mIatResults = new LinkedHashMap<String, String>();// 用HashMap存储说话人听写结果
List<Map<String,String>> lists = new ArrayList<Map<String, String>>();//创建一个List集合,集合元素是Map
Map<String,String> list = new HashMap<String, String>();//list由time与detail组成
final SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy年mm月dd日HH:mm:ss");
Date date = new Date(System.currentTimeMillis());//时间
final Handler handler=new Handler()
{
@Override
public void handleMessage(Message msg) {
switch (msg.what)
{
case 0x123:
Log.v("vvvvv", "0123");
String input = msg.obj.toString();//将说话内容放入参数中
Log.v("vvvvv","45");
String requestUrl = baseUrl + "?key=879a6cb3afb84dbf4fc84a1df2ab7319&info=" + URLEncoder.encode(input) + "&userid=eb2edb736";
// Log.v("test", "request url is" + requestUrl);
// String requestUrl="key=879a6cb3afb84dbf4fc84a1df2ab7319&info=%E6%9F%A5%E5%A4%A9%E6%B0%94%E2%80%9C%E5%8C%97%E4%BA%AC%E4%BB%8A%E5%A4%A9%E5%A4%A9%E6%B0%94%E2%80%9D&userid=eb2edb736";
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.GET, requestUrl, null, new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject jsonObject) {
try {
Log.v("test", "get response success");
Log.v("test", "response is" + jsonObject.get("text").toString());
list.put("time", simpleDateFormat.format(date));
list.put("detail", jsonObject.get("text").toString());
lists.add(list);
Log.v("timewhat2",list.get("time"));
Log.v("detailwhat2", list.get("detail"));
} catch (Exception exception) {
Log.v("test", "json exception" + exception.toString());
}
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError volleyError) {
Log.v("test", "get response fail");
}
}) {
@Override
public Map<String, String> getHeaders() {
HashMap<String, String> headers = new HashMap<String, String>();
headers.put("apikey", "37d6b6cc3972f5392e35cf9e391b8b5e");//37d6b6cc3972f5392e35cf9e391b8b5e
return headers;
}
};
mRequestQueue.add(jsonObjectRequest);
SimpleAdapter simpleAdapter = new SimpleAdapter(ChatTogether.this,lists,R.layout.notelist_item,new String[] { "time" , "detail" },new int[] {R.id.time, R.id.detail} );
ListView listView = (ListView)findViewById(R.id.lvChat);
listView.setAdapter(simpleAdapter);
break;
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SpeechUtility.createUtility(getApplicationContext(), SpeechConstant.APPID + "=55b20041");
setContentView(R.layout.activity_chat_together);
mRequestQueue = Volley.newRequestQueue(getApplication());
btChat = (Button) findViewById(R.id.btChat);
btChat.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {//点击说话
RecognizerDialog recognizerDialog = new RecognizerDialog(ChatTogether.this, null);//创建对象,本地听写的话第二个参数传InitListener
recognizerDialog.setParameter(SpeechConstant.DOMAIN, "iat");//设置听写参数,详见《科大讯飞MSC API手册(Android)》SpeechConstant类
recognizerDialog.setParameter(SpeechConstant.LANGUAGE, "zh_cn");
recognizerDialog.setParameter(SpeechConstant.ACCENT, "mandarin ");
recognizerDialog.setListener(recognizerDialogListener);//开始听写
recognizerDialog.show();//asset下的动画
Log.v("test", "click button");
}
});
}
public RecognizerDialogListener recognizerDialogListener = new RecognizerDialogListener() {//听写监听器
@Override
public void onResult(RecognizerResult recognizerResult, boolean isLast) {
/* 听写结果回调接口(返回Json格式结果,用户可参见附录12.1);
一般情况下会通过onResults接口多次返回结果,完整的识别内容是多次结果的累加;
关于解析Json的代码可参见MscDemo中JsonParser类;
isLast等于true时会话结束。*/
Log.v("jsonresult", recognizerResult.getResultString());
Log.v("this is dialog result", JsonParser.parseIatResult(recognizerResult.getResultString()));
Message msg=new Message();
msg.what=0x123;
msg.obj=jsonChange(recognizerResult);
handler.sendMessage(msg);
list.put("time", simpleDateFormat.format(date));
list.put("detail", msg.obj.toString());
Log.v("timewhat1", list.get("time"));
Log.v("detailwhat1", list.get("detail"));
}
@Override
public void onError(SpeechError speechError) {
Log.v(TAG,"this is error");
Log.v(TAG, speechError.toString());
}
};
public String jsonChange(RecognizerResult results) {//将json转换为汉字--我还不太懂
String text = JsonParser.parseIatResult(results.getResultString());
String sn = null;
// 读取json结果中的sn字段
try {
JSONObject resultJson = new JSONObject(results.getResultString());
sn = resultJson.optString("sn");
} catch (JSONException e) {
e.printStackTrace();
}
mIatResults.put(sn, text);
StringBuffer resultBuffer = new StringBuffer();
for (String key : mIatResults.keySet()) {
resultBuffer.append(mIatResults.get(key));
}
Log.v("finalresult", resultBuffer.toString());
return resultBuffer.toString();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_chat_together, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}