Android中的代理模式
1. 什么是代理
比如我们生活中的找出租屋,需要去找中介进行寻找挑选.
而这里的中介就是代理.
列子中看出代理特点如下
1. 租客跟中介要做成的最终目的是一致的就是租到房子(目标一致).
2. 中介资源多,有权利跟房东进行价格协商(功能强大).
3. 中介是不会让我们直接跟房东进行协商(无法直接访问到目标).
我们在开发中也是有相似的情况出现
你有个a类,本来是调用c类方法,完成某个功能.但是c类不让a直接调用.
a-->不能直接调用c的方法
在a和c之间直接创建一个b代理类,c让b访问.
a-->访问b方法-->访问c方法
总结:我们在开发中使用代理模式是为了在不修改目标对象的基础上,增强主业务逻辑,客户类真正的想要访问的对象是目标对象,但是客户类真正可以访问的对象是代理对象.
2. 代理模式的作用
1.功能增强:在原有的功能上,增加额外的功能.
2.控制访问:代理类不让你访问到目标类.
3. 实现代理的方式-静态代理
1.自己手工实现的代理类.
2.代理的目标类是固定的.
特点:实现简单,容易理解.
举例子:
用户买鞋子行为
用户(客户端)-----商家(代理类)-----厂家(目标类)
其中,商家和厂家都是卖鞋子的,他们的完成的功能是一致的都是卖鞋子
interface IShoesSell {
//num 购买的数量 返回值是一双鞋子的价格
public float sell(int num);
}
//特步厂家
public class TebuShoesSellimpl implements IShoesSell {
@Override
public float sell(int num) {
return 300.0f;
}
}
//京东商家
public class JD implements IShoesSell {
private IShoesSell mFactory = new TebuShoesSellimpl();
@Override
public float sell(int num) {
float price = mFactory.sell(num);
price += 25;
return price;
}
}
public void main(String[] args) {
//创建代理对象-JD 进行购买
JD jd =new JD();
jd.sell(1); //这里我们就是通过京东购买了特步的鞋子325块
}
我们可以在JD类sell方法进行功能增强(添加优惠券,满减等),也不难发现我们JD类里面的目标类是固定的(特步厂家TebuShoesSellimpl).
多添加厂家和商家代码的情况:
//京东商家
public class JD implements IShoesSell {
private IShoesSell mFactory = new TebuShoesSellimpl();
@Override
public float sell(int num) {
float price = mFactory.sell(num);
price += 25;
return price;
}
}
//拼多多商家
public class PDD implements IShoesSell {
private IShoesSell mFactory = new TebuShoesSellimpl();
@Override
public float sell(int num) {
float price = mFactory.sell(num);
price -= 25;
return price;
}
}
//安踏厂家
public class AntaShoesSellimpl implements IShoesSell {
@Override
public float sell(int num) {
return 350.0f;
}
}
//京东商家-安踏
public class JDAnta implements IShoesSell {
private IShoesSell mFactory = new AntaShoesSellimpl();
@Override
public float sell(int num) {
float price = mFactory.sell(num);
price += 25;
return price;
}
}
//拼多多商家-安踏
public class PDDAnta implements IShoesSell {
private IShoesSell mFactory = new AntaShoesSellimpl();
@Override
public float sell(int num) {
float price = mFactory.sell(num);
price -= 25;
return price;
}
}
//这里就带来一个问题我只要添加一个目标类(安踏厂家),那我的代理类(商家)都要对应添加类,会出现一对n的变化,增加代码维护成本.
缺点:
- 目标类增多对应的代理类成倍增加.
- 当接口的方法进行添加修改时,会影响到众多类实现类需要修改,大大增加出错率.
4. 实现代理的方式-动态代理
优点:
- 代理类数量可以很少.
- 当你修改了接口中的方法时,不会影响代理类.
概念:
在程序执行过程中,使用jdk的反射机制,创建代理类对象,并动态的制定要代理目标类.
理解:
正常我们在java中想要创建对象是需要两个步骤
- 创建类文件,java文件编译成class文件.
- 使用构造方法new JD() ,创建类的对象.
动态代理直接是第二步骤(创建类的对象),跳过类文件创建.(so 文件少的原因)
动态代理的实现需要掌握的类(java.lang.reflect):
- InvocationHandler:
接口,invoke方法里面填写功能代码
public Object invoke(Object proxy, Method method, Object[] args);
- Method:
类中的方法,通过Method对象就可以执行某个方法. (invoke方法)
public native Object invoke(Object obj, Object ... args)
- Proxy:
核心的对象,主要是创建代理对象.使用newProxyInstance()代替new.
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
实现动态代理完整代码
IShoesSell mFactory = new TebuShoesSellimpl(); //特步厂家
// IShoesSell mFactory = new AntaShoesSellimpl(); //安踏厂家
IShoesSell proxy = (IShoesSell)Proxy.newProxyInstance(mFactory.getClass().getClassLoader(), mFactory.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
float price = (float) method.invoke(mFactory, args);
price += 30;// 京东代理
//price -= 25; 拼多多代理
return price;
}
});
proxy.sell(1);
下面是实际的项目中的运用–获取项目中metaData数据进行修改
通过源码发现metadata 在ApplicationInfo中metaData属性.
private static void hookPM( ) {
try {
//获取ActivityThread对象
Class<?> activityThreadClass = Class.forName("android.app.ActivityThread");
Field field = activityThreadClass.getDeclaredField("sCurrentActivityThread");
field.setAccessible(true);
Object activityThread = field.get(null);
//获取了PackageManager对象
Method getPackageManager = activityThread.getClass().getDeclaredMethod("getPackageManager");
getPackageManager.setAccessible(true);
Object iPackageManager = getPackageManager.invoke(activityThread);
//获取IPackageManager接口的Class对象
Class<?> iPackageManagerClass = Class.forName("android.content.pm.IPackageManager");
//生成动态代理类
Object pmProxy = Proxy.newProxyInstance(
Thread.currentThread().getContextClassLoader(), //加载代理类的类加载器
new Class[]{iPackageManagerClass}, //代理类需要实现的接口 (需要实现被代理类的接口)
(proxy, method, args) -> { // 当被代理类的接口实现方法被调用时,会回调此实现类的invoke()方法,该方法中应该保证被代理类的原逻辑的执行(即 return时的调用)
//ApplicationInfo
if (method.getName().equals("getApplicationInfo")) {
ApplicationInfo invoke = (ApplicationInfo) method.invoke(iPackageManager, args);
if (invoke.metaData == null) {
} else {
Bundle metaData = invoke.metaData;
metaData.putString("BD_KEY", "fdfdfdfffff");
metaData.putString("GD_KEY", "fffffsdssss");
}
return invoke;
} else {
return method.invoke(iPackageManager, args);
}
});
Field sPackageManagerField = activityThreadClass.getDeclaredField("sPackageManager");
sPackageManagerField.setAccessible(true);
sPackageManagerField.set(activityThread, pmProxy);
} catch (Exception e) {
e.printStackTrace();
}
}