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;
...
}
}
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
· PowerShell开发游戏 · 打蜜蜂
· 凌晨三点救火实录:Java内存泄漏的七个神坑,你至少踩过三个!