技术标签: android杂七八说 android 动态代理 View Android
本博客将会介绍动态代理在Android应用中的一种使用场景
代理模式的作用是为其它对象提供一种代理以控制对这个对象的访问。比如用户调用了一个“吃饭”的方法,如果不依靠代理,用户可能自己拿碗饭吃就行,而如果通过代理的话,可能连碗都不需要用户自己拿,用户只需要张开嘴,代理来喂就行了,需要注意的是,这里代理除了负责拿碗和喂饭外还可以做其他的任何事情,比如说帮你把饭吹凉一些,或者担心你的体重而偷偷帮你倒掉了一半的饭,又或者是往饭里加点什么奇奇怪怪的东西,谁知道呢,这就是代理干的活。实际上在java里面也提供了代理这一神奇的模式,而且还分为静态和动态两种,两者的区别是静态代理的结构在程序运行前就已经安排好了的,而动态代理则是在程序运行过程中指定的,本文所采用的就是动态代理方法。
在之前的一篇博客【Android】android镜像翻转 中分析过如何对一个View进行镜像翻转,也就是实现如下的效果:
镜像水平翻转前后效果
对于一般的View而言,直接用view.setScaleY(-1)即可达到这样的效果,而且针对自定义SurfaceView,也可以使用
canvas.scale(-1,1,canvas.getWidth()/2,canvas.getHeight()/2)
来进行翻转。但是如果面对的是第三方SurfaceView,且无法直接获取到SurfaceView用于绘制的canvas对象的话。比如上面左图实现代码如下。
public class TestSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
public TestSurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
getHolder().addCallback(this);
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
// 获取canvas
Canvas canvas = holder.lockCanvas();
canvas.drawColor(Color.rgb(220,220,220));
Paint paint = new Paint();
paint.setTextSize(60);
// 绘制文字
canvas.drawText("Hello, this is SurfaceView",200,600,paint);
// 绘制圆
canvas.drawCircle(300,800,100,paint);
// 显示
holder.unlockCanvasAndPost(canvas);
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {}
}
假设TestSurfaceView在第三方Jar包中,且无法对其进行修改。那么该如何对这个界面进行镜像翻转呢,下面给出通过动态代理实现的方案
结合上面的代码,我们知道,SurfaceView的绘制过程如下:
SurfaceView绘制流程
通常调用代码如下:
// 获取canvas画布
Canvas canvas = holder.lockCanvas();
//绘制内容
... ...
// 解锁画布,显示画布内容
holder.unlockCanvasAndPost(canvas);
holder是什么呢,我们可以在SurfaceView的源码里找到SurfaceHolder的实例mSurfaceHolder以及实现。
public class SurfaceView extends View {
......
private final SurfaceHolder mSurfaceHolder = new SurfaceHolder() {
private static final String LOG_TAG = "SurfaceHolder";
@Override
public boolean isCreating() {
return mIsCreating;
}
......
@Override
public Canvas lockCanvas() {
return internalLockCanvas(null);
}
@Override
public Canvas lockCanvas(Rect inOutDirty) {
return internalLockCanvas(inOutDirty);
}
......
};
}
代理的目标是要实现对surfaceholder里的lockCanvas方法进行监控,并为其返回值添加一定的操作,也就是将原先的流程改为如下结构:
动态代理添加访问控制
首先需要实现的是代理处理器,其代码如下:
public class TestInvocation implements InvocationHandler {
Object mObject ;
public TestInvocation(Object object) {
mObject = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 截取lockCanvas方法调用
if ("lockCanvas".equals(method.getName())) {
// lockCanvas方法返回值是canvas画布
Canvas canvas = (Canvas) method.invoke(mObject,args);
// 添加镜像
canvas.scale(-1,1,canvas.getWidth()/2,canvas.getHeight()/2);
return canvas;
}
return method.invoke(mObject,args);
}
}
完成代理处理器之后就可以为surfaceHolder添加动态代理,这里需要注意的是surfaceHolder在SurfaceView中,所需先取出来,再为之添加代理,代码如下:
// 获取 surfaceView中的 surfaceHolder
SurfaceHolder mSurfaceHolder = mTestSurfaceView.getHolder();
// 创建代理接口的实现
TestInvocation testInvocation = new TestInvocation(mSurfaceHolder);
// 为 mSurfaceHolder 添加动态代理,并获取添加代理之后的 newSurfaceHolder
SurfaceHolder newSurfaceHolder = (SurfaceHolder) Proxy.newProxyInstance(mSurfaceHolder.getClass().getClassLoader(),mSurfaceHolder.getClass().getInterfaces(),testInvocation);
新生成的newSurfaceHolder就是已经添加上动态代理的surfaceHolder,因为在SurfaceView中SurfaceHolder是私有属性,无法直接替换,所以这里需要借助反射机制来讲newSurfaceHolder替换掉SurfaceView中原先的mSurfaceHolder,代码如下:
// 获取mSurfaceHolder的field
Field fieldHolder = SurfaceView.class.getDeclaredField("mSurfaceHolder");
// 更改为可访问权限
fieldHolder.setAccessible(true);
// 用添加代理后的 newSurfaceHolder 替换 mSurfaceHolder
fieldHolder.set(mTestSurfaceView,newSurfaceHolder);
添加动态代理之后,TestSurfaceView中调用holder的lockCanvas方法所获取到的canvas都是经过TestInvocation转置的canvas,从而实现了这个奇怪的需求,也就是实现右侧图片的效果。
1.导入第三方包,以python-docx为例file->settings->project:***->project interpreter->+->搜索python-docx->Install Package2.输入代码from docx import Documentfrom docx.shared import Ptfrom docx.enum.text import WD_LINE_SPACINGimport reimport os
wzhifuSDK- 由微信支付SDK 官方PHP Demo移植而来,v3.37下载地址weixin_pay- 是一个简单的微信支付的接口weixin_pay- 微信支付接口(V3.3.7)类库。此类库目前只提供了三种接口的操作类:①统一支付接口②订单查询接口③JSAPI 支付wxpay- 微信支付非官方Python工具库。主要提供函数:get_brand_wc_pay_requ...
返回的错误为 14234: ‘指定的 ‘@server’ 无效(有效值由 sp_helpserver 返回)。’。请使用此操作和错误来确定失败的原因并重新提交请求。’。请使用此操作和错误来确定失败的原因并重新提交请求。使用如下语句查看主机名:select @@SERVERNAMEEXEC sp_helpserver; SELECT * FROM master.dbo.sysserve...
一:泛型 的好处: 1. 把运行时出现 的问题提前至了编译时。 2. 避免了无谓的强制类型转换。在泛型中没有多态的概念,两边的数据必须要一致。 或者是只写一边 的泛型类型。建议两边的数据类型都写上一致的。自定义泛型: 自定义泛型可以理解为是一个数据类型的占位符,或者是理解为是一个数据类型的变量。二:泛型的分类1. 泛型方法:泛型方法的定义格式: ...
由于无法访问国外网络,所以安装chrome的插件一直是心中的痛。老版本的postman已经无法使用了,怀念老的postman,可以直接使用chrome的开发者工具来进行调试,github地址 https://github.com/postmanlabs/postman-chrome-extension-legacy 。编译了一下,安装上了也无法使用。目前的postman插件如果想正常使用,必须安装...
编程实现Arnold变换1.概念Arnold变换是由Arnold提出的一种变换,也称猫变换、猫映射。目前Arnold变换主要用于图像置乱。该变换可以在其它图像处理前对图像做预处理,例如在数字盲水印嵌入前对水印进行置乱。也可以用于普通的图像加密。(1).正变换对于规模为NXN的正方形数字图像来说,我们将图像的所有像素集合看作一个NXN的矩阵。在Arnold变换中,设该矩阵中的任意像素位置为(x,y),
@阿乐今天敲代码没Java设计文本编辑器前言一、实现功能二、扼要代码1.界面程序设计2.文件菜单设计3.编辑菜单栏设计4.格式菜单栏设计运行截图前言利用Java设计一个文本编辑器。提示:以下是本篇文章正文内容,下面案例可供参考一、实现功能该简易记事本主要可实现以下几个功能:(1)菜单中有“文件”、“编辑”、“格式”三个主菜单。(2)“文件”有“打开”、“保存”、“退出”三个子菜单:分别用于打开文件,保存文件,退出记事本。(3)“编辑”中有“剪切”、“复制”、“粘贴”三个子菜单:用于剪
目录一、稠密点云的获取方式二、基础知识1.极线搜索:2.光度一致性假设 photo-consistency3.可视性约束三、多视角立体技术1.基于体素的方法2. 基于空间patch扩散的方法3.基于深度图融合的方法[4]参考一、稠密点云的获取方式Lidar扫描:精度高(毫米级别),效率高,有效范围几米到几百米,价格昂贵;高反光,玻璃表面,吸收表面Kinect:使用方便、价格适中、速度较快;精度较低、有效距离短结构光:高精度、高效率、近距离数据获取
今天在用Elementui 的表格时,发现所有表格的底部和分页之间有留白在滚轮和下部分页之间隔了一个白块,但是一刷新就没了,表格恢复正常。<el-table v-loading="loading" :key='tableKey' :data="genlist" @selection-change="handleSelectionChange" height="calc(100% - 152px)" :stripe="true" @sort-change="handleSo.
KNN,称K近邻,是一种有监督学习算法,可处理分类和回归问题。
#define PI (3.14159265358979323846)#define PI_DIV_180 (0.017453292519943296)//π/180#define DegToRad(x)((x)*PI_DIV_180)//角度转换为弧度让我们稍微写几行代码就可以验证其结果:// sin(x)中x角度还是弧度问题.cpp : 定义控制台应用程序的入口点。//#include "st...
Darknet_Yolov4实战(一)_安装Ubuntu+cuda+cudnn安装Ubuntu18.04安装显卡驱动安装cuda安装cudnn安装Ubuntu18.04首先关闭你要安装 Ubuntu18.04.1 的目标主机,然后插入启动盘,接着开机,迅速的按住 Del直到进入 bios 设置界面(不同的电脑进入 bios 的按键不同,一般为 F12 或者 Delete 键),通过方向键选择Boot Menu,然后回车.然后选择 设置U盘启动为第一选项,之后进入安装界面,一步步点击即可。注意分区,一