美文网首页Android组件化
Android组件化架构 - 4. 动态创建 & 反射机制

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

作者: 今阳说 | 来源:发表于2020-12-22 20:27 被阅读0次

    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<T> {
            //    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<Int>(), 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<String> pageTitles = new ArrayList<String>();
    
        public static List<String> 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<Class<?extends BaseAppLogic>> logicClassList =new ArrayList<>();
        private List<BaseAppLogic>logicList=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");
        }
    }
    
    我是今阳,如果想要进阶和了解更多的干货,欢迎关注公众号”今阳说“接收我的最新文章

    相关文章

      网友评论

        本文标题:Android组件化架构 - 4. 动态创建 & 反射机制

        本文链接:https://www.haomeiwen.com/subject/brkfnktx.html