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