我们在说HandlerThread前先看下在子线程如何使用Handler,如果你了解过主线程中的Handler,就很容易知道该怎么用,如果没有,建议你去看这篇博客:https://blog.csdn.net/android_seven/article/details/88838832
好了,这里我默认你读过前面的文章,现在就撸下代码吧,犹如在主线程一样,我们也要先去获取一个当前线程的looper对象,然后去创建一个Handler对象去接收发送消息,在开启loop.looper()轮询消息,注意这个方法要写在最后额,因为是个死循环,其他代码写在这之后就无法执行了。那就贴一下在子线程中使用Handler的代码吧。
private String TAG="HandlerActivity";
Button btn1,btn2;
Handler mThreadHandler1;
Handler mThreadHandler2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handler);
btn1=findViewById(R.id.button1);
btn2=findViewById(R.id.button2);
initHandler();
}
private void initHandler() {
new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();
mThreadHandler1=new Handler(Looper.myLooper()){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.d(TAG, "handleMessage1: "+msg.what);
}
};
try {
sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// mThreadHandler2.sendEmptyMessage(1);
Looper.loop();
}
}).start();
看,这样就能在子线程中接收消息了,那么子线程和子线程是否可以传递消息呢,答案当然是可以的,同样我们在开启另外一个线程 互发消息,这里我让线程休眠几秒是为了防止对象为空喔,请大家看代码:
private String TAG="HandlerActivity";
Button btn1,btn2;
Handler mThreadHandler1;
Handler mThreadHandler2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handler);
btn1=findViewById(R.id.button1);
btn2=findViewById(R.id.button2);
initHandler();
}
private void initHandler() {
new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();
mThreadHandler1=new Handler(Looper.myLooper()){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.d(TAG, "handleMessage1: "+msg.what);
}
};
try {
sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
mThreadHandler2.sendEmptyMessage(1);
Looper.loop();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();
mThreadHandler2=new Handler(Looper.myLooper()){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.d(TAG, "handleMessage2: "+msg.what);
}
};
try {
sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
mThreadHandler1.sendEmptyMessage(2);
Looper.loop();
}
}).start();
}
通过打印我们看见这样我们的两个子线程就可以互发消息了,不过这样写是不是很麻烦,还得在每个子线程中去创建loop对象然后在去循环消息,谷歌也觉得,于是乎,HandlerThread就诞生了,我们去看HandlerThread的源码,这里我贴出来:
/*
* Copyright (C) 2006 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.os;
import android.annotation.NonNull;
import android.annotation.Nullable;
/**
* Handy class for starting a new thread that has a looper. The looper can then be
* used to create handler classes. Note that start() must still be called.
*/
public class HandlerThread extends Thread {
int mPriority;
int mTid = -1;
Looper mLooper;
private @Nullable Handler mHandler;
public HandlerThread(String name) {
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
/**
* Constructs a HandlerThread.
* @param name
* @param priority The priority to run the thread at. The value supplied must be from
* {@link android.os.Process} and not from java.lang.Thread.
*/
public HandlerThread(String name, int priority) {
super(name);
mPriority = priority;
}
/**
* Call back method that can be explicitly overridden if needed to execute some
* setup before Looper loops.
*/
protected void onLooperPrepared() {
}
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
/**
* This method returns the Looper associated with this thread. If this thread not been started
* or for any reason isAlive() returns false, this method will return null. If this thread
* has been started, this method will block until the looper has been initialized.
* @return The looper.
*/
public Looper getLooper() {
if (!isAlive()) {
return null;
}
// If the thread has been started, wait until the looper has been created.
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
/**
* @return a shared {@link Handler} associated with this thread
* @hide
*/
@NonNull
public Handler getThreadHandler() {
if (mHandler == null) {
mHandler = new Handler(getLooper());
}
return mHandler;
}
/**
* Quits the handler thread's looper.
* <p>
* Causes the handler thread's looper to terminate without processing any
* more messages in the message queue.
* </p><p>
* Any attempt to post messages to the queue after the looper is asked to quit will fail.
* For example, the {@link Handler#sendMessage(Message)} method will return false.
* </p><p class="note">
* Using this method may be unsafe because some messages may not be delivered
* before the looper terminates. Consider using {@link #quitSafely} instead to ensure
* that all pending work is completed in an orderly manner.
* </p>
*
* @return True if the looper looper has been asked to quit or false if the
* thread had not yet started running.
*
* @see #quitSafely
*/
public boolean quit() {
Looper looper = getLooper();
if (looper != null) {
looper.quit();
return true;
}
return false;
}
/**
* Quits the handler thread's looper safely.
* <p>
* Causes the handler thread's looper to terminate as soon as all remaining messages
* in the message queue that are already due to be delivered have been handled.
* Pending delayed messages with due times in the future will not be delivered.
* </p><p>
* Any attempt to post messages to the queue after the looper is asked to quit will fail.
* For example, the {@link Handler#sendMessage(Message)} method will return false.
* </p><p>
* If the thread has not been started or has finished (that is if
* {@link #getLooper} returns null), then false is returned.
* Otherwise the looper is asked to quit and true is returned.
* </p>
*
* @return True if the looper looper has been asked to quit or false if the
* thread had not yet started running.
*/
public boolean quitSafely() {
Looper looper = getLooper();
if (looper != null) {
looper.quitSafely();
return true;
}
return false;
}
/**
* Returns the identifier of this thread. See Process.myTid().
*/
public int getThreadId() {
return mTid;
}
}
我们发现,原来HandlerThread原来就是个线程啊,只不过它的run方法里面去创建了一个looper对象,并且开起了消息循环,这里我们要注意一下getLooper()里面的notifyAll()和wait()额,这个是为了防止我们在调用getLooper()时对象为空,所以让主线程挂起了,知道run方法执行获取了looper对象才唤醒了主线程。好了HandlerThread的源码就是这样简单,那我们该怎么用呢?我们来贴下代码:
private String TAG="HandlerActivity";
Button btn1,btn2;
Handler mWorkHandler1;
Handler mWorkHandler2;
HandlerThread mHandlerThread1;
HandlerThread mHandlerThread2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handler);
btn1=findViewById(R.id.button1);
btn2=findViewById(R.id.button2);
btn1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mWorkHandler1.sendEmptyMessage(2);
}
});
initHandlerThread();
}
private void initHandlerThread() {
mHandlerThread1=new HandlerThread("workThread1");
mHandlerThread1.start();
mWorkHandler1=new Handler(mHandlerThread1.getLooper()){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.d(TAG, "handleMessage1: "+msg.what);
// if(msg.what==1){
// mWorkHandler2.sendEmptyMessage(2);
// }
}
};
mHandlerThread2=new HandlerThread("workThread2");
mHandlerThread2.start();
mWorkHandler2=new Handler(mHandlerThread1.getLooper()){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.d(TAG, "handleMessage2: "+msg.what);
if(msg.what==2){
mWorkHandler1.sendEmptyMessage(1);
}
}
};
}
其实也就三步走,第一步我们去new一个HandlerThread,第二步:我们去start一下,这样Looper对象就被创建并开始循环了,第三步:去创建一个Handler对象,并把HandlerThread里面的looper对象去创建Handler,这样的话Handler就运行在子线程了,三步搞定,我们在Button1设置点击事件,发送消息给mWorkHandler1,当1收到后在1的线程中发送给2,通过打印我们看见,完美执行了,
至此我们就说完了HandlerThread,简单吧,当然前提你得了解Handler机制。
至于内存泄漏的问题建议看两篇博客:https://www.cnblogs.com/baiqiantao/p/7425120.html
http://www.zhimengzhe.com/Androidkaifa/444651.html
关键点1.用静态内部类和弱引用代替内部类,因为非静态内部类会持有外部引用
2.Activity退出时移除所有消息
本文如有不正之处,烦请大神指正,谢谢!