责任链
责任链模式使得链上的每个处理者都有机会处理相应的请求,直到链上的某个节点能正确的对请求作出响应。
看着是不是觉得很熟悉,其实在android上最常见的事件分发,okhttp上拦截器的实现,都是基于责任链模式来实现的。
使用场景
咱们这次的使用场景是对view转为Bitmap的时候,可考虑加上责任链,其实真正使用的时候,我们在此场景下大可不必使用责任链模式来构建我们的转换逻辑,因为实在有些小题大做,而在此场景下也不适用责任链模式来构建,只不过在我正准备写的时候突然灵光一闪,觉得可以用这个场景来练习下责任链模式的实现,其实我们责任链的实现参考okhttp拦截器的实现。
考虑一下有这种情况,我们的webview转为bitmap的使用,如果我们的webview显示的内容很长很长,而这时我们获取webview的bitmap的时候可能在生成bitmap的时候发生oom,所以如果产生这种情况,我们要找出第二种解决方法,也就是第一个节点解决获取不了我们要的bitmap的时候,我们将这次转换请求传递给下一个节点来处理,以此类推,直到有一个节点能获取到正确的bitmap。
抽象获取类
//抽象获取者
public interface Capture {
//获取view的bitmap
Bitmap capture(Chain chain);
//抽象责任链
interface Chain {
//执行链的下一个节点方法
Bitmap proceed(View view);
//目标view
View view();
}
}
获取实现类
//初始类,可用来初始化我们的目标view,也可以用来包装我们最终获取的bitmap
public class InitCapture implements Capture {
@Override
public Bitmap capture(Chain chain) {
View view = chain.view();
//例如我们这里进行判空
if (view == null) new RuntimeException("view must not be null");
//又例如我们的view还未加入窗口时,这时我们不能获取view的测量宽高,要手动调用测量函数
if (view.getMeasuredHeight() == 0 || view.getMeasuredWidth() == 0) {
int measureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
view.measure(measureSpec, measureSpec);
}
//将请求交给下一个节点处理
Bitmap bitmap = chain.proceed(view);
//当然我们可以在获取这个bitmap后包装这个bitmap再返回
return bitmap;
}
}
上面这个类,我们用来对初始view的初始化之类的操作,当然我们这里只是为了练习,增加的这个类只是来说明责任链模式对请求的处理,实际情况可能和我们现在写的不同。
//一次性获取view的bitmap的实现类
public class FullCapture implements Capture {
@Override
public Bitmap capture(Chain chain) {
Bitmap bitmap = capture(chain.view());
//如果我们这次获取不到bitmap,交给下一个节点处理,否则将回传我们处理好的bitmap
return bitmap != null ? bitmap : chain.proceed(chain.view());
}
public Bitmap capture(View view) {
return getBitmap(view);
}
private Bitmap getBitmap(View view) {
Bitmap bitmap;
try {
//创建view大小的bitmap
bitmap = Bitmap.createBitmap(view.getMeasuredWidth(), view.getMeasuredHeight(), Bitmap.Config.RGB_565);
} catch (OutOfMemoryError error) {
//如果oom手动gc
System.gc();
try {
//再次尝试
bitmap = Bitmap.createBitmap(view.getMeasuredWidth(), view.getMeasuredHeight(), Bitmap.Config.RGB_565);
} catch (OutOfMemoryError error2) {
return null;
}
}
Canvas canvas = new Canvas(bitmap);
view.draw(canvas);
return bitmap;
}
}
上面这个获取实现类,我们通过view.draw(canvas)方法来一次性获取整个bitmap,当然这时候有可能发生oom,我们可以手动gc后再尝试,如果还是oom,我们将请求传递给下一个处理者来处理。
//分段获取bitmap类,这里还没写实现
public class SubsectionCapture implements Capture {
public Bitmap capture(View view) {
........
......
return bitmap;
}
@Override
public Bitmap capture(Chain chain) {
Bitmap bitmap = null;
try {
bitmap = capture(chain.view());
} catch (OutOfMemoryError error) {
}
//假设这是最后一个处理类,不管我们处理是否成功都要返回我们的处理结果
return bitmap;
}
}
分段处理类这里的逻辑是使用 view.setDrawingCacheEnabled(true)等视图缓存函数来构建我们一节节的bitmap,最后合并成一个大的bitmap,当然实际情况下就算获取一节节bitmap,我们也要先这些bitmap存为本地文件,而不能直接返回我们大bitmap,不然还是会发生oom,这里只是为了说明责任链模式的实现才这样来写。
SubsectionCapture 作为我们链中的最后一个节点,不管我们处理是否成功,都将我们的处理结果回传。
责任链实现类
上面说了几个获取类的实现,他们都是链上的一个个节点,而我们的获取抽象方法是 Bitmap capture(Chain chain);
那这个Chain,也就是链从哪里来,又是怎么将每个节点给链接起来的呢?
//责任链实现类
public class CaptureChain implements Capture.Chain {
//保存我们链上的每个节点
private List<Capture> captures;
//目标view
private View view;
//节点的前进数
private int index;
public CaptureChain(List<Capture> captures, View view, int index) {
this.captures = captures;
this.view = view;
this.index = index;
}
@Override
public Bitmap proceed(View view) {
if (index >= captures.size()) throw new RuntimeException("captures size is " + captures.size());
//这里构建一个链,将节点前进一步,然后调用当前节点的捕获方法
CaptureChain captureChain = new CaptureChain(captures, view, index + 1);
return captures.get(index).capture(captureChain);
}
@Override
public View view() {
return view;
}
}
链的实现也简单,就是包装一个新的链,链上的处理节点指向下一个节点,也就是说如果有一个Capture 中调用 chain.proceed(chain.view())方法,则会将事件传递给下一个Capture 处理,直到最后处理并返回。
ViewCapture真正的转化请求类
做了上面的准备工作后,我们准备一个真正处理请求的类来响应用户的请求。
public class ViewCapture {
private static volatile ViewCapture instance;
private List<Capture> captures;
private ViewCapture() {
captures = new ArrayList<>();
captures.add(new InitCapture());
captures.add(new FullCapture());
captures.add(new SubsectionCapture());
}
public static ViewCapture get() {
if (instance == null) {
synchronized (ViewCapture.class) {
if (instance == null) {
instance = new ViewCapture();
}
}
}
return instance;
}
public Bitmap getBitmap(View view) {
//构建初始责任链,链的节点传0也就是第一个节点将会被执行
CaptureChain captureChain = new CaptureChain(captures,view,0);
//开始执行
return captureChain.proceed(view);
}
}
我们的处理类也很简单,通过单例来构建一个处理类,然后构建我们的链,开始处理请求,当执行captureChain.proceed(view)的时候,第一个Capture将处理开始处理我们的的请求,假设我们所有的节点都处理了请求,那么请求的顺序是从第一个节点到最后一个节点,也就是上面的InitCapture —> FullCapture —> SubsectionCapture
然后最后一个Capture处理好了bitmap,将bitmap回传,也就是从SubsectionCapture—>FullCapture —>InitCapture 最后给我们的调用方。
我们的节点可以具体处理某一个事件,也就说说例如我们增加一个Capture,将这个Capture放在第一个节点,然后我们将最后返回来的bitmap进行压缩处理之类,每个节点都有自己的职责,都有机会参与到我们的请求处理,和响应处理,这就是责任链模式。
总结
责任链我们通过上面的例子就讲清楚啦,当然我们的场景可能用不上责任链,只不过是用这个例子来学习责任链的实现,共勉。