仿写Arouter框架实现Activity的跳转

Arouter 框架是主要由三个模块组成,annotation,compiler,core.

annotation :自定义注解,用来声明需要路由的页面(Java Library)

compiler :注解解析,在编译时根据自定义注解生成注册路由表的java类(Java Library)。

core : 实现路由跳转功能,供Android调用(Android Library)

先上工程结构图

仿写Arouter框架实现Activity的跳转

一、annotation模块

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

仿写Arouter框架实现Activity的跳转

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

仿写Arouter框架实现Activity的跳转

二、compiler模块

  1. 首先导入依赖的第三方库,compiler模块使用javax的Processor类来解析注解,auto-service自动编译Processor类,使用javapoet库生成java类。
仿写Arouter框架实现Activity的跳转
  1. 新建RouterProcessor继承AbstractProcessor类,添加如下注解
仿写Arouter框架实现Activity的跳转

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

仿写Arouter框架实现Activity的跳转

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

仿写Arouter框架实现Activity的跳转

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

仿写Arouter框架实现Activity的跳转
仿写Arouter框架实现Activity的跳转

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

仿写Arouter框架实现Activity的跳转

三、core模块

  1. 定义一个路由表保存所有的路由信息
仿写Arouter框架实现Activity的跳转
  1. 然后,遍历所有的dex文件,查找所有的使用javapoet生成的分组信息类和表信息类。查找是一个耗时操作,使用ThreadPoolExecutor维护一个线程池,来查找所有包名为com.hc.androiddemo.routes 类,并使用使用同步计数器来判断查找是否完成。然后将分组信息类加入Warehouse的groupsIndex中
仿写Arouter框架实现Activity的跳转
仿写Arouter框架实现Activity的跳转

四、跳卡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文件目录如下
仿写Arouter框架实现Activity的跳转

项目地址:稍后上传!

原文 

https://juejin.im/post/5efc446cf265da22c7572b63

本站部分文章源于互联网,本着传播知识、有益学习和研究的目的进行的转载,为网友免费提供。如有著作权人或出版方提出异议,本站将立即删除。如果您对文章转载有任何疑问请告之我们,以便我们及时纠正。

PS:推荐一个微信公众号: askHarries 或者qq群:474807195,里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多

转载请注明原文出处:Harries Blog™ » 仿写Arouter框架实现Activity的跳转

赞 (0)
分享到:更多 ()

评论 0

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址