Android组件化架构 – 4. 动态创建 & 反射机制

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

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()
    }
}



2. 动态创建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崩溃

3. 动态配置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");
    }
}
阅读全文
下载说明:
1、本站所有资源均从互联网上收集整理而来,仅供学习交流之用,因此不包含技术服务请大家谅解!
2、本站不提供任何实质性的付费和支付资源,所有需要积分下载的资源均为网站运营赞助费用或者线下劳务费用!
3、本站所有资源仅用于学习及研究使用,您必须在下载后的24小时内删除所下载资源,切勿用于商业用途,否则由此引发的法律纠纷及连带责任本站和发布者概不承担!
4、本站站内提供的所有可下载资源,本站保证未做任何负面改动(不包含修复bug和完善功能等正面优化或二次开发),但本站不保证资源的准确性、安全性和完整性,用户下载后自行斟酌,我们以交流学习为目的,并不是所有的源码都100%无错或无bug!如有链接无法下载、失效或广告,请联系客服处理!
5、本站资源除标明原创外均来自网络整理,版权归原作者或本站特约原创作者所有,如侵犯到您的合法权益,请立即告知本站,本站将及时予与删除并致以最深的歉意!
6、如果您也有好的资源或教程,您可以投稿发布,成功分享后有站币奖励和额外收入!
7、如果您喜欢该资源,请支持官方正版资源,以得到更好的正版服务!
8、请您认真阅读上述内容,注册本站用户或下载本站资源即您同意上述内容!
原文链接:https://www.dandroid.cn/archives/19692,转载请注明出处。
0

评论0

显示验证码
没有账号?注册  忘记密码?