【从零之四】运用Handler另起线程运行科大讯飞语音识别

开始接触主线程和子线程之后觉得不应该在主线程中实现用户登录、语音识别还有合成这诸多工作,因为人们都说需要联网的工作最好另起新的线程。而且我调用语音包的程序跑起来也很复杂,所以本文就将介绍如何另起新线程运行语音识别。

关于前期准备工作参见前一篇博文

启动新的子线程主要要完成两个功能,一个是在子线程中定义如何运行自己的程序,第二个就是子线程完成了识别工作要及时通知主线程(又叫UI线程)以更新界面。

我的OutputActivity

public class OutputActivity extends Activity {
	private static final int ASK_USER_INPUT = 1;
	// Tip
	private Toast mToast;
	//语义理解结果显示
	private EditText mResultText;
	ClawnThread CoreThread = null;
	
	// Handler object
	private Handler MainHandler=new Handler(){
		public void handleMessage(Message msg){
			switch(msg.what){
			case ASK_USER_INPUT:
				mResultText.append(msg.obj.toString());
				//showSpeechUnderstanderNoPop();
				Log.e("haha","called");
				break;
			}
		}
	};
	class ClawnThread extends Thread{
		public void run(){
			//Init the message looper queue
			Looper.prepare();
			
			//User login
			SpeechUser.getUser().login(MyOutput.getAppContext(), null, null
					, "appid=" + getString(R.string.app_id), listener);
			DMCore.DialogTaskOnBeginSession();
			Log.d("ThreadId",""+Thread.currentThread().getId());
			DMCore.pDMCore.Execute(MainHandler);
			
			// 启动子线程消息循环队列
			Looper.loop();
		}
	}
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_output);
		
		//语义理解结果设置
		mResultText = (EditText) findViewById(R.id.txt_result);
		mResultText.setText(null);
		//findViewById(R.id.personal_layout).setVisibility(View.VISIBLE);	
		
		
		Log.d("ThreadId",""+Thread.currentThread().getId());
		CoreThread = new ClawnThread();
		CoreThread.start();
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.output, menu);
		return true;
	}
	
	

	
	/**
	 * 用户登录回调监听器.
	 */
	private SpeechListener listener = new SpeechListener()
	{

		@Override
		public void onData(byte[] arg0) {
		}

		@Override
		public void onCompleted(SpeechError error) {
			if(error != null) {
				Toast.makeText(OutputActivity.this, getString(R.string.text_login_fail)
						, Toast.LENGTH_SHORT).show();
				
			}			
		}
		@Override
		public void onEvent(int arg0, Bundle arg1) {
		}		
	};

	private void showTip(String str)
	{
		if(!TextUtils.isEmpty(str))
		{
			mToast.setText(str);
			mToast.show();
		}
	}
}

在这个Activity中定义了一个private Handler,里边定义了handleMessage方法,其中定义收到子线程传来的信息作出相应的反应。这个handler是和UI线程绑定在一起的,必须要传递到子线程中,然后子线程用这个handler.sendMessage方法,就直接将message传递给主线程了,所以传递这个handler很重要。

另外自己定义的ClawnThread继承了Thread类,重写run方法,这里要特别注意,因为主线程的Looper队列是不需要另外声明,但是子线程则需要单独初始化循环队列。然后就是登陆,登陆的参数稍加修改,用的是MyOutput的getContext方法获取上下文对象(代码见前一篇博文),然后就是实现自己写的初始化、执行方法。在Execute中传递了handler参数。

在OnCreate中先打印线程id,然后创建新线程然后运行。同样可以在子线程中打印线程id,可以看出真的启动了一个新的线程!

在另外的调用语音识别程序的类中,创建两个private对象,一个Message用来存储要传递的信息,一个String JsonString用来保存识别的结果。然后在识别回调接口里定义完成识别后要传递的信息

/**
	 * 语义理解回调监听器
	 */
	SpeechUnderstanderListener understanderListener = new SpeechUnderstanderListener()
	{
		@Override
		public void onBeginOfSpeech() {
			//showTip("开始说话");
		}

		@Override
		public void onError(SpeechError error) {
			//showTip(error.getPlainDescription(true));
		}

		@Override
		public void onEndOfSpeech() {
			//showTip("结束说话");
		}

		@Override
		public void onEvent(int eventType, int arg1, int arg2, String msg) {
			
		}

		@Override
		public void onResult(UnderstanderResult result) {
			message = new Message();
			message.what=1;
			JsonResult = result.getResultString();
			message.obj=(String)JsonResult;
			
		}

		@Override
		public void onVolumeChanged(int volume) {
			//showTip("当前正在说话,音量值为:" + volume);
			
		}
		
	};
这是传递主线程handler过来的函数,定义在自己的类中,在这个函数里边调用识别函数。
public void WaitForEvent(Handler mhMainHandler) {

		if (qpieEventQueue.isEmpty()) {
			// retrieve the current thread id
			//DWORD dwThreadId = GetCurrentThreadId();
			// call speech understand method
			JsonResult = "";
			showSpeechUnderstanderNoPop();
			Log.d(INPUTMANAGER_STREAM,JsonResult);
			// send a message to the galaxy interface to wait for input
			mhMainHandler.sendMessage(message);
			
			// log that we started waiting for an input
			Log.d(INPUTMANAGER_STREAM, "Waiting for interaction event ...");
这样当完成识别后主屏幕就会I显示识别结果出来。

你可能感兴趣的:(Android)