版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qingjianduoyun/article/details/80623421
一、几个概念
1.UI线程、主线程、ActivityThread
当每个应用启动时都会启动一个主进程,接着这个主进程会开启一个主线程(主线程可以叫做UI线程,主要负责处理界面上UI相关的消息的分发)。一个Android 程序默认情况下也只有一个进程Process,但可以有许多个线程Thread。
2.线程不安全
具体参考博文:android 那些事—主线程是线程不安全的
3.消息循环机制
具体参见博文:Android消息循环机制
4.Handler、Looper、Message、MessageQueue
具体参考上面的博客Android消息循环机制
,四者之间的关系如下图所示:
二、Handler的使用
1.在主线程中使用Handler
新建一个名为Handler的项目,MainActivity.java
代码如下:
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//创建Handler
final Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//处理消息
Log.d(TAG, "handleMessage: " + msg.what);
}
};
//在主线程中发送一条空消息
handler.sendEmptyMessage(1001);
}
}
输出结果如下图所示:
2.可能会发生的问题
2.1 子线程无法更新UI
实现效果为:点击按钮,改变TextView中的内容
为此需修改activity_main.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=".MainActivity">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView" />
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button" />
</LinearLayout>
MainActivity.java
代码修改如下:
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private TextView textView;
private Button button;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
//创建Handler
final Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//处理消息
Log.d(TAG, "handleMessage: " + msg.what);
}
};
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new Thread(new Runnable() {
@Override
public void run() {
textView.setText("hello");
}
}).start();
}
});
}
private void initView() {
textView = findViewById(R.id.textView);
button = findViewById(R.id.button);
}
}
运行程序,点击按钮,程序崩溃,打开日志打印窗口,查看错误如下图所示:
这说明,我们新创建的子线程无法更改UI界面,那么该怎么办呢?这时我们就要告诉主线程(即将消息传给主线程),让主线程来更新UI。
2.2 告诉主线程,让主线程来操纵UI
MainActivity.java
代码修改如下:
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private TextView textView;
private Button button;
@Override
protected void onCreate(Bundle savedInstanceState) {
/**
* UI线程
*/
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
//创建Handler
final Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
/**
* 接收子线程发来的消息,并处理消息
*/
Log.d(TAG, "handleMessage: " + msg.what);
if (msg.what == 1001) {
textView.setText("hello,handler!");
}
}
};
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
/**
* 子线程:有可能做大量耗时操作
*/
new Thread(new Runnable() {
@Override
public void run() {
/**
* 通知UI更新
*/
//调用此方法会触发主线程(UI线程)中Handler对象中的handleMessage方法,并将消息传递给主线程
handler.sendEmptyMessage(1001);
}
}).start();
}
});
}
private void initView() {
textView = findViewById(R.id.textView);
button = findViewById(R.id.button);
}
}
效果图如下所示:
3.Handler发送消息的常见方法
3.1 message的几个参数
如下代码所示:
Message message =Message.obtain();
message.what = 1002;
message.arg1 = 1003;
message.arg2 = 1004;
message.obj = MainActivity.this;
handler.sendMessage(message);
这里不建议使用
Message message=new Message();
,我们来看看源码:
Message有obtain方法,在Message对象有的情况下直接使用就行,没有的话会自动为我们创建。
3.2 Handler发送消息的常见方法
代码如下:
//定时发送
handler.sendMessageAtTime(message, SystemClock.uptimeMillis() + 6000);
//延时发送
handler.sendMessageDelayed(message, 3000);
Runnable runnable = new Runnable() {
@Override
public void run() {
}
};
handler.post(runnable);
handler.postDelayed(runnable, 2000);
三、总结
官方API文档给出的Handler主要有两方面的功能:
1. 安排将来要执行的消息和可运行的程序
2. 排队在不同于你自己的线程上执行的动作
说白了就是进行定时任务,在子线程汇总执行一些耗时操作。
四、敲代码时Get到的技巧
更多见博客:Android Studio快速打印Log