一个handler对象中有对应的线程队列和消息队列,如下示例线程队列:
布局文件(很简单,就两个按钮,一个TextView):
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
android:orientation="vertical"
tools:context="com.austin.handlerstudy.MainActivity">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/btn_start"
android:text="开始" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/btn_stop"
android:text="停止" />
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/tv_info"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:text="第一条信息" />
</LinearLayout>
</ScrollView>
</LinearLayout>
public class MainActivity extends AppCompatActivity {
TextView tvInfo;
Button btnStart,btnStop;
Handler handler = new Handler();
MyTask task = new MyTask();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tvInfo = findViewById(R.id.tv_info);
btnStart = findViewById(R.id.btn_start);
btnStop = findViewById(R.id.btn_stop);
btnStart.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
handler.post(task);
}
});
btnStop.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
handler.removeCallbacks(task);
}
});
}
class MyTask extends Thread{
@Override
public void run() {
tvInfo.append("\n received msg!");
handler.postDelayed(task,3000);
}
}
}
运行时点击start,就会每隔三秒打印一次msg,点击stop后停止接收和打印。这就是一个简单的线程队列应用的例子,但注意,此时调用的run方法,其实没有真正启动给一个子线程,相当于手动调用了一次run方法而已,也就是说所有消息的创建和处理都在主线程。
GIF.gif
下面演示如何在主线程发消息由子线程处理:
public class Handler2Act extends AppCompatActivity {
private final String TAG = Handler2Act.class.getSimpleName();
MyHandler mHandler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.content_handler2);
Log.e(TAG,"MainActivity所在线程名:"+Thread.currentThread().getName()+" 线程Id"+Thread.currentThread().getId());
//HandlerThread实现了使用Looper来处理消息队列的功能
HandlerThread handlerThread = new HandlerThread("my handler thread");
handlerThread.start();
//getLooper()一定要写在线程start方法之后
mHandler = new MyHandler(handlerThread.getLooper());
Message msg = mHandler.obtainMessage();
msg.arg1 = 5;
msg.sendToTarget();//发送消息到创建该消息的handler的looper所在线程上
}
class MyHandler extends Handler{
MyHandler(Looper looper){
super(looper);
}
@Override
public void handleMessage(Message msg) {
Log.e(TAG,"MyHandler所在线程名字:"+Thread.currentThread().getName()+" 线程id:"+Thread.currentThread().getId());
}
}
}
temp.jpg
可以发现handlerMessage方法运行在了子线程。
HandlerThread优点:
- HandlerThread 内部实现了一个Handler轮循器,可以使用它而非主线程中自带的轮循器从而避免主线程任务过多和压力过大导致的流畅度不佳。
- 可以处理多个任务,开启一个线程起到多个线程的作用。因为其内部Handler.handleMessage的执行,一定在它的Looper的线程中。(Looper共享)
举例:HandlerThread与Camera能够Looper共享。
所以Handler机制(消息机制)不仅仅是能够实现主子线程通讯,还能实现资源共享(Looper共享)。
网友评论