在上一篇文章组件化-从零开始组件化(1)_z936689039的博客-CSDN博客中,我们已经搭建好整体框架了,然后问题就来了,因为组件化,各个业务组件是互相不依赖的,那假如涉及到跳转,我们应该怎么做呢,目前这块的做法有2种
通过AndroidManifest中对要跳转的activity设置action值,然后跳转的时候,指定对应的action,从而实现跳转的,例如
在要隐式跳转的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,别人肯定不乐意的,所以就有了下面更好的方案了
原理借用计算机网络中的路由器概念,将各组件看成不同的局域网,通过路由做中转站,这个中转站可以拦截一些不安全的跳转,或者设定一些特定的拦截服务;
路由和原生跳转的对比:
1. 原生显示跳转是直接的类依赖,耦合严重;路由通过URL索引,无需依赖;
2. 原生隐式跳转通过AndroidManifest集中管理,协作开发困难;路由则是分布式管理页面配置;
3. 原生需要在 AndroidManifest中注册,扩展性差;路由用注解来注册,方便扩展;
4. 原生只要调用了startActivity就交由Android系统控制,过程无法干预,失败无法降级;
路由使用AOP切面编程可以进行控制跳转的过滤,有灵活的降级方式;
阿里那边是开源了一款ARoute来实现这个功能,这个下篇文章在讲,这篇文章主要是为了阐述手动搭建路由框架的目的的,其实咱这个实现也简单,原理就是利用hashMap的存储功能去实现,因为业务组件模块不是都会关联个library_base,嗯,就这个基础库组件,那么我们就可以在这个里头创建个全局的HashMap,里头存储各个界面的路由不就行了,说搞就搞:
public class Aroute {
private Context mContext;
private static Map> 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 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 getActivityFromPackage(String packgeName){
List 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 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