MRouter(Android路由)

路由的意義:

  1. 模塊間解耦,不能在代碼中寫死Activity類名。
  2. 動態(tài)配置業(yè)務需求,現(xiàn)在都是業(yè)務模塊化開發(fā)了。

1. 注解

我們這次編寫的MRoute主要使用了編譯時注解技術(shù),注解在我們?nèi)粘J褂玫目蚣苤卸加畜w現(xiàn)。

運行時注解,主要集合反射來完成功能。

編譯時注解,則主要是在編譯階段生成類,來輔助我們后面實現(xiàn)功能。

關(guān)于注解,不做詳細描述。

2. Activity跳轉(zhuǎn)

正常情況下,我們進行Activity跳轉(zhuǎn)是這樣的:

Intent intent=new Intent(this,AnotherActivity.class);
startActivity(intent);

使用路由跳轉(zhuǎn)是這樣的:


MRouter.startActivity(context,url,bundle);

MRouter會根據(jù)傳入的參數(shù)url來查找對應的類,然后完成Activity的跳轉(zhuǎn)。

3. 具體實現(xiàn)

3.1 項目結(jié)構(gòu)

MRoute
|--RouteAnnotation
|
|--RouteProcessor
|
|--RouteApi

3.2 RouteAnnotation

注意該Moudule為Java Library.

RouteAnnotation中定義了MRouter使用的注解Route,具體實現(xiàn)如下:

/**
 * Android路由注解。
 *
 * @author zhangshuai.
 */
@Documented
@Inherited
@Retention(RetentionPolicy.CLASS)
@Target(ElementType.TYPE)
public @interface Route {
    String url() default "";
}

要點解釋:

  1. 因為使用編譯時注解,因此Route的只存在于class中,不是Runtime。
  2. 注解的只能使用在類上。

3.3 RouteCompiler

該Module同樣為Java Library,用于處理注解并生成輔助類。

該項目中定義了注解處理器RouteProcessor,使用了auto-service、javapoet來輔助完成。

下面來看核心類RouteProcessor實現(xiàn):


import core.zs.routeannotation.Route;

@AutoService(Processor.class)
public class RouteProcessor extends AbstractProcessor {
    
    private Filer mFiler;

    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);
        mFiler = processingEnv.getFiler();
    }

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(Route.class);
        TypeSpec spec = processElements(elements);
        try {
            if (spec != null) {
                // 生成Java文件
                // RouteMap.java
                JavaFile.builder("core.zs.route", spec).build().writeTo(mFiler);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return true;
    }

    private TypeSpec processElements(Set<? extends Element> elements) {
        if (elements == null || elements.size() == 0) {
            return null;
        }

        // 1. 構(gòu)造參數(shù),參數(shù)為activityMap
        // 參數(shù)類型為:HashMap<String,Class<?>>
        ParameterizedTypeName mapTypeName =
                ParameterizedTypeName.get(ClassName.get(HashMap.class), ClassName.get(String
                        .class), ClassName.get(Class.class));
        ParameterSpec mapSpec = ParameterSpec.builder(mapTypeName, "activityMap").build();
        
        // 2. 構(gòu)造方法,方法名為initActivityMap
        // 參數(shù)為activityMap
        MethodSpec.Builder initMethodBuilder =
                MethodSpec.methodBuilder("initActivityMap").addModifiers(Modifier.PUBLIC,
                        Modifier.STATIC).addParameter(mapSpec);
        // 3. 處理使用Route注解的類信息
        for (Element element : elements) {
            Route route = element.getAnnotation(Route.class);
            String url = route.url();
            if (null != url && !"".equals(url)) {
                // 在initActivityMap中添加語句
                // activityMap.put(url,xxx.class);
                initMethodBuilder.addStatement("activityMap.put($S,$T.class)", url, ClassName.get
                        ((TypeElement) element));
            }
        }
        // 返回我們構(gòu)造的類元素
        return TypeSpec.classBuilder("RouteMap").addMethod(initMethodBuilder.build())
                .addModifiers(Modifier.PUBLIC).build();
    }

    @Override
    public Set<String> getSupportedAnnotationTypes() {
        Set<String> set = new LinkedHashSet<>();
        set.add(Route.class.getCanonicalName());
        return set;
    }

    @Override
    public SourceVersion getSupportedSourceVersion() {
        return SourceVersion.latestSupported();
    }
}


使用處理器后,會在project的app/build/generated/source/apt/debug/項目名 下生產(chǎn)一個RouteMap.java文件。

其內(nèi)容如下:

package core.zs.router;

import java.lang.Class;
import java.lang.String;
import java.util.HashMap;

public class RouteMap {
  public static void initActivityMap(HashMap<String, Class> activityMap) {
    activityMap.put("/core/zs/TestActivity",TestActivity.class);
  }
}

3.4 RouteApi

注意該Module為Android Library,該Module主要是封裝一些常用的api,供其他項使用。

只有一個類MRouter。


package core.zs.routeapi;

/**
 * Created by ZhangShuai on 2018/6/26.
 */

public class MRouter {

    public static HashMap<String, Class<?>> activityMap = new HashMap<>();

    public static void init(Context context) {
        try {
            // 通過反射來調(diào)用RouteMap的initActivityMap方法,將數(shù)據(jù)保存到activityMap中
            Class clz = Class.forName("core.zs.route.RouteMap");
            if (clz != null) {
                Method initMapMethod = clz.getMethod("initActivityMap", HashMap.class);
                initMapMethod.invoke(null, activityMap);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    // 替換常規(guī)的startActivity方法
    public static void startActivity(Context context, String url, Bundle bundle) {
        if (context == null || url == null) {
            return;
        }
        Class atClazz = activityMap.get(url);
        if (atClazz != null) {
            System.out.println(atClazz.getCanonicalName());
            Intent intent = new Intent(context, atClazz);
            if (bundle != null) {
                intent.putExtras(bundle);
            }
            context.startActivity(intent);
        }else{
            System.out.println("=====Activity is null.");
        }


    }
}

3.5 如何使用

  1. 在Application中初始化
public class MyApp extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        MRouter.init(this);
    }
}
  1. 在Activity上使用Route注解。
@Route(url = "/core/zs/route/RouteActivity")
public class RouteActivity extends AppCompatActivity{
    //....
}

  1. 進行跳轉(zhuǎn)
MRouter.startActivity(MainActivity.this, "/core/zs/route/RouteActivity", null);

4. 總結(jié)

隨著項目的不斷變化,模塊化開發(fā)、組件化開發(fā)逐步被引入,使用MRouter能很好的幫你實現(xiàn)業(yè)務之間的解耦,實現(xiàn)業(yè)務之間的簡單配置、順利跳轉(zhuǎn)。

奉上源碼地址MRouter。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 178,720評論 25 709
  • Android組件化項目地址:Android組件化項目AndroidModulePattern Android組件...
    半灬邊灬天閱讀 2,996評論 4 37
  • 夜幕降臨,陰沉沉的天空開始飄落起入秋以來第n場秋雨。 吃過晚飯,我們照例在客廳玩耍嬉戲。兒子現(xiàn)在特黏電視,吃過飯自...
    八七在路上閱讀 234評論 1 5
  • 本文主要介紹怎么在Thinkphp中集成后臺前端腳手架框架Vue-Cli。 一.安裝Vue-Cli到Thinkph...
    風殤嶄往閱讀 7,882評論 1 13
  • 2009-08-18 00:42:33 盛夏時光,陽光明媚。 遇見你。 也許是我多情 暗生情愫。 愛,要怎么說出口...
    國王的心事閱讀 385評論 0 1

友情鏈接更多精彩內(nèi)容