Android中责任链模式的简单实现

责任链

责任链模式使得链上的每个处理者都有机会处理相应的请求,直到链上的某个节点能正确的对请求作出响应。
看着是不是觉得很熟悉,其实在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进行压缩处理之类,每个节点都有自己的职责,都有机会参与到我们的请求处理,和响应处理,这就是责任链模式。

总结

责任链我们通过上面的例子就讲清楚啦,当然我们的场景可能用不上责任链,只不过是用这个例子来学习责任链的实现,共勉。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值