Android系统中,执行耗时操作都需要另外开启子线程来执行,执行完线程以后自动销毁。为了避免重复的创建和销毁线程,避免过多的消耗性能,可以采用:
- 1.使用线程池
- 2.使用
HandlerThread
1.HandleThread 使用场景,以及如何使用
使用场景
HandlerThread是Google帮我们封装好的,可以用来执行多个耗时操作,而不需要多次创建销毁线程,里面是采用Handler
和Looper
实现的。
使用方式
- 创建HandlerThread的实例对象
//构造方法的参数表示的是线程的名称
HandlerThread mHandlerThread = new HandlerThread("wyw");
- 启动创建的实例对象
mHandlerThread.start()
- 将实例对象和handler绑定在一起。(必须按照这三步进行)
mThreadHandler = new Handler(mHandlerThread.getLooper()) {
@Override
public void handleMessage(@NonNull Message msg) {
checkForUpdate();
if (isUpdate) {
mThreadHandler.sendEmptyMessage(MSG_UPDATE_INFO);
}
}
};
完整使用实例代码:
public class MyActivity extends AppCompatActivity {
private static final int MSG_UPDATE_INFO = 0x100;
private HandlerThread mHandlerThread;
private Handler mThreadHandler;
Handler mMainHandler = new Handler();
private TextView tv;
private boolean isUpdate = true;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//创建handlerThread实例
mHandlerThread = new HandlerThread("wyw");
//启动handlerThread实例
mHandlerThread.start();
//handlerThread 绑定handler
mThreadHandler = new Handler(mHandlerThread.getLooper()) {
@Override
public void handleMessage(@NonNull Message msg) {
checkForUpdate();
if (isUpdate) {
mThreadHandler.sendEmptyMessage(MSG_UPDATE_INFO);
}
}
};
}
private void checkForUpdate() {
try {
//模拟耗时
Thread.sleep(1200);
mMainHandler.post(new Runnable() {
@Override
public void run() {
String result = "实时更新中, 当前股票行情: <fontcolor='red'>%d</font>";
result = String.format(result, (int) Math.random() * 5000 + 1000);
tv.setText(result);
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
protected void onResume() {
super.onResume();
isUpdate = true;
mThreadHandler.sendEmptyMessage(MSG_UPDATE_INFO);
}
@Override
protected void onPause() {
super.onPause();
isUpdate = false;
mThreadHandler.sendEmptyMessage(MSG_UPDATE_INFO);
}
@Override
protected void onDestroy() {
super.onDestroy();
mHandlerThread.quit();
mMainHandler.removeCallbacksAndMessages(null);
}
}
2.HandlerThread源码解析
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;
}
public HandlerThread(String name, int priority) {
super(name);
mPriority = priority;
}
protected void onLooperPrepared() {
}
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
//持有锁机制来获得当前线程的Looper对象
synchronized (this) {
mLooper = Looper.myLooper();
//发出通知,当前线程已经创建mLooper对象成功,这里主要是通知getLooper方法中的waiter
notifyAll();
}
//线程的优先级设置
Process.setThreadPriority(mPriority);
//方法空实现,可以重写这个方法,处理线程开启之前的准备工作
onLooperPrepared();
Looper.loop();
mTid = -1;
}
public Looper getLooper() {
if (!isAlive()) {
return null;
}
//直到线程创建完Looper之后才能获取Looper对象,Looper未创建成功阻塞
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
@NonNull
public Handler getThreadHandler() {
if (mHandler == null) {
mHandler = new Handler(getLooper());
}
return mHandler;
}
public boolean quit() {
Looper looper = getLooper();
if (looper != null) {
looper.quit();
return true;
}
return false;
}
public boolean quitSafely() {
Looper looper = getLooper();
if (looper != null) {
looper.quitSafely();
return true;
}
return false;
}
public int getThreadId() {
return mTid;
}
}
-
HandlerThread
构造方法,一个参数和两个参数的,name代表当前线程的名称,priority代表线程的优先级。 - 前面强调在使用
HandlerThread
的时候必须先调用start(),接着才可以将HandlerThread
和Handler
绑定在一起。因为在run()方法中,我们才初始化looper,而我们调用HandlerThread的start()方法的时候,线程会交给虚拟机调度,由虚拟机自动调用run()方法。 - run()方法中使用锁机制和notifyAll()的原因,可以在getLooper()方法中找到。
在获取mLooper对象的时候存在一个同步的问题,只有当当线程成功创建并且Looper对象也创建成功之后才能获取mLooper的值。这里等待waite()和run()中的notifAll()共同实现同步。 -
quit()和quitSafe()的区别:
通过源码追踪,可以发现,实际这个两个方法最终调用的是MessageQueue.quit(boolean safe)
。MessageQueue.quit方法源码:
可以看出,这个方法根据传入的参数safe来判断执行removeAllFutureMessagesLocked()或removeAllMessagesLocked()。void quit(boolean safe) { if (!mQuitAllowed) { throw new IllegalStateException("Main thread not allowed to quit."); } synchronized (this) { if (mQuitting) { return; } mQuitting = true; if (safe) { removeAllFutureMessagesLocked(); } else { removeAllMessagesLocked(); } // We can assume mPtr != 0 because mQuitting was previously false. nativeWake(mPtr); } }
如果不是安全退出,执行removeAllMessagesLocked(),该方法就是遍历Message链表,移除所有信息的回调,并重置为null。private void removeAllMessagesLocked() { Message p = mMessages; while (p != null) { Message n = p.next; p.recycleUnchecked(); p = n; } mMessages = null; }
如果是安全的退出,执行removeAllFutureMessagesLocked(),该方法,根据private void removeAllFutureMessagesLocked() { final long now = SystemClock.uptimeMillis(); Message p = mMessages; if (p != null) { if (p.when > now) { removeAllMessagesLocked(); } else { Message n; for (;;) { n = p.next; if (n == null) { return; } if (n.when > now) { break; } p = n; } p.next = null; do { p = n; n = p.next; p.recycleUnchecked(); } while (n != null); } } }
Message.when
这个属性,判断我们当前消息队列是否正在处理消息,没有处理消息的话,直接移除所有的回调,正在处理的话,等待该消息处理完毕再退出该循环。因此说quiteSafe()是安全的,而quit()是不安全的,因为quit()不管是否正在处理,直接移除所有的回调。
网友评论