从零开始组件化(2)_路由跳转方式和手动搭建组件化路由

本文探讨了组件化应用中如何解决跳转问题,介绍了隐式跳转的局限性和路由跳转的优越性,重点讲述了利用HashMap预编译策略在启动时注册Activity的方法。通过ARoute示例和GitHub代码实现,展示了团队协作中简化组件间路由管理的实践。
摘要由CSDN通过智能技术生成

在上一篇文章组件化-从零开始组件化(1)_z936689039的博客-CSDN博客中,我们已经搭建好整体框架了,然后问题就来了,因为组件化,各个业务组件是互相不依赖的,那假如涉及到跳转,我们应该怎么做呢,目前这块的做法有2种

1.隐式跳转

通过AndroidManifest中对要跳转的activity设置action值,然后跳转的时候,指定对应的action,从而实现跳转的,例如

在要隐式跳转的activity中配置:

//清单文件注册
<activity android:name=".MainActivity"
android:exported="false">
    <intent-filter>
        <action android:name="com.glde.dlr.module_main.MainActivity"/>
        <category android:name="android.intent.category.DEFAULT"/>
    </intent-filter>
</activity>

然后跳转到该activity:

           Intent intent=new Intent();
           intent.setAction("com.glde.dlr.module_main.MainActivity");
          if (LoginActivity.this.getPackageManager().resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY) != null) {
                    intent.addCategory("android.intent.category.DEFAULT");
                    startActivity(intent);
                }

大概就这样子,但是问题也很明显吧,假如你们是2个团队开发,你这跳一个界面,就要人家配置androidManifest,别人肯定不乐意的,所以就有了下面更好的方案了

2.路由跳转

原理借用计算机网络中的路由器概念,将各组件看成不同的局域网,通过路由做中转站,这个中转站可以拦截一些不安全的跳转,或者设定一些特定的拦截服务;

路由和原生跳转的对比:
1. 原生显示跳转是直接的类依赖,耦合严重;路由通过URL索引,无需依赖;
2. 原生隐式跳转通过AndroidManifest集中管理,协作开发困难;路由则是分布式管理页面配置;
3. 原生需要在 AndroidManifest中注册,扩展性差;路由用注解来注册,方便扩展;
4. 原生只要调用了startActivity就交由Android系统控制,过程无法干预,失败无法降级;
路由使用AOP切面编程可以进行控制跳转的过滤,有灵活的降级方式;

阿里那边是开源了一款ARoute来实现这个功能,这个下篇文章在讲,这篇文章主要是为了阐述手动搭建路由框架的目的的,其实咱这个实现也简单,原理就是利用hashMap的存储功能去实现,因为业务组件模块不是都会关联个library_base,嗯,就这个基础库组件,那么我们就可以在这个里头创建个全局的HashMap,里头存储各个界面的路由不就行了,说搞就搞:

public class Aroute {
    private Context mContext;
    private static Map<String,Class<? extends Activity>> map;
    private static Aroute instance;
    public static Aroute getInstance(){
        if(instance==null){
            synchronized (Aroute.class){
                if(instance==null){
                    instance=new Aroute();
                }
                if(map==null){
                    map=new HashMap<>();
                }
            }
        }
        return instance;
    }
  
    public void putActivity(String activityName,Class cls){
        if(!TextUtils.isEmpty(activityName)&&null!=cls){
            map.put(activityName,cls);
        }
    }
    public void startActivity(String activityName, Bundle bundle,Context context){
        Class<? extends Activity> activity=map.get(activityName);
        if(null==activity){
            return;
        }
        Intent intent=new Intent(context,activity);
        if(null!=bundle){
            intent.putExtras(bundle);
        }
        intent.setFlags(FLAG_ACTIVITY_NEW_TASK);
        context.startActivity(intent);
    }
}

其中putActivity,你在要跳转的界面注册就好了,那么问题又来了,我们要跳转的时候,它那个界面还没实例化呀,也就是说根本注册不了,那么怎么办呢?

办法是有的, 我们将它提前编译,原理就是利用AMS中的相关知识点,我们都知道当我们在android Studio编译的时候会打包个apk到手机上,然后系统会创建个apk在用户的手机上,这个apk的路径地址为:

/data/app/app包名/base.apk

 这块对用户来说是不可见的,开发者们可以通过Android studio的Device File Explorer进行访问。

 然后当我们点击应用的时候,实际是加载解压这个文件里头的apk资源,那么就简单了,我们都知道apk实际是个压缩包来的,然后apk下面是好多个dex,其中dex里面是一堆class文件,对此我们就可以利用这点去提前获取到这些class,从而进行对业务组件进行注册

开搞

既然是利用它加载文件的特点的话,那么我们就可以这么做

1.先创建个接口,声明要跳转的界面和开放一个注册方法

public interface IRoute {
    String act_login="LoginActivity";
    String act_main="MainActivity";
    void onPut();
}

2.各个业务组件新建个目录,目录下创建个对象类去实现这个接口

public class LoginRoute implements IRoute {
    @Override
    public void onPut() {
        Aroute.getInstance().putActivity(IRoute.act_login, LoginActivity.class);
    }
}

 3.在app壳层的application中对这个Aroute进行初始化操作,初始化的时候,实际就是执行各个业务组件的onPut方法。具体做法是先通过

getActivityFromPackage获取base.apk下包名为com.glde.dlr.route的所有类集合,然后将它们加载进行内存,并且执行onPut方法
 public void init(Context context){
        mContext=context;
        //获取baseApk(android 打包后的apk)下对应包名为com.glde.dlr.route的所有类集合
        List<String> classNameList=getActivityFromPackage("com.glde.dlr.route");
        for(String className:classNameList){
            try {
                //将类装载进内存
                Class<?> cls= Class.forName(className);
                //判断转载进内存的类是否实现了IRoute接口
                if(IRoute.class.isAssignableFrom(cls)){
                    IRoute iRoute= (IRoute) cls.newInstance();//实例化对象向上转型为IRoute
                    iRoute.onPut();
                }
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            }
        }
    }
    public List<String>  getActivityFromPackage(String packgeName){
        List<String> classList=new ArrayList<>();
        try {
            //mContext.getPackageName()  获取  /data/app/对应包名下的base.apk的文件路径
            String path=mContext.getPackageManager().getApplicationInfo(mContext.getPackageName(),0).sourceDir;
            DexFile dexFile=new DexFile(path);//将baskapk 解压成dex,并且扫描apk中的dex有哪些类
            Enumeration<String> enumeration=dexFile.entries();//获取dexFail中所有类名
            //遍历dex所有类名
            while (enumeration.hasMoreElements()){
                //获取类名
                String className=enumeration.nextElement();
                if(className.startsWith(packgeName)){
                    classList.add(className);
                }
            }
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return classList;
    }
这样的话,就可以了

想要查看完整代码的可以去这里看GitHub - zhi936689039/ComponentizedDemo

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值