jQuery鼠标指针特效

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) { /* ... */ }
}
posted @ 2024-06-28 15:14  僵小七  阅读(38)  评论(0)    收藏  举报