一、使用Handler来更新UI
Handler是Android提供用于更新UI的一套消息处理机制。
主要作用有两个:
- 在新启动的线程中发送消息
- 在主线程中获取并处理消息
//1.实例化 Handler
//2.在子线程中发送空消息
//3.Handler对象接受消息,并处理
private Handler handler = new Handler() {
//只要Handler发了消息,必然会触发该方法,并且传入一个Message对象
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
if (msg.what == 1) {
textView.setText("received msg succeed !");
}
}
};
//子线程发送空消息给主线程的Handler处理
private void sendEmptyMessage() {
//模拟在线程
new Thread() {
@Override
public void run() {
//发送空消息给HandlerMessage
//这里相当于Message对象中的.what == 1;
handler.sendEmptyMessage(1);
}
}.start();
}
运行结果:
二、使用Message对象传数据给Handler
Message是在线程之间传递的消息,它可以在内部携带少量的信息,用于在不同线程之间交换数据。
常用属性:
- what属性
- arg1属性
- obj属性
由子线程传递信息给主线程处理:
private Handler handler = new Handler() {
//只要Handler发了消息,必然会触发该方法,并且传入一个Message对象
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
if (msg.what == 1) {
textView.setText("received msg succeed !");
} else if (msg.what == 2) {
int i = ((Random)msg.obj).nextInt();
Toast.makeText(MainActivity.this, "Random.nextInt() = " + i,
Toast.LENGTH_SHORT).show();
}
}
};
//子线程发送空消息给主线程的Handler处理
private void sendMessage() {
new Thread() {
@Override
public void run() {
//what:用于区分handler发送消息的不同线程来源
//arg1,arg2:如果子线程需要想主线程传递整型数据,则可用这些参数
//obj:Object
Message msg = new Message();
msg.what = 2;
msg.arg1 = 1234;
msg.arg2 = 2333;
msg.obj = new Random();
handler.sendMessage(msg);
//handler.sendMessageDelayed(msg, 2000);
}
}.start();
}
三、Looper的使用
Looper是每个线程中的MessageQueue的管家,调用Looper的loop()方法后,就会进入到一个无限循环当中,然后每当MesssageQueue中存在一条消息,Looper就会将这条消息取出,并将它传递到Handler的handleMessage()方法中。每个线程只有一个Looper对象。主线程默认有一个Looper。
MessageQueue就是消息队列的意思,它只要用于存放所有通过Handler发送过来的消息。这部分消息会一直存放于消息队列当中,等待被处理。
由主线程传递信息给子线程处理:
Handler handler2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
testLooperThread();
handler2.sendEmptyMessage(2);
}
private void testLooperThread() {
new Thread() {
@Override
public void run() {
//开启Looper
Looper.prepare();
handler2 = new Handler() {
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
Toast.makeText(MainActivity.this,
"主线程传来的message.what:" + msg.what,
Toast.LENGTH_SHORT).show();
}
};
//Looper循环,相当于产生了一个while(true){...}
Looper.loop();
}
}.start();
}
一个线程只有一个Message Queue,Message通过MessageQueue.IdleHandler关联到该线程的Looper上,通过Looper.looper()来处理消息分发到该handler回调。
Looper、Message Queue、Handler的关系:
四、post()、postDelayed()、postAtTime() 方法的使用
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
new Thread(){
@Override
public void run() {
//runOnUiThread的运行机制:判断当前线程是不是主线程
//如果是:则直接执行Runnable对象的run方法
//如果不是:则由handler调用post方法
runOnUiThread(new Runnable() {
@Override
public void run() {
//refresh ui page
}
});
//在post方法中,我们可以处理一切和视图相关的操作
handler.post(new Runnable() {
@Override
public void run() {
//refresh ui page
}
});
//延时3000毫秒运行post
handler.postDelayed(new Runnable() {
@Override
public void run() {
//refresh ui page
}
}, 3000);
//当前系统时间+3000毫秒运行post
handler.postAtTime(new Runnable() {
@Override
public void run() {
//refresh ui page
}
}, SystemClock.uptimeMillis() + 3000);
}
}.start();
}
});
五、使用handler实现简易计时器
timer.java
public class TimerActivity extends AppCompatActivity {
private TextView title, time, txt;
private ImageView btn;
private boolean flag;
private int i, min, sec;
private String str;
private Handler handler = new Handler();
private Runnable runnable = new Runnable() {
@Override
public void run() {
min = i / 60;
sec = i % 60;
// 00:00
str = (min < 10 ? "0" + min : "" + min) + ":" +
(sec < 10 ? "0" + sec : "" + sec);
time.setText(str);
i++;
//递归
handler.postDelayed(runnable, 1000);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_timer);
title = findViewById(R.id.title);
time = findViewById(R.id.time);
txt = findViewById(R.id.txt);
btn = findViewById(R.id.btn);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(flag == false) {
flag = true;
title.setText("计时中");
btn.setImageResource(R.mipmap.stop);
txt.setText("");
i = 1;
new Thread() {
@Override
public void run() {
handler.postDelayed(runnable, 1000);
}
}.start();
} else {
flag = false;
title.setText("计时器");
txt.setText("所用时间:" + str);
time.setText("00:00");
btn.setImageResource(R.mipmap.start);
//移除回调
handler.removeCallbacks(runnable);
}
}
});
}
}
layout.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:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".TimerActivity"
android:gravity="center_horizontal"
android:background="#2C1F55">
<LinearLayout
android:layout_width="300dp"
android:layout_height="300dp"
android:background="@drawable/circle"
android:orientation="vertical"
android:layout_marginTop="40dp"
android:gravity="center_horizontal">
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="计时器"
android:textColor="#ffffff"
android:textSize="50sp"
android:layout_marginTop="60dp"/>
<TextView
android:id="@+id/time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="00:00"
android:textColor="#ffffff"
android:textSize="50sp"
android:layout_marginTop="30dp"/>
</LinearLayout>
<ImageView
android:id="@+id/btn"
android:layout_width="100dp"
android:layout_height="100dp"
android:src="@mipmap/start"
android:layout_marginTop="45dp"/>
<TextView
android:id="@+id/txt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#ffffff"
android:textSize="45sp"
android:layout_marginTop="45dp"/>
</LinearLayout>
drawable circle.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<corners android:radius="150dp"/>
<stroke android:width="3dp" android:color="#ffffff"/>
</shape>
参考文章:
图解Handler机制