Thead+Handler+Looper应用实例
Thead+Handler+Looper应用实例
使用SeekBar(当用户的选择有变化后,会回调onProgressChanged函数)来控制系统的音效,
比如高音的增益,范围-12~+12dp.
要求1:UI界面不能卡顿,响应流畅
要求2:能实时反应出音效的变化,功能不延迟
要求3:系统必须稳定
假设有如下前提:
1.像系统发送音效调整是一个耗时的操作
2.频繁发送调整命令可能导致界面卡死,系统死机
3.用户从操作是不可控的,可能快速,也可能缓慢,不能让用户感受到滞后的感觉
针对要求1,可以将耗时的操作放在一个独立的线程内,这样不会影响主线程刷新UI
而要求2和要求3的表现是有矛盾的,如果需要实时听到音效的变化,意味着SeekBar在变化的时候,
需要不断的发送变化的值给系统,而不是等用户松手是才发送最终值.但是如果用户操作是快速来回拖动,
必然会产生大量的请求命令,这样违背了前提2.举个例子,用户在1s内从-12拉到+12,这可能产生(假设)24个调整值,
(实际可能少一点,seekBar可能不会触发这么多次onProgressChanged),而发送每个调整值则需要500ms,相当于
用户停止操作后,最坏情况要0.5*24-1 = 11s,才能逐步听到音效的变化.
思路:
如果用户1s内产生了24个调整值,这24个调整值自然有产生的先后顺序,可以按照这个先后顺序将它们放入一个队列中,
然后排队进行处理,直到用户操作结束(500ms才处理一个),队列里面的数就不会在增加!对于这个队列里的值,
是存在优先级,明显后进入队列的值,更能接近用户想要的效果.控制队列中的消息数量,比如:
1.当产生一个新的调整值时,先清空消息队列,然后在才把请求入队
2.当产生一个新的调整值时,先判断消息队列中的数量,根据实际情况删除部分消息,然后才把请求入队
总是去处理最后几个进入队列的调整值
BusinessThread.java
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
public class BusinessThread {
private Thread mBusinessThread = null;
private boolean mBusinessThreadStarted = false;
private BusinessThreadHandler mBusinessThreadHandler = null;
private void startBusinessThread() {
if (true == mBusinessThreadStarted) {
return;
} else {
mBusinessThreadStarted = true;
mBusinessThread = new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();
mBusinessThreadHandler = new BusinessThreadHandler();
Looper.loop();
}
});
mBusinessThread.start();
}
}
class BusinessThreadHandler extends Handler {
public boolean sendMessage(int what, int arg1, int arg2) {//重写sendMessage
removeMessages(what);//清理消息队列中未处理的消息
return super.sendMessage(obtainMessage(what, arg1, arg2));//发送消息到队列
}
public void handleMessage(Message msg) {
switch (msg.what) {
case 0:
//耗时操作
break;
}
}
}
}
在Android系统中负责调节音量的SystemUI中音量模块,也用到了类似的设计思路
com.android.systemui.volume.VolumeDialogControllerImpl.java
private final HandlerThread mWorkerThread;
private final W mWorker;
public VolumeDialogControllerImpl(...){
...
mWorkerThread = new HandlerThread(VolumeDialogControllerImpl.class.getSimpleName());
mWorkerThread.start();
mWorker = new W(mWorkerThread.getLooper());
...
}
private final class W extends Handler {
private static final int VOLUME_CHANGED = 1;
...
W(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case VOLUME_CHANGED: onVolumeChangedW(msg.arg1, msg.arg2); break;
...
}
}
}
异步线程管理在Android上的实现方法
HandlerThread是Thread的子类,内部有自己的Looper,适合在后台执行耗时任务,而Handler用于在不同线程之间发送和处理消息。
// 创建HandlerThread实例
HandlerThread handlerThread = new HandlerThread("AsyncThread");
// 启动HandlerThread
handlerThread.start();
// 创建Handler与HandlerThread绑定
Handler asyncHandler = new Handler(handlerThread.getLooper()) {
@Override
public void handleMessage(Message msg) {
// 处理后台线程传递过来的消息
// 更新UI或者其他操作
}
};
// 发送消息到HandlerThread进行异步处理
Message message = Message.obtain();
message.what = SOME_MESSAGE_ID;
asyncHandler.sendMessage(message);
demo_1 :MyBackgroundService
import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import androidx.annotation.Nullable;
/*
消息处理流程图 :
UI->>WorkerHandler: sendMessage(MSG_TASK_A)
WorkerHandler->>HandlerThread: 消息入队
HandlerThread->>WorkerHandler: 取出消息处理
WorkerHandler->>UI: 通过MainHandler更新界面
* */
public class MyBackgroundService extends Service {
private HandlerThread mWorkerThread;
private Handler mWorkerHandler;
private static final int MSG_TASK_A = 1;
private static final int MSG_TASK_B = 2;
@Override
public void onCreate() {
super.onCreate();
// 初始化后台线程
mWorkerThread = new HandlerThread("BackgroundWorker");
mWorkerThread.start();
// 初始化工作Handler
mWorkerHandler = new Handler(mWorkerThread.getLooper()) {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_TASK_A:
performTaskA(msg.arg1);
break;
case MSG_TASK_B:
String data = (String) msg.obj;
String result = performTaskB(data);
// 通过主线程Handler更新UI
new Handler(Looper.getMainLooper()).post(() -> {
updateUI(result);
});
break;
}
}
};
}
// 外部调用接口
public void scheduleTaskA(int param) {
Message msg = Message.obtain();
msg.what = MSG_TASK_A;
msg.arg1 = param;
mWorkerHandler.sendMessage(msg);
}
public void scheduleDelayedTaskB(String data, long delayMillis) {
mWorkerHandler.sendMessageDelayed(
Message.obtain(mWorkerHandler, MSG_TASK_B, data),
delayMillis
);
}
@Override
public void onDestroy() {
// 安全退出线程
mWorkerThread.quitSafely();
try {
mWorkerThread.join(1000); // 最多等待1秒
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
super.onDestroy();
}
private void performTaskA(int param) { /* 耗时操作 */ }
private String performTaskB(String data) { /* 返回处理结果 */
return null;
}
private void updateUI(String result) { /* 更新界面 */ }
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
demo_2:MyHandlerThread
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import androidx.annotation.NonNull;
import java.lang.ref.WeakReference;
public class MyHandlerThread extends HandlerThread {
private static final int MSG_DOWNLOAD = 1;
private Handler mWorkerHandler;
private final Object mLock = new Object();// 增加同步锁防止初始化竞争
private Handler mUiHandler = new Handler(Looper.getMainLooper());
private WeakReference<Handler> mUiHandlerRef;// 使用WeakReference防止内存泄漏
public MyHandlerThread() {
super("MyWorkerThread");
}
public MyHandlerThread(Handler uiHandler) {
super("MyWorkerThread");
mUiHandlerRef = new WeakReference<>(uiHandler);
}
// 初始化工作Handler
public void prepareHandler() {
synchronized (mLock) {
if (mWorkerHandler == null) {
mWorkerHandler = new Handler(getLooper()) {
@Override
public void handleMessage(@NonNull Message msg) {
switch (msg.what) {
case MSG_DOWNLOAD:
// 执行后台任务
String url = (String) msg.obj;
String result = downloadData(url);
// 通过UI Handler更新界面
/*mUiHandler.post(() -> {
updateUI(result);
});*/
Handler uiHandler = mUiHandlerRef.get();
if (uiHandler != null) {
mUiHandler.post(() -> {
updateUI(result);
});
}
break;
}
}
};
}
}
}
// 示例任务执行方法
public void startDownload(String url) {
mWorkerHandler.sendMessage(
Message.obtain(mWorkerHandler, MSG_DOWNLOAD, url)
);
}
// 退出时释放资源
@Override
public boolean quit() {
mWorkerHandler.removeCallbacksAndMessages(null);
return super.quit();
}
private String downloadData(String url) { /* ... */
//to do
return url;
}
private void updateUI(String result) { /* ... */ }
}

浙公网安备 33010602011771号