当前位置: 首页 > article >正文

Android在子线程中更新UI

Android在子线程中更新UI

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

眼见为实,让我们通过一个具体的例子来验证一下吧。新建一个AndroidThreadTest项目,然后修改activity_main.xml中的代码,如下所示:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<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>

布局文件中定义了两个控件,TextView用于在屏幕的正中央显示一个Hello world字符串,Button用于改变TextView中显示的内容,我们希望在点击Button后可以把TextView中显示的字符串改成Nice to meet you。

接下来修改MainActivity中的代码,如下所示:

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 = (TextView) findViewById(R.id.text);
Button changeText = (Button) findViewById(R.id.change_text);
changeText.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.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按钮,你会发现程序果然崩溃了。然后观察logcat中的错误日志,可以看出是由于在子线程中更新UI所导致的,如图所示:

在这里插入图片描述

由此证实了Android确实是不允许在子线程中进行UI操作的。但是有些时候,我们必须在子线程里去执行一些耗时任务,然后根据任务的执行结果来更新相应的UI控件,这该如何是好呢?

对于这种情况,Android提供了一套异步消息处理机制,完美地解决了在子线程中进行UI操作的问题。本小节中我们先来学习一下异步消息处理的使用方法,下一小节中再去分析它的原理。

修改MainActivity中的代码,如下所示:

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
public static final int UPDATE_TEXT = 1;
private TextView text;
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 v) {
switch (v.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对象,并重写父类的handleMessage()方法,在这里对具体的Message进行处理。如果发现Message的what字段的值等于UPDATE_TEXT,就将TextView显示的内容改成Niceto meet you。

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

可以放心地在这里进行UI操作。接下来对Message携带的what字段的值进行判断,如果等于UPDATE_TEXT,就将TextView显示的内容改成Nice to meet you。

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

在这里插入图片描述

这样你就已经掌握了Android异步消息处理的基本用法,使用这种机制就可以出色地解决掉在子线程中更新UI的问题。不过恐怕你对它的工作原理还不是很清楚,下一节我们就来分析一下Android异步消息处理机制到底是如何工作的。

如果对你有帮助,就一键三连呗(点赞+收藏+关注),我会持续更新更多干货~~


http://www.kler.cn/a/289086.html

相关文章:

  • 学习日志010--python异常处理机制与简单文件操作
  • 〔 MySQL 〕数据类型
  • WLAN消失或者已连接但是访问不了互联网
  • 如何使用ffmpeg命令行进行录屏
  • 【JVM】关于JVM的内部原理你到底了解多少(八股文面经知识点)
  • 用vscode编写verilog时,如何有信号定义提示、信号定义跳转(go to definition)、模块跳转这些功能
  • Java导出图片到excel
  • 【算法】贪心算法解析:基本概念、策略证明与代码例题演示
  • ARM汇编指令
  • Pandas 2-读取文件
  • CSRF 概念及防护机制
  • 3D幻想空间:Scratch中探索虚拟世界的奥秘
  • 【量化分析】Python、JavaScript(Node.js)、Java、C#和Ruby五种主流语言的实例代码给大家演示一下如何获取股票实时交易数据
  • 深入理解MySQL慢查询优化(2) -- SQL的执行流程
  • OCI编程高级篇(十八) OCI连接池概念
  • 如何打造一个成功的直播矩阵
  • 【科研新人必看】什么是期刊等级,SCI、核心期刊、省刊
  • qt6 socket 不使用代理 socket error: The proxy type is invalid for this operation
  • 8.29 C++
  • 常用Pandas操作(笔记整理)
  • 前端学习笔记-Web APIs篇-02
  • 基于机器学习的工业制造缺陷分析预测系统
  • 运动多线激光三维重建
  • 解决bug: RuntimeError: Address already in use,一个linux下pytorch多卡训练tcp端口占用的bug
  • SpringCloudGateway网关技术
  • 笔记整理—uboot番外(2)find_cmd函数