美文网首页Android开发
仿写Arouter框架实现Activity的跳转

仿写Arouter框架实现Activity的跳转

作者: Android进阶架构 | 来源:发表于2020-07-01 22:24 被阅读0次

    Arouter 框架是主要由三个模块组成,annotation,compiler,core.
    annotation :自定义注解,用来声明需要路由的页面(Java Library)
    compiler :注解解析,在编译时根据自定义注解生成注册路由表的java类(Java Library)。
    core : 实现路由跳转功能,供Android调用(Android Library)

    先上工程结构图


    一、annotation模块

    新建一个文件,编写一个注解,声明路由路径


    RouteMeta保存路由信息,通过解析注解获取。


    二、compiler模块

    1. 首先导入依赖的第三方库,compiler模块使用javax的Processor类来解析注解,auto-service自动编译Processor类,使用javapoet库生成java类。


    2. 新建RouterProcessor继承AbstractProcessor类,添加如下注解



      初始化RouterProcessor,在process方法中遍历Route注解的节点,如果不为null,进行解析



      获取Activity类的节点信息,然后循环,判断是Activity类型的节点,新建RouteMeta对象保存节点信息。然后调用categories()验证节点的路由地址是否符合规则,再根据分组名保存节点到groupMap中

      遍历groupMap中的节点信息,使用javapoet工具生成一个继承IRouteGroup接口的java类,用来保存每个分组的路由信息。叫分组信息类。




      然后遍历所有的分组信息类,生成继承IRouteRoot接口的表信息类,保存分组名对应的分组信息类。

    三、core模块

    1. 定义一个路由表保存所有的路由信息


    2. 然后,遍历所有的dex文件,查找所有的使用javapoet生成的分组信息类和表信息类。查找是一个耗时操作,使用ThreadPoolExecutor维护一个线程池,来查找所有包名为com.hc.androiddemo.routes 类,并使用使用同步计数器来判断查找是否完成。然后将分组信息类加入Warehouse的groupsIndex中



    四、跳卡PostCard

    Postcard继承RouteMeta类,保存路由地址、分组名以及要传递的数据。使用Postcard的with方法添加传递的数据,调用Postcard的navigation()进行页面跳转

    public class Postcard extends RouteMeta {
        private Bundle mBundle;
        //新版风格
        private Bundle optionsCompat;
        private int flags = -1;
        public Postcard(String path, String group) {
            this(path, group, null);
        }
    
        public Postcard(String path, String group, Bundle bundle) {
            setPath(path);
            setGroup(group);
            this.mBundle = (null == bundle ? new Bundle() : bundle);
        }
    
        public Bundle getExtras() {return mBundle;}
    
        public Bundle getOptionsBundle() {
            return optionsCompat;
        }
        /**
         * Intent.FLAG_ACTIVITY**
         * @param flag
         * @return
         */
        public Postcard withFlags(int flag) {
            this.flags = flag;
            return this;
        }
    
        public Postcard withString(String key,String value){
            mBundle.putString(key,value);
            return this;
        }
    
        public Postcard withInt(String key,int value){
            mBundle.putInt(key,value);
            return this;
        }
    
        public Postcard withBoolean(String key,boolean value){
            mBundle.putBoolean(key,value);
            return this;
        }
    
        public int getFlags() {
            return flags;
        }
    
        public Object navigation() {
            return ToolRouter.getInstance().navigation(null, this, -1, null);
        }
    
        public Object navigation(Context context) {
            return ToolRouter.getInstance().navigation(context, this, -1, null);
        }
    
        public Object navigation(Context context, NavigationCallback callback) {
            return ToolRouter.getInstance().navigation(context, this, -1, callback);
        }
    
        public Object navigation(Context context, int requestCode) {
            return ToolRouter.getInstance().navigation(context, this, requestCode, null);
        }
    
        public Object navigation(Context context, int requestCode, NavigationCallback callback) {
            return ToolRouter.getInstance().navigation(context, this, requestCode, callback);
        }
    }
    

    五、跳转页面

    调用Postcard的navigation()进行跳转。

     protected Object navigation(Context context, final Postcard postcard, final int requestCode,
                                    final NavigationCallback callback) {
            try {
                //准备卡片,路由信息
                prepareCard(postcard);
            } catch (NoRouteFoundException e) {
                e.printStackTrace();
                if (null != callback) {
                    callback.onLost(postcard);
                }
                return null;
            }
            if (null != callback) {
                callback.onFound(postcard);
            }
            switch (postcard.getType()) {
                case ACTIVITY:
                    final Context currentContext = null == context ? mContext : context;
                    final Intent intent = new Intent(currentContext, postcard.getDestination());
                    intent.putExtras(postcard.getExtras());
                    int flags = postcard.getFlags();
                    if (-1 != flags) {
                        intent.setFlags(flags);
                    } else if (!(currentContext instanceof Activity)) {
                        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    }
                    mHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            //带返回码
                            if(requestCode > 0 ){
                                ActivityCompat.startActivityForResult((Activity) currentContext,intent,requestCode,postcard.getExtras());
                            }else {
                                ActivityCompat.startActivity(currentContext,intent,postcard.getExtras());
                            }
                            if(null != callback){
                                callback.onArrival(postcard);
                            }
                        }
                    });
                    break;
            }
            return null;
        }
    

    先准备路由的卡片信息,如果没有准备路由信息,根据分组名从Warehouse的groupsIndex中找到分组信息类,加载对应路由表的信息。这里实现了按需加载。获取到路由信息后,设置postcard的信息。再调用startActivity来跳转

    private void prepareCard(Postcard postcard) {
            RouteMeta routeMeta = Warehouse.routes.get(postcard.getPath());
            if (null == routeMeta) {//还没有准备信息
                //创建并调用 loadinto 函数  然后记录在仓库
                Class<? extends IRouteGroup> groupMeta = Warehouse.groupsIndex.get(postcard
                        .getGroup());
                if (null == groupMeta) {
                    throw new NoRouteFoundException("没找到对应路由: " + postcard.getGroup() + " " +
                            postcard.getPath());
                }
                IRouteGroup iGroupInstance = null;
                try {
                    iGroupInstance = groupMeta.getConstructor().newInstance();
                } catch (Exception e) {
                    e.printStackTrace();
                }
                iGroupInstance.loadInto(Warehouse.routes);
                //已经准备过了就可以移除了
                Warehouse.groupsIndex.remove(postcard.getGroup());
                //再次进入else
                prepareCard(postcard);
            } else {
                //获取要跳转的activity
                postcard.setDestination(routeMeta.getDestination());
                postcard.setType(routeMeta.getType());
    //            switch (routeMeta.getType()){
    //
    //            }
            }
        }
    

    六、使用

    1. 在Application中进行初始化
    public class App extends Application {
        @Override
        public void onCreate() {
            super.onCreate();
            initToolRouter();
        }
    
        private void initToolRouter() {
            ToolRouter.init(this);
        }
    }
    

    2.在FirstActivity 和MainActivity中添加注解,在MainActivity中点击按钮进行跳转

    @Route(path = "/demo1/fisrtActivity")
    public class FirstActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_first);
        }
    }
    
    @Route(path = "/demo2/MainActivity")
    public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    
        private Button jump_btn;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            jump_btn = findViewById(R.id.jump_btn);
            jump_btn.setOnClickListener(this);
        }
    
        @Override
        public void onClick(View v) {
            switch (v.getId()) {
                case R.id.jump_btn:
                    ToolRouter.getInstance().build("/demo1/fisrtActivity")
                            .navigation();
                    break;
            }
        }
    }
    
    1. 编译期生成的java文件目录如下


    在这里我也分享自己收录整理的Android学习PDF,里面对仿写Arouter框架实现Activity的跳转讲解,希望可以帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,可以分享给身边好友一起学习

    有需要的朋友可以点赞+评论+转发,关注我,然后简信我【666】获取

    相关文章

      网友评论

        本文标题:仿写Arouter框架实现Activity的跳转

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