仿寫Arouter框架實現Activity的跳轉

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;
        }
    }
}

3.編譯期生成的java文件目錄如下

在這裏我也分享自己收錄整理的Android學習PDF,裏面對仿寫Arouter框架實現Activity的跳轉講解,希望可以幫助大家學習提升進階,也節省大家在網上搜索資料的時間來學習,可以分享給身邊好友一起學習

有需要的朋友可以點贊+評論+轉發,關注我,然後私信我【666】獲取

也可以加入粉絲羣獲取:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章