我们在开发应用程序的时候,考虑到线程安全的问题,子线程是不能直接修改UI的,也就是说Android的UI也是不安全的线程,如果想要更新UI元素,则必须在主线程里执行,否则就会出现异常。

首次来看一个在子线程修改UI的例子:

1、新建一个TestDemo项目,然后修改MainActivity.xml中的代码,代码如下:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >
<Button 
    android:id="@+id/btn_click_me"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="click me"
    />
<TextView 
    android:id="@+id/tv_show_info"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="dd"
    />
    
</LinearLayout>

在布局文件MainActivity中添加了两个控件,一个Button和一个TextView.我希望当我点击Button时能够把TextView的Text属性值修改成我所希望的值。

下面来看一下MainActivity中的代码:

public class MainActivity extends ActionBarActivity implements OnClickListener {
    private static final String TAG = "MainActivity";
    private Button btn_click_me;
    private TextView tv_show_info;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        btn_click_me = (Button) findViewById(R.id.btn_click_me);
        tv_show_info = (TextView) findViewById(R.id.tv_show_info);
        btn_click_me.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {

        switch (v.getId()) {
        case R.id.btn_click_me: {
            log("----------------click------------------------");
            new Thread(new Runnable() {

                @Override
                public void run() {
                    tv_show_info.setText("hello world");
                }
            }).start();
        }
            break;

        default:
            break;
        }
    }

    public void log(String info) {
        Log.d(TAG, info);
    }

}

这段代码很简单,在btn_click_me按钮的点击事件里面开启了一个子线程,然后在子线程中调用TextView的setText的方法将显示的字符串改成hello world。代码逻辑非常简单,不过这是在子线程中更新UI的。现在运行一下这段代码,你会发现程序崩溃了。查看LogCat中的错误日志,你可以看到造成崩溃的原因是由于在子线程中更新UI所导致的。异常信息如下:

android子线程更新ui的方法 android子线程更新ui后果_Android

以上可以证实了Android确实是不允许在子线程中对UI元素进行修改。但是Android为我们提供了一套异步消息处理机制,能够完美的解决在子线程中操作UI.现在我们来修改一下MainActivity中的代码。代码如下:

public class MainActivity extends ActionBarActivity implements OnClickListener {
    private static final String TAG = "MainActivity";
    private Button btn_click_me;
    private TextView tv_show_info;
    private static final int UPDATA_TEXT=1;
    private Handler handler=new Handler(){
        public void handleMessage(Message msg) {
            switch (msg.what) {
            case UPDATA_TEXT:
                tv_show_info.setText(msg.obj.toString());
                break;

            }
        };
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        btn_click_me = (Button) findViewById(R.id.btn_click_me);
        tv_show_info = (TextView) findViewById(R.id.tv_show_info);
        btn_click_me.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {

        switch (v.getId()) {
        case R.id.btn_click_me: {
            log("----------------click------------------------");
            Message msg=new Message();
            msg.what=UPDATA_TEXT;
            msg.obj="hello world";
            handler.sendMessage(msg);
        }
            break;

        default:
            break;
        }
    }

    public void log(String info) {
        Log.d(TAG, info);
    }

}

在修改后的代码里面新增了一个静态常量UPDATA_TEXT,用来表示更新textView的动作,然后又定义了一个Handler对象,并重写了父类的handlerMessage方法,在重写的方法中进行了对textView的操作。在重写的handlerMessage里面你会发现当msg.what的值等于UPDATA_TEXT时,就会将TextView的值改我msg.obj传递过去的值hello world.