创建父子工程module_组件化架构 4. 动态创建

组件化中使用动态创建的作用是解耦;

  1. 反射机制

反射有两个作用:1.反编译:.class->.java;2.通过反射机制访问java对象中的属性,方法,构造器等;

实现反射,实际上是得到Class对象

data class Person(val name: String = "") {
private var age = -1

fun setAge(age: Int) {
this.age = age
}

override fun toString(): String {
return "Person(name='$name', age=$age)"
}

companion object {
fun getAuthor() {
LjyLogUtil.d("JinYang")
}
}

}

private fun initClass() {
//常用类
// import java.lang.Class //类的创建
// import java.lang.reflect.Constructor //反射类中构造方法
// import java.lang.reflect.Field//反射属性
// import java.lang.reflect.Method//反射方法
// import java.lang.reflect.Modifier//访问修饰符的信息
// 反射机制获取类:使用Class
//三种获取Class对象的方法
//1.会让ClassLoader装载类,并进行类的初始化
val c1 = Class.forName("com.ljy.publicdemo.activity.Person")
//2.会让ClassLoader装载类,不进行类的初始化操作
val c2 = Person::class.java
//3.在实例中获取,返回类对象运行时真正所指的对象
val c3 = Person("bob").javaClass
//无参数创建对象
val person = c1.newInstance() as Person
LjyLogUtil.d(person.toString())
//new Person()是直接创建一个实列,同时完成类的装载和连接
//newInstance是使用类加载机制,可以灵活的创建类的实例,更换类的时候无需修改之前的代码
//有参数的创建对象: 使用Constructor
val constructor = c1.getConstructor(String::class.java)
val person2 = constructor.newInstance("Emily") as Person
LjyLogUtil.d(person2.toString())
//反射类的属性:使用Field
val fieldAge = c1.getDeclaredField("age")
val fieldName = c1.getDeclaredField("name")
//取消封装,特别是取消私有字段的访问限制,并不是将方法的权限设置为public,而是取消java的权限控制检查,
// 所以即使是public方法,其isAccessible默认也是false
fieldAge.isAccessible = true
fieldName.isAccessible = true
fieldAge.set(person2, 18)
LjyLogUtil.d("fieldAge.name=${fieldAge.name}")

//修改属性中的修饰符,使用Modifier
val modifierAge = Modifier.toString(fieldAge.modifiers)
val modifierName = Modifier.toString(fieldName.modifiers)
LjyLogUtil.d("modifierAge=$modifierAge, modifierName=$modifierName")
LjyLogUtil.d(person2.toString())
//反射类中的方法:使用Method
val method = c1.getDeclaredMethod("setAge", Int::class.java)//获取类中的方法
method.invoke(person2, 22)//通过反射调用方法
LjyLogUtil.d(person2.toString())

//遍历属性
for (it in c1.declaredFields) {
LjyLogUtil.d("declaredFields.it:${it.name}")
}
//遍历方法
for (it in c1.declaredMethods) {
LjyLogUtil.d("declaredMethods.it:${it.name}")
}
//遍历构造器
for (it in c1.declaredConstructors) {
LjyLogUtil.d("declaredConstructors.it:")
for (i in it.parameterTypes) {
LjyLogUtil.d("it.parameterTypes.i:${i.name}")
}
}

//反射静态方法
val clz = Class.forName("com.ljy.publicdemo.util.LjyLogUtil")
val m = clz.getDeclaredMethod("d", CharSequence::class.java)
m.invoke(LjyLogUtil::class.java, "log.d")

//反射泛型参数方法
//class Test {
// public void test(T t){
// LjyLogUtil.d("Test.test(),t:"+t);
// }
//}
val clz2 = Class.forName("com.ljy.publicdemo.activity.Test")
//注意这里有个泛型的基础--泛型擦除,编译器会自动类型向上转型,T向上转型是Object,所以下面第二个参数是Object.class
val tm = clz2.getDeclaredMethod("test", Object::class.java)
tm.isAccessible = true
tm.invoke(Test(), 666)
//Proxy动态代理机制
//java的反射机制提供了动态代理模式实现,代理模式的作用是为其他对象提供一种代理,以控制对这个对象的访问
//
// * 声明共同的接口
//public interface Subject {
// void doSomething();
//}
// * 具体实现类
//public class RealSubject implements Subject{
// @Override
// public void doSomething() {
// LjyLogUtil.d("RealSubject.doSomething()");
// }
//}
// * 代理类
//public class ProxyHandler implements InvocationHandler {
// private Object realSubject;
//
// public ProxyHandler(Object realSubject) {
// this.realSubject = realSubject;
// }
//
// @Override
// public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// //...可执行一些实际的业务逻辑
// Object result=method.invoke(realSubject, args);
// //...可执行一些实际的业务逻辑
// return result;
// }
//}
val real = RealSubject()
val proxySubject = Proxy.newProxyInstance(
Subject::class.java.classLoader,
arrayOf(Subject::class.java),
ProxyHandler(real)
) as Subject
proxySubject.doSomething()
//反射简化: jOOR
//当预期工程非常多的使用到反射时,我们需要更加简化的工具来优化开发流程,一个很棒的反射框架jOOR,非常轻量,让代码更加优雅
//项目地址 https://github.com/jOOQ/jOOR
//gradle中添加依赖
//implementation 'org.jooq:joor:0.9.13'
val helloStr: String? = Reflect.onClass("java.lang.String")//类似于Class.forName
.create("Hello jOOR")//调用类中构造方法
.call("substring", 8)//调用类中方法
.call("toString")
.get()//获取包装好的对象
LjyLogUtil.d("helloStr=$helloStr")
//也支持动态代理
Reflect.onClass(RealSubject::class.java).create().`as`(Subject::class.java).doSomething()
}
}复制代码
  1. 动态创建fragment

  • 开发中经常会用到activity+多fragment的场景;

  • 正常使用activity引用fragment方式时是强引用(import包名),在组件化项目中,如果fragment是组件module中的, activity是主module或其他module的, 就会造成耦合严重,当需要移除时也很麻烦,那么如何降低耦合呢, 这就可以通过上面说的反射实现;

//管理fragment标题及路径的类
public class PageConfig {
public static List pageTitles = new ArrayList();
public static List getPageTitles(Context context) {
pageTitles.clear();
pageTitles.add("Fragment1");
pageTitles.add("Fragment2");
pageTitles.add("Fragment3");
return pageTitles;
}
private static final String PATH_FRAGMENT1 = "com.ljy.publicdemo.activity.fragment.Fragment1";
private static final String PATH_FRAGMENT2 = "com.ljy.publicdemo.activity.fragment.Fragment2";
private static final String PATH_FRAGMENT3 = "com.ljy.publicdemo.activity.fragment.Fragment3";
public static String[] fragmentNames = {
PATH_FRAGMENT1,
PATH_FRAGMENT2,
PATH_FRAGMENT3,
};
}
//通过反射遍历添加
class FragmentActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_frag)
try {
//遍历Fragment地址
for (address in PageConfig.fragmentNames) {
//反射获得Class
val clazz = Class.forName(address)
//创建类
val fragment = clazz.newInstance() as Fragment
//添加到viewPagerAdapter的资源
supportFragmentManager
.beginTransaction()
.add(R.id.frame_layout, fragment)
.commit()
}
} catch (e: ClassNotFoundException) {
} catch (e: IllegalAccessException) {
} catch (e: InstantiationException) {
}
}
}复制代码

使用反射会相对安全,也会降低耦合,但反射会造成一定的效率下降;

ARouter也提供了跨模块获取fragment对象的操作

class FragmentActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_frag)
//ARouter提供了跨模块获取fragment对象的操作
val fragment1=ARouter.getInstance().build(ARouterPath.FRAGMENT_PATH_1).navigation() as Fragment1
fragment1.fragmentManager = supportFragmentManager
supportFragmentManager
.beginTransaction()
.add(R.id.frame_layout, fragment1)
.commit()
}
}

底层_ARouter类中也是通过反射实现
private Object _navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {
final Context currentContext = null == context ? mContext : context;
switch (postcard.getType()) {
...
case FRAGMENT:
Class fragmentMeta = postcard.getDestination();
try {
Object instance = fragmentMeta.getConstructor().newInstance();
if (instance instanceof Fragment) {
((Fragment) instance).setArguments(postcard.getExtras());
} else if (instance instanceof android.support.v4.app.Fragment) {
((android.support.v4.app.Fragment) instance).setArguments(postcard.getExtras());
}

return instance;
} catch (Exception ex) {
logger.error(Consts.TAG, "Fetch fragment instance error, " + TextUtils.formatStackTrace(ex.getStackTrace()));
}
...
}

return null;
}

复制代码
  • 使用跨模块获取Fragment非日常适合在单Activity+多fragment的app架构中使用,因为fragment划分模块作为入口的设计,使用ARouter的方式非常适应模块间解耦的要求;

  • 当业务模块选用fragment的形式作为业务入口时,需要充分考虑模块间业务跳转的解耦性,以保证业务分离后不会造成app崩溃

  1. 动态配置Application

  • 开发中我们经常会遇到某些功能模块中需要一些初始化的操作,只能强引用到主module的application中,这种情况如何更好的解耦呢?

//1. 通过主module的application获取各module的初始化文件,然后通过反射初始化的java文件来调用初始化方法

/**
* @Author: LiuJinYang
* 在base module中定义通用接口
*/
public interface BaseAppInit {
/**
* 需要优先被初始化的
*/
boolean onInitSpeed(Application application);
/**
* 可以延迟初始化的
*/
boolean onInitLow(Application application);
}

/**
* @Author: LiuJinYang
*
* 在组件module中的实现
*/
public class LibAppInitImpl implements BaseAppInit {
@Override
public boolean onInitSpeed(Application application) {
//一些初始化操作
return false;
}

@Override
public boolean onInitLow(Application application) {
//一些初始化操作
return false;
}
}

//主module中配置文件
public class PageConfig {
private static final String LIB_APP_INIT="com.jinyang.mylibrary.LibAppInitImpl";

public static String[] initModules={LIB_APP_INIT,};
}

//主application中通过反射加载组件module的初始化文件
public class DemoApplication extends Application {

@Override
public void onCreate() {
super.onCreate();
initModulesSpeed();
//todo 。。。其他的初始化操作
initModulesLow();
}

private void initModulesSpeed() {
for (String address : PageConfig.initModules) {
try {
//反射获得Class
Class clazz = Class.forName(address);
BaseAppInit moduleInit = (BaseAppInit) clazz.newInstance();
moduleInit.onInitSpeed(this);
} catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) {
//todo ...
}
}
}

private void initModulesLow() {
for (String address : PageConfig.initModules) {
try {
//反射获得Class
Class clazz = Class.forName(address);
BaseAppInit moduleInit = (BaseAppInit) clazz.newInstance();
moduleInit.onInitLow(this);
} catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) {
//todo ...
}
}
}
}

上面代码可以基本满足组件化中的解耦,但反射有一定的性能损耗,对于追求app秒开体验的需求,可以通过RxJava使用
非UI线程初始化各组件module;

2. 通过主module的application中继承base module的application实现

/**
* @Author: LiuJinYang
*
* baseModule中声明一个初始化类
*/
class BaseAppLogic {
protected BaseApplication mApplication;

public BaseAppLogic() {
}

public void setApplication(@NonNull BaseApplication application) {
this.mApplication = application;
}

public void onCreate(){}
public void onTerminate(){}
public void onLowMemory(){}
public void onTrimMemory(int level){}
public void onConfigurationChanged(Configuration configuration){}
}

/**
* @Author: LiuJinYang
* base module的application中做初始化文件的启动封装
*/
public abstract class BaseApplication extends Application {
private List> logicClassList =new ArrayList<>();
private ListlogicList=new ArrayList<>();
@Override
public void onCreate() {
super.onCreate();
initLogic();
logicCreate();
for (BaseAppLogic logic:logicList){
logic.onCreate();
}
}
/**
* 主module的application中调用
*/
protected abstract void initLogic();
protected void registerApplicationLogic(String logicClassPath){
Class extends BaseAppLogic> logicClass= null;
try {
logicClass = (Class extends BaseAppLogic>) Class.forName(logicClassPath);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
logicClassList.add(logicClass);
}
protected void logicCreate(){
for(Class<?extends BaseAppLogic> logicClass:logicClassList){
try {
BaseAppLogic appLogic=logicClass.newInstance();
logicList.add(appLogic);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
}
}
@Override
public void onTerminate() {
super.onTerminate();
for (BaseAppLogic logic:logicList){
logic.onTerminate();//其他BaseAppLogic接口同样处理
}
}
}
/**
* @Author: LiuJinYang
* 每个组件module中需要初始化时继承此类,然后复写需要的接口
*/
public class LibInitLogic extends BaseAppLogic{
@Override
public void onCreate() {
super.onCreate();
Log.d("LJY_LOG","LibInitLogic.onCreate");
}
}
//主module的application继承BaseApplication,调用initLogic注册所有BaseAppLogic的实现类
public class MyApplication extends BaseApplication {
@Override
protected void initLogic() {
registerApplicationLogic("com.jinyang.mylibrary.LibInitLogic");
}
}复制代码

我是今阳,如果想要进阶和了解更多的干货,欢迎关注公众号接收我的最新文章

8467b06436e07b3394566011bed0ec45.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值