文章目录
众所周知,Android中更新UI的操作只能在Main Thread(UI Thread)中进行,而耗时的操作要放在子线程中,这是因为UI线程是和用户交互的,必须有较高的响应速度,如果主线程执行一些耗时操作,界面就会卡顿,甚至无法响应。当子线程想更新UI的时候,必然要有机制通知UI线程操作。本文先介绍Android多线程的简单使用,每种方法的详解之后会写总结。
读本篇文章之前需要对java线程有一定的认识,不熟悉的可以查看java线程基础知识总结
Handler + Thread + Message
在主线程中创建Handler对象,并重写handleMessage()方法,负责消息的发送和接收处理,子线程通过调用Handler对象的send或post(post内部也是调用send的方法)方法把消息发送给主线程,Handler接收到消息后,根据消息的种类作出相应的操作。
注:这里可能有人不明白,Handler发送消息,Handler又负责接收消息并处理?是不是多此一举了,其实并不是,这里Handler发送消息和接收消息处理是发生在不同线程中的。比如子线程执行完耗时任务了,想更新UI提醒用户已执行完毕,但子线程不能操作UI,所以他只能发送一个消息给主线程,主线程接收消息并根据消息类型执行指定的操作。
例子
activity_handler_example.xml
<?xml version="1.0" encoding="utf-8"?>
<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"
android:gravity="center"
tools:context=".thread.HandlerExampleActivity">
<Button
android:layout_centerInParent="true"
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="点我加载"/>
<TextView
android:id="@+id/text"
android:layout_below="@+id/button"
android:layout_centerInParent="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="还没开始加载!" />
<ProgressBar
android:layout_below="@+id/text"
android:id="@+id/progress_bar"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:progress="0"
android:max="100"
style="?android:attr/progressBarStyleHorizontal"/>
</RelativeLayout>
HandlerExampleActivity
public class HandlerExampleActivity extends AppCompatActivity {
private Handler mHandler;
private Button mBtnLoad;
private TextView mTvStatus;
private ProgressBar mProgressBar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handler_example);
initView();
setClick();
// 新建Handler对象重写handleMessage方法
mHandler = new Handler() {
@Override
public void handleMessage(@NonNull Message msg) {
switch (msg.what) {
case 1:
mProgressBar.setProgress((int)msg.obj);
mTvStatus.setText("已加载" + (int)msg.obj + "%");
break;
case 2:
mTvStatus.setText("加载完毕");
}
}
};
}
private void initView() {
mBtnLoad = findViewById(R.id.button);
mTvStatus = findViewById(R.id.text);
mProgressBar = findViewById(R.id.progress_bar);
}
private void setClick() {
mBtnLoad.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new Thread(new MyTask()).start();
}
});
}
private class MyTask implements Runnable {
@Override
public void run() {
int progess = 0;
while (progess < 100){
progess++;
Message msg = Message.obtain();
msg.what = 1;
msg.obj = progess;
mHandler.sendMessage(msg);
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Message msg = Message.obtain();
msg.what = 2;
mHandler.sendMessage(msg);
}
}
}
上面的代码很简单,点击按钮开启子线程,子线程不断发送消息给UI线程,UI线程根据消息类型作出不同的UI操作。
需要注意的是,如果在子线程中创建Handler