安卓的子线程中不允许直接更新UI,否则会报错。一般常见的子线程中更新UI的几种方法如下:
1)runOnUiThread
2)Handler与Message
3)View.post(Runnable )
4)AsyncTask
下面写个demo测试下几种情况,在布局文件中定义5个按钮和一个文本控件,5个按钮中的前4个用于演示前面提到的可以进行更新UI的四种情况,第5个按钮测试在子线程中直接更新UI报错的问题,文本控件用来测试被更新的控件,不同的更新显示不同的内容。
先看下界面的效果图(不知道能否正常显示):
第5个按钮测试崩溃情况输出错误如下:
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
下面展示下测试代码:
布局文件activity_update_ui.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_update_ui"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.mobile.cdtx.blog.main.activity.UpdateUIActivity">
<Button
android:id="@+id/id_btn_one"
android:textAllCaps="false"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="runOnUiThread"/>
<Button
android:id="@+id/id_btn_two"
android:textAllCaps="false"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Handler与Message"/>
<Button
android:id="@+id/id_btn_three"
android:textAllCaps="false"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="View.post(Runnable )"/>
<Button
android:id="@+id/id_btn_four"
android:textAllCaps="false"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="AsyncTask"/>
<Button
android:id="@+id/id_btn_five"
android:textAllCaps="false"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Crash"/>
<TextView
android:id="@+id/id_tv_text"
android:textAllCaps="false"
android:layout_marginTop="10dp"
android:background="#F32567"
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="wait for update"/>
</LinearLayout>
主界面测试代码:
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import com.mobile.cdtx.blog.R;
public class UpdateUIActivity extends AppCompatActivity implements View.OnClickListener{
private static final String TAG = "UpdateUIActivity";
private static int MESSAGE_WHAT = 1;
Button btnOne,btnTwo,btnThree,btnFour,btnFive;
TextView tvText;
private Handler handler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_update_ui);
initView();//初始化控件
handler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if(msg.what == MESSAGE_WHAT){
tvText.setText("Handler and Message");
}
}
};
}
//初始化控件
private void initView(){
btnOne = (Button)findViewById(R.id.id_btn_one);
btnTwo = (Button)findViewById(R.id.id_btn_two);
btnThree = (Button)findViewById(R.id.id_btn_three);
btnFour = (Button)findViewById(R.id.id_btn_four);
btnFive = (Button)findViewById(R.id.id_btn_five);
tvText = (TextView)findViewById(R.id.id_tv_text);
btnOne.setOnClickListener(this);
btnTwo.setOnClickListener(this);
btnThree.setOnClickListener(this);
btnFour.setOnClickListener(this);
btnFive.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch(v.getId()){
case R.id.id_btn_one://runOnUiThread
testOne();
break;
case R.id.id_btn_two://Handler与Message
textTwo();
break;
case R.id.id_btn_three://View.post(Runnable )
textThree();
break;
case R.id.id_btn_four://AsyncTask
testFour();
break;
case R.id.id_btn_five://Crash
textFive();
break;
default:
break;
}
}
//runOnUiThread
private void testOne(){
new Thread(new Runnable() {
@Override
public void run() {
runOnUiThread(new Runnable() {
@Override
public void run() {
tvText.setText("runOnUiThread");
}
});
}
}).start();
}
//Handler与Message
private void textTwo(){
new Thread(new Runnable() {
@Override
public void run() {
Message message = new Message();
message.what = MESSAGE_WHAT;
handler.sendMessage(message);
}
}).start();
}
//View.post(Runnable )
private void textThree(){
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
btnThree.post(new Runnable() {
@Override
public void run() {
tvText.setText("View.post(Runnable )");
}
});
}
}).start();
}
//AsyncTask
private void testFour(){
MyAsyncTask myAsyncTask = new MyAsyncTask(tvText);
myAsyncTask.execute();
}
//Crash-主要用于演示如果在子线程中如果直接更新UI会崩溃
private void textFive(){
new Thread(new Runnable() {
@Override
public void run() {
tvText.setText("Crash");
}
}).start();
}
//自定义AsyncTask类
class MyAsyncTask extends AsyncTask<Void,Integer,String>{
TextView textView;
public MyAsyncTask(TextView textView){
this.textView = textView;
}
@Override
protected void onPreExecute() {
super.onPreExecute();
textView.setText("开始准备执行doInBackground");
}
@Override
protected String doInBackground(Void... params) {
try{
Log.i(TAG, "doInBackground: 这里可以做耗时运算");
Thread.sleep(2000);
}catch (Exception e){
e.printStackTrace();
}
return "AsyncTask";
}
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
textView.setText(s);
}
}
}