標籤:
1,事實上安卓的UI線程是不安全的,所以如果想要更新應用程式的UI元素,必須在主線程中更新
先看一個例子
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.example.androidthreadtest.MainActivity" > <Button android:id="@+id/change_text" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Change Text" /> <TextView android:id="@+id/text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:text="Hello world" android:textSize="20sp" /></RelativeLayout>
介面布局圖
我們想要的效果是點擊上面的按鈕,然後改變下面的文本操作
所以假定我們有如下的代碼
public class MainActivity extends Activity implements OnClickListener {private static final int UPDATE_TEXT=1;private TextView text;private Button changeText; @Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);text = (TextView) findViewById(R.id.text);changeText = (Button) findViewById(R.id.change_text);changeText.setOnClickListener(this);}@Overridepublic void onClick(View v) {// TODO Auto-generated method stubswitch (v.getId()) {case R.id.change_text:new Thread(new Runnable() {@Overridepublic void run() {// TODO Auto-generated method stub text.setText("內容都已經改變咯");}}).start();break;default:break;}}}
想改變介面的中間的內容,但是發現會出現錯誤CalledFromWrongThreadException:Only the original thread created a view hierarchy can touch its views子線程中更新出現的錯誤安卓不允許在子線程中進行UI操作
2,所以解決上面UI子線程問題的辦法就是非同步訊息處理機制
安卓中的非同步訊息處理主要由四個部分組成:Message,Handler,MessageQueue和Looper.1,MessageMessage是線上程間進行傳遞訊息的。定義一個包含描述性和任意資料對象的訊息是可以被傳給Handler的。
大致有Int類型的what agr1 arg2欄位和一個Object對象的obj欄位
2,HandlerHandler就是處理者的意思。主要用於發送和處理訊息發送訊息一般是用到方法sendMessage(),而發出的訊息進過一些列的輾轉處理最終會傳遞到Handler的handleMessage()方法中
3,MessageQueueMessageQueue是訊息佇列,主要是用於存放所有通過handler發送的訊息,這部分訊息會一直存在訊息佇列中等待被處理。每個線程中只會有一個MessageQueue對象
4,LooperLooper是每個線程中的MessageQueue的管家,調用Looper的loop()方法後就會進入到一個無限迴圈中每當大仙MessageQueue中有訊息,就會將其取出,然後傳遞到Handler的handlerMessage()方法中。每個線程也只會有一個Looper對象
則非同步訊息的處理流程:首先一般主線程中建立一個Handler對象,同時重寫handleMessage()方法當子線程需要進行UI操作的時候,就會建立一個Message對象,並通過Hnadler將這條訊息發送出去之後訊息會被添加到MessageQueue隊列中等待被處理,而Looper則會一直嘗試從MessageQueue中取出待處理的訊息,最後分發回Handler的handlerMessage()方法中由於Handler是在主線程中建立的,所以此時handleMessage()方法中的代碼也會在主線程中運行,於是就可以正常的進行UI操作了
所以改進後的代碼如下:
public class MainActivity extends Activity implements OnClickListener {private static final int UPDATE_TEXT=1;private TextView text;private Button changeText; private Handler handler=new Handler(){public void handleMessage(Message msg){switch (msg.what) {case UPDATE_TEXT://在此處進行UI操作text.setText("內容在這裡進行改變");break;default:break;}}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);text = (TextView) findViewById(R.id.text);changeText = (Button) findViewById(R.id.change_text);changeText.setOnClickListener(this);}@Overridepublic void onClick(View v) {// TODO Auto-generated method stubswitch (v.getId()) {case R.id.change_text:new Thread(new Runnable() {@Overridepublic void run() {// TODO Auto-generated method stub//不能在這裡直接改變/*text.setText("內容都已經改變咯");*/Message message=new Message();message.what=UPDATE_TEXT;//將message對象發送出去handler.sendMessage(message);}}).start();break;default:break;}}}
點擊後會出現想要的結果
安卓UI線程與非同步訊息處理機制