首页 » Android » Android 在子线程中更新UI

Android 在子线程中更新UI

原文 http://blog.csdn.net/Tongsiyuaichidami/article/details/79236397

2018-02-03 02:00:50阅读(564)

和许多其他的GUI库一样,Android的UI也是线程不安全的,也就是说,如果想要更新应用程序里的UI元素,则必须在主线程中进行,否则就会出现异常。

还是通过一个小例子来看一下,activity_main.xml中的代码,如下:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    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="wrap_content"
        android:layout_height="wrap_content"
        android:text="Change Text"
        android:textAllCaps="false"/>
    
    <TextView
        android:id="@+id/text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello world"
        android:textAllCaps="false"
        android:textSize="20sp"
        app:layout_constraintTop_toBottomOf="@id/change_text"/>
</android.support.constraint.ConstraintLayout>
布局文件中定义了两个控件,TextView用于显示一个Hello world字符串,Button用于改变TextView中显示的内容,我们希望在点击Button后可以把TextView中显示的字符串改成Nice to meet you。

MainActivity.java中的代码,如下:

public class MainActivity extends AppCompatActivity implements View.OnClickListener{
    private TextView text;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        text = findViewById(R.id.text);
        Button changeText = findViewById(R.id.change_text);
        changeText.setOnClickListener(this);
    }
    @Override
    public void onClick(View view) {
        switch (view.getId()){
            case R.id.change_text:
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        text.setText("Nice to meet you");
                    }
                }).start();
                break;
                default:
                    break;
        }
    }
}
可以看到,我们在Change Text按钮的点击事件里面开启了一个子线程,然后在子线程中调用TextView的setText()方法将显示的字符串改成Nice to meet you,代码的逻辑非常简单,只不过我们是在子线程中更新UI的,现在运行一下程序,并点击Change Text按钮,你会发现程序崩溃了,如图:

Android 在子线程中更新UI

然后观察logcat中的错误日志,可以看出是由于在子线程中更新UI所导致的,如图:

Android 在子线程中更新UI

由此证实了Android确实是不允许在子线程中进行UI操作的,但是有些时候,我们必须在子线程里去执行一些耗时任务,然后根据任务的执行结果来更新相应的UI控件,对于这种情况,Android提供了一套异步消息处理机制,完美的解决了在子线程中进行UI操作的问题,修改MainActivity.java中的代码,如下:

public class MainActivity extends AppCompatActivity implements View.OnClickListener{
    public static final int UPDATE_TEXT = 1;
    private TextView text;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        text = findViewById(R.id.text);
        Button changeText = findViewById(R.id.change_text);
        changeText.setOnClickListener(this);
    }
    
    private Handler handler = new Handler(){
        
        public void handleMessage(Message msg){
            switch (msg.what){
                case UPDATE_TEXT:
                    //在这里可以进行UI操作
                    text.setText("Nice to meet you");
                    break;
                    default:
                        break;
            }
        }
    };
    @Override
    public void onClick(View view) {
        switch (view.getId()){
            case R.id.change_text:
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        Message message = new Message();
                        message.what = UPDATE_TEXT;
                        handler.sendMessage(message);//将Message对象发送出去
                    }
                }).start();
                break;
                default:
                    break;
        }
    }
}
这里我们先是定义了一个整型常量UPDATE_TEXT,用于表示更新TextView这个动作,然后新增一个Handler对象,并重写父类的handlerMessage()方法,在这里对具体的Message进行处理,如果发现Message的what字段的值等于UPDATE_TEXT,就将TextView显示的内容改成Nice to meet you。

下面再来看一下Change Text按钮的点击事件中的代码,可以看到,这次我们并没有在子线程里直接进行UI操作,而是创建了一个Message(android.os.Message)对象,并将它的what字段的值指定为UPDATE_TEXT,然后调用Handler的sendMessage()方法将这条Message发送出去,很快,Handler就会收到这条Message,并在handlerMessage()方法中对它进行处理,注意此时handlerMessage()方法中的代码就是在主线程当中运行的了,所以我们可以放心的在这里进行UI操作,接下来对Message携带的what字段的值进行判断,如果等于UPDATE_TEXT,就将TextView显示的内容改成Nice to meet you。

现在重新运行程序,可以看到屏幕上显示着Hello world,然后点击一下Change Text按钮,显示的内容就被替换成Nice to meet you,如图:

Android 在子线程中更新UI

这样就实现了在子线程中更新UI的问题。

最新发布

CentOS专题

关于本站

5ibc.net旗下博客站精品博文小部分原创、大部分从互联网收集整理。尊重作者版权、传播精品博文,让更多编程爱好者知晓!

小提示

按 Ctrl+D 键,
把本文加入收藏夹