Handler的理解及android.view.ViewRootImpl$CalledFromWrongThreadException錯誤處理
在前面的幾篇文章中,不管是AsyncTAsk方式,亦或是new一個Runable,都沒有涉及UI介面的更新(),今天在進行註冊反饋註冊資訊的時候,就發生了ViewRootImpl$CalledFromWrongThreadException異常,究其原因是因為android中的view和和控制元件不是執行緒安全的。
為此android已入了Handler訊息傳遞機制,來實現在新建的執行緒中操作UI介面。
資訊處理類(Handler)允許傳送和處理Message或Runable物件到其所線上程的MessageQuene中。Handler主要有以下作用:
(1)將Message或Runable應用Post() 或 sendMessage() 方法傳送到MessageQuene中,在傳送是可以指定延遲時間,傳送時間及要攜帶的Bundle資料,當MessageQuene迴圈到該Message時,呼叫相應的Handler物件的HandlerMessage()方法對其進行處理。
(2)在子執行緒與主執行緒進行通訊,也就是在工作執行緒中與UI執行緒進行通訊。
補充:在android中,一個執行緒對應一個Looper物件,而一個Looper物件又對應一個MessageQuene(訊息佇列,用於存放Message訊息,MessageQuene封裝在Looper中),在主執行緒中,系統會自動為主執行緒建立Looper物件,並開啟訊息迴圈,但在非主執行緒建立Handler物件(不加Looper.prepare()和Looper.Loop()方法來初始化一個Looper物件),會報Can't
create handler inside thread that has not called Looper.prepare()
從飛天開放平臺獲取註冊資料的簡單程式碼:
package com.example.alitest; import java.io.IOException; import java.util.HashMap; import java.util.Map; import ECSConnecter.SigninConnecter; import XMLReader.SigninData; 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.view.View.OnClickListener; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; public class MainActivity extends Activity implements Runnable { private Button button; private Handler handler; private TextView name; private TextView pwd; private EditText etName; private EditText etPwd; @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); button.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Thread t = new Thread(MainActivity.this); //建立新執行緒 t.start(); //開啟執行緒 handler = new Handler() { //這個handler傳送的Message會被傳遞給主執行緒的MessageQueue。 public void handleMessage(Message msg) { //回撥 if (msg.what == 1) { name.setText(msg.getData().getString("result")); pwd.setText(msg.getData().getString("ID")); } super.handleMessage(msg); } }; } }); } @Override public void run() { while (!Thread.currentThread().isInterrupted()) { /* * 連線註冊程序 */ Map<String, String> map = new HashMap<String, String>(); map.put("name", etName.getText().toString()); map.put("password", etPwd.getText().toString()); SigninConnecter signconn = new SigninConnecter(map); try { signconn.getXML(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } signconn.readXML(); SigninData data = signconn.getData(); Message m = handler.obtainMessage(); //獲取一個Message Bundle bundle = new Bundle(); //獲取Bundle物件 m.what = 1; //設定訊息標識 bundle.putString("result", data.getResult()); bundle.putString("ID", data.getId()); //儲存資料 m.setData(bundle); //將Bundle物件儲存到Message中 handler.sendMessage(m); //傳送訊息 } } /* * 初始化控制元件 */ private void initView() { name = (TextView) findViewById(R.id.textView1); pwd = (TextView) findViewById(R.id.textView2); etName = (EditText) findViewById(R.id.etName); etPwd = (EditText) findViewById(R.id.etPwd); button = (Button) findViewById(R.id.button); } }
像所有的android通訊方法一樣,別忘了開啟internet的許可權~