观察者模式的实际使用——状态监控及恢复策略

背景

在实际项目开发过程中,我们常常会用到一些状态监控策略,这种策略通常是观察者模式的具体应用。这种策略只关注状态的异常情况,当出现了超时情况时向观察者发送通知,与通常意义上的观察者模式不同的是,被监控的对象和我们的监控管理类构成了被观察者,被监控的对象定时向监控管理类发送状态通知。

关系图

代码实现

ITimeoutCallback

/**
 * 超时回调
 *
 * @author jiangwenzhong
 * @date 2019/7/25
 */
public interface ITimeoutCallback {

    /**
     * 超时回调
     */
    @MainThread
    void timeout();
}

ITimeoutMonitorAction


/**
 * 超时监控的包含的操作方法
 *
 * @author jiangwenzhong
 * @date 2019/7/25
 */
public interface ITimeoutMonitorAction {

    /**
     * 初始化监控任务
     *
     * @param timeout 毫秒
     */
    void initial(long timeout);

    /**
     * 启动超时监控任务
     */
    void start();

    /**
     * 通知刷新监听状态
     *
     * @param forceRefresh 强制更新
     */
    void updateStatus(boolean forceRefresh);

    /**
     * 设置超时回调
     *
     * @param timeoutCallback 超时回调
     */
    void setTimeoutCallback(ITimeoutCallback timeoutCallback);

    /**
     * 停止超时监控任务
     */
    void stop();

    /**
     * 释放监控任务
     */
    void release();
}

TimeoutMonitor


import android.os.Handler;
import android.os.Looper;
import android.os.SystemClock;

import com.sensetime.log.BILog;


/**
 * 定时器操作者
 *
 * @author jiangwenzhong
 * @date 2019/7/25
 */
public class TimeoutMonitor implements ITimeoutMonitorAction {

    public static final int DEFAULT_TIMEOUT = 10000;
    private ITimeoutCallback mTimeoutCallback;
    private long mTimeout = DEFAULT_TIMEOUT;
    private volatile long vHasStartTime = 0;
    private Runnable mWorkRun;
    private Handler mHandler;
    private volatile boolean vIsMonitoring = false;

    public TimeoutMonitor() {

    }

    /**
     * 初始化超时监控任务
     *
     * @param timeout 毫秒
     */
    @Override
    public synchronized void initial(long timeout) {

        this.mTimeout = timeout;
        if (mHandler == null) {
            mHandler = new Handler(Looper.getMainLooper());
        }
    }

    /**
     * 开始超时监控任务
     */
    @Override
    public synchronized void start() {

        if (mWorkRun == null) {
            mWorkRun = () -> {

                BILog.d("-------Dealing with timeout exception------");
                if (mTimeoutCallback != null) {
                    synchronized (TimeoutMonitor.this) {

                        stop();
                        mTimeoutCallback.timeout();
                        start();
                    }
                }
            };
        }
        if (mHandler == null) {
            initial(mTimeout);
        }

        // 停止上次的消息
        stop();
        // 开始延时消息
        mHandler.postDelayed(mWorkRun, mTimeout);
        vHasStartTime = SystemClock.uptimeMillis();
        vIsMonitoring = true;
    }

    /**
     * 强制刷新定时器
     *
     * @param forceRefresh 是否强制刷新定时器
     */
    @Override
    public synchronized void updateStatus(boolean forceRefresh) {

        if (mWorkRun == null || mHandler == null) {
            return;
        }
        // 还没有启动监听则退出
        if (!vIsMonitoring) {
            BILog.e("-------Didn't start monitor,ignore updateStatus ------");
            return;
        }
        boolean noNeedReset = Math.abs(SystemClock.uptimeMillis() - vHasStartTime) < mTimeout / 2;
        if (noNeedReset && !forceRefresh) {
            return;
        }
        stop();
        start();
    }


    /**
     * 设置超时回调
     *
     * @param timeoutCallback 超时回调
     */
    @Override
    public void setTimeoutCallback(ITimeoutCallback timeoutCallback) {

        mTimeoutCallback = timeoutCallback;
    }

    /**
     * 停止超时监控任务
     */
    @Override
    public synchronized void stop() {

        if (mHandler != null) {
            mHandler.removeCallbacksAndMessages(null);
        }
        vIsMonitoring = false;
    }

    /**
     * 释放超时监控任务资源
     */
    @Override
    public synchronized void release() {

        if (mHandler != null) {
            mHandler.removeCallbacksAndMessages(null);
            mHandler = null;
        }
    }
}

应用例子

监控摄像头数据是否突然中断

  • CameraTimeoutMonitor
/**
 * 摄像头操作
 *
 * @author jiangwenzhong
 * @date 2019/7/25
 */
public class CameraTimeoutMonitor extends TimeoutMonitor implements ITimeoutCallback {

    private int mCameraType;
    private PreviewCallback mPreviewCallback;

    public CameraTimeoutMonitor(int cameraType) {

        super.setTimeoutCallback(this);
        this.mCameraType = cameraType;
    }

    @Override
    public synchronized void initial(long timeout) {

        if (mPreviewCallback == null) {
            mPreviewCallback = (data, camera) -> updateStatus(false);
        }
        CameraManager.getInstance(mCameraType).addPreviewCallbackWithBuffer(mPreviewCallback);
        super.initial(timeout);
    }

    @Override
    public synchronized void release() {

        CameraManager.getInstance(mCameraType).removePreviewCallbackWithBuffer(mPreviewCallback);
        super.release();
    }

    @Override
    public void timeout() {

        BILog.e("---------CameraTimeoutMonitor timeout--------------");
        CameraManager cameraManager = CameraManager.getInstance(mCameraType);
        cameraManager.stopPreview();
        cameraManager.releaseCamera();
        cameraManager.openCamera(ContextUtils.getContext());
        cameraManager.startPreview();
    }
}
  • 在摄像头的生命周期中一次调用监控器的生命周期方法
// 启动摄像头
camera.open(1);
cameraTimeoutMonitor.initial(10*1000);

// 开始预览
camera.startPreview();
cameraTimeoutMonitor.start();

// 停止预览
camera.stopPreview();
cameraTimeoutMonitor.stop;

// 关闭摄像头
camera.release();
cameraTimeoutMonitor.release();

结束

这种策略的思路其实很简单,但是在很多场景中都是使用这样的思路来实现的,包括我们Android系统里面的超时机制,系统监控应用是否出现了相应超时就是通过类似的方式来做的,之后有机会再将系统anr的监控机制整理一下发出来。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值