日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android组件化专题-路由动态注入跳转参数以及获取其他模块的fragment

發布時間:2024/1/17 Android 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android组件化专题-路由动态注入跳转参数以及获取其他模块的fragment 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

上幾篇組件化專題文章,我們對路由框架基本實現了,Activity之間當跳轉和模塊間當通信。

現在思考一個問題: 不管是在Activity或者Fragment,跳轉都會傳遞一些參數,然后在對應對Activity或著Fragment獲取對應對參數,都要寫大量重復的代碼,然而我們作為一名有素質有夢想的碼農,我們是不可以做這種搬磚的操作的,不想當大牛當碼農不是好碼農。

那么我們如何用優雅的代碼,解決這個問題呢?請看下面分解

路由動態注入跳轉參數

原生的獲取intent跳轉傳遞過來的參數:

Intent intent = getIntent(); final String path = intent.getStringExtra("path"); ...... 復制代碼

同時還有fragment的參數傳遞等。

如果稍微進行一些封裝的話可以這樣寫:

public class MainActivityExtra {public static void loadExtra(Main2Activity main2Activity) {Intent intent = main2Activity.getIntent();main2Activity.path = intent.getStringExtra("path");......} }復制代碼

上述不管哪種寫法,都是相當麻煩和大量的重復代碼。

最為一名有夢想的碼農,我理想中的寫法:

在相應的Activity,通過一個注解就可以拿到跳轉傳遞過來的參數的值,然后直接使用。

@Extra public String path; 復制代碼

那么我們如何實現呢? 其實很簡單,我們通過注解拿到父類Activity,然后注解變量的類型和名稱,然后我們動態生成一個類,通過原生的方式來實現參數獲取。

其實跟上幾篇的文章是一樣的原理,這里就不再多復述了這是鏈接組件化專題

下面就直接一堆代碼,拋給你

  • 首先聲明注解
  • @Target(ElementType.FIELD) @Retention(RetentionPolicy.CLASS) public @interface Extra {String name() default ""; } 復制代碼
  • 注解處理器處理注解,這里面的邏輯其實非常簡單,主要是看你對APT使用是不是熟練
  • @AutoService(Processor.class) @SupportedSourceVersion(SourceVersion.RELEASE_7) @SupportedAnnotationTypes({Consts.EXTRA_NAME}) @SupportedOptions({Consts.ARGUMENTS_NAME}) public class ExtraProcessor extends AbstractProcessor {/*** key:類節點 value:需要注入的屬性節點集合*/private Map<TypeElement, List<Element>> extraMap = new HashMap<>();private Elements elementUtils;private Types typeUtils;private Filer filer;private Log log;private Messager messager;@Overridepublic synchronized void init(ProcessingEnvironment processingEnvironment) {super.init(processingEnvironment);elementUtils = processingEnvironment.getElementUtils();typeUtils = processingEnvironment.getTypeUtils();filer = processingEnvironment.getFiler();messager = processingEnvironment.getMessager();log = Log.newLog(messager);}@Overridepublic boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {if (null != set && !set.isEmpty()) {//注意這里必須要判斷set.isEmpty() 否則會走兩遍log.i("process");//拿到注有Extra 的節點集合Set<? extends Element> elementsAnnotatedWith = roundEnvironment.getElementsAnnotatedWith(Extra.class);if (null != elementsAnnotatedWith) {try {saveExtras(elementsAnnotatedWith);generateExtras();} catch (Exception e) {e.printStackTrace();}}return true;}return false;}/*** 保存節點的信息** @param elementsAnnotatedWith*/private void saveExtras(Set<? extends Element> elementsAnnotatedWith) {for (Element element : elementsAnnotatedWith) {//獲取注解父類的節點類型TypeElement enclosingElement = (TypeElement) element.getEnclosingElement();if (extraMap.containsKey(enclosingElement)) {extraMap.get(enclosingElement).add(element);} else {List<Element> list = new ArrayList<>();list.add(element);extraMap.put(enclosingElement, list);}}}private MethodSpec.Builder builder;private TypeMirror parcelableType;private TypeMirror iServiceType;private TypeElement extraElement;private TypeMirror activity;/*** 生成表*/private void generateExtras() {//支持Activity和Fragmentactivity = elementUtils.getTypeElement(Consts.Activity).asType();extraElement = elementUtils.getTypeElement(Consts.Extra);parcelableType = elementUtils.getTypeElement(Consts.PARCELABLE).asType();iServiceType = elementUtils.getTypeElement(Consts.Service).asType();log.i("generateExtras");//參數ParameterSpec target = ParameterSpec.builder(TypeName.OBJECT, "target").build();if (!Utils.isEmpty(extraMap)) {//遍歷被Extra注解屬性的類for (Map.Entry<TypeElement, List<Element>> entry : extraMap.entrySet()) {TypeElement classType = entry.getKey();log.i("isSubtype:" + typeUtils.isSubtype(classType.asType(), activity) + " | " + classType.asType());if (typeUtils.isSubtype(classType.asType(), activity)) {generateClass(target, entry, classType);} else {throw new RuntimeException("[Just Support Activity Field] : " + classType + " --> " + typeUtils.isSubtype(classType.asType(), activity));}}}}public void generateClass(ParameterSpec target, Map.Entry<TypeElement, List<Element>> entry, TypeElement classType) {builder = MethodSpec.methodBuilder(Consts.EXTRA_METHOD_NAME)//方法名.addAnnotation(Override.class)//注解.addModifiers(Modifier.PUBLIC)//作用域.addParameter(target);//添加參數log.i("generate method");//設置函數體addFuncationBody(entry, classType);log.i("generate type");//生成Java類TypeSpec typeSpec = TypeSpec.classBuilder(classType.getSimpleName() + "$$Extra").addSuperinterface(ClassName.get(extraElement)).addModifiers(Modifier.PUBLIC).addMethod(builder.build()).build();try {//生成Java類文件log.i("package name:" + ClassName.get(classType).packageName());JavaFile.builder(ClassName.get(classType).packageName(), typeSpec).build().writeTo(filer);} catch (IOException e) {e.printStackTrace();log.i("package name error");}}private void addFuncationBody(Map.Entry<TypeElement, List<Element>> entry, TypeElement classType) {for (Element element : entry.getValue()) {//$T t = ($T)targetbuilder.addStatement("$T t = ($T)target", classType, classType);//遍歷注解節點 生成函數體TypeMirror typeMirror = element.asType();//獲取注解節點的類型//獲取TypeKind 枚舉類型的序列號int type = typeMirror.getKind().ordinal();//獲取屬性名String fieldName = element.getSimpleName().toString();//獲取注解的值String extraName = element.getAnnotation(Extra.class).name();//判斷直接的值為空的情況下的處理extraName = Utils.isEmpty(extraName) ? fieldName : extraName;String defaultValue = "t." + fieldName;String statement = defaultValue + " = t.getIntent().";if (type == TypeKind.BOOLEAN.ordinal()) {statement += "getBooleanExtra($S, " + defaultValue + ")";} else if (type == TypeKind.BYTE.ordinal()) {statement += "getByteExtra($S, " + defaultValue + ")";} else if (type == TypeKind.SHORT.ordinal()) {statement += "getShortExtra($S, " + defaultValue + ")";} else if (type == TypeKind.INT.ordinal()) {statement += "getIntExtra($S, " + defaultValue + ")";} else if (type == TypeKind.LONG.ordinal()) {statement += "getLongExtra($S, " + defaultValue + ")";} else if (type == TypeKind.CHAR.ordinal()) {statement += "getCharExtra($S, " + defaultValue + ")";} else if (type == TypeKind.FLOAT.ordinal()) {statement += "getFloatExtra($S, " + defaultValue + ")";} else if (type == TypeKind.DOUBLE.ordinal()) {statement += "getDoubleExtra($S, " + defaultValue + ")";} else {//數組類型if (type == TypeKind.ARRAY.ordinal()) {addArrayStatement(statement, fieldName, extraName, typeMirror, element);} else {//ObjectaddObjectStatement(statement, fieldName, extraName, typeMirror, element);}return;}log.i("generate statement:" + statement);builder.addStatement(statement, extraName);}}/*** 添加對象 String/List/Parcelable** @param statement* @param extraName* @param typeMirror* @param element*/private void addObjectStatement(String statement, String fieldName, String extraName,TypeMirror typeMirror,Element element) {//Parcelableif (typeUtils.isSubtype(typeMirror, parcelableType)) {statement += "getParcelableExtra($S)";} else if (typeMirror.toString().equals(Consts.STRING)) {statement += "getStringExtra($S)";} else if (typeUtils.isSubtype(typeMirror, iServiceType)) { // TestService testService = (TestService) DNRouter.getInstance().build("/main/service1") // .navigation(); // testService.test();statement = "t." + fieldName + " = ($T) $T.getInstance().build($S).navigation()";builder.addStatement(statement, TypeName.get(element.asType()), Consts.ROUTER,extraName);return;} else {//ListTypeName typeName = ClassName.get(typeMirror);//泛型if (typeName instanceof ParameterizedTypeName) {//list 或 arraylistClassName rawType = ((ParameterizedTypeName) typeName).rawType;//泛型類型List<TypeName> typeArguments = ((ParameterizedTypeName) typeName).typeArguments;if (!rawType.toString().equals(Consts.ARRAYLIST) && !rawType.toString().equals(Consts.LIST)) {throw new RuntimeException("Not Support Inject Type:" + typeMirror + " " +element);}if (typeArguments.isEmpty() || typeArguments.size() != 1) {throw new RuntimeException("List Must Specify Generic Type:" + typeArguments);}TypeName typeArgumentName = typeArguments.get(0);TypeElement typeElement = elementUtils.getTypeElement(typeArgumentName.toString());// Parcelable 類型if (typeUtils.isSubtype(typeElement.asType(), parcelableType)) {statement += "getParcelableArrayListExtra($S)";} else if (typeElement.asType().toString().equals(Consts.STRING)) {statement += "getStringArrayListExtra($S)";} else if (typeElement.asType().toString().equals(Consts.INTEGER)) {statement += "getIntegerArrayListExtra($S)";} else {throw new RuntimeException("Not Support Generic Type : " + typeMirror + " " +element);}} else {throw new RuntimeException("Not Support Extra Type : " + typeMirror + " " +element);}}builder.addStatement(statement, extraName);}/*** 添加數組** @param statement* @param fieldName* @param typeMirror* @param element*/private void addArrayStatement(String statement, String fieldName, String extraName, TypeMirrortypeMirror, Element element) {//數組switch (typeMirror.toString()) {case Consts.BOOLEANARRAY:statement += "getBooleanArrayExtra($S)";break;case Consts.INTARRAY:statement += "getIntArrayExtra($S)";break;case Consts.SHORTARRAY:statement += "getShortArrayExtra($S)";break;case Consts.FLOATARRAY:statement += "getFloatArrayExtra($S)";break;case Consts.DOUBLEARRAY:statement += "getDoubleArrayExtra($S)";break;case Consts.BYTEARRAY:statement += "getByteArrayExtra($S)";break;case Consts.CHARARRAY:statement += "getCharArrayExtra($S)";break;case Consts.LONGARRAY:statement += "getLongArrayExtra($S)";break;case Consts.STRINGARRAY:statement += "getStringArrayExtra($S)";break;default://Parcelable 數組String defaultValue = "t." + fieldName;//object數組 componentType獲得object類型ArrayTypeName arrayTypeName = (ArrayTypeName) ClassName.get(typeMirror);TypeElement typeElement = elementUtils.getTypeElement(arrayTypeName.componentType.toString());//是否為 Parcelable 類型if (!typeUtils.isSubtype(typeElement.asType(), parcelableType)) {throw new RuntimeException("Not Support Extra Type:" + typeMirror + " " +element);}statement = "$T[] " + fieldName + " = t.getIntent()" +".getParcelableArrayExtra" +"($S)";builder.addStatement(statement, parcelableType, extraName);builder.beginControlFlow("if( null != $L)", fieldName);statement = defaultValue + " = new $T[" + fieldName + ".length]";builder.addStatement(statement, arrayTypeName.componentType).beginControlFlow("for (int i = 0; i < " + fieldName + "" +".length; " +"i++)").addStatement(defaultValue + "[i] = ($T)" + fieldName + "[i]",arrayTypeName.componentType).endControlFlow();builder.endControlFlow();return;}builder.addStatement(statement, extraName);} }復制代碼

    其實上面的注解處理器,會動態生成這樣的一個類

    public class Main2Activity$$Extra implements IExtra {@Overridepublic void loadExtra(Object target) {Main2Activity t = (Main2Activity)target;t.path = t.getIntent().getStringExtra("path");} } 復制代碼
  • 通過一個API去加載這個類
  • public void loadExtra(Activity activity) {String name = activity.getClass().getName();IExtra iExtra = extraLruCache.get(name);try {if (iExtra == null) {iExtra = (IExtra) Class.forName(activity.getClass().getName() + "$$Extra").getConstructor().newInstance();}iExtra.loadExtra(activity);extraLruCache.put(name, iExtra);} catch (Exception e) {e.printStackTrace();}} 復制代碼
  • 具體的調用實現
  • public class ModuleTest2Activity extends AppCompatActivity {@Extra(name = "path")public String url;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_module_test2);PrimRouter.getInstance().inject(this);TextView module2_textView = findViewById(R.id.module2_textView); // Intent intent = getIntent(); // final String path = intent.getStringExtra("path");module2_textView.setText("我是module2,我的地址是:/module2/test. 我是被地址:" + url + " 調起的");} } 復制代碼

    這樣處理不僅大大提高了編碼效率還減少了大量重復的代碼,也提高了程序的可讀性.

    實現fragment的跳轉

    這里我們需要在原來的基礎上,加幾句代碼。代碼地址

    //拿到fragment的全類名 TypeElement fragment = elementUtils.getTypeElement(Consts.Fragment);TypeElement v4Fragment = elementUtils.getTypeElement(Consts.V4Fragment);//單個的節點for (Element element : annotatedWith) {// 獲取類信息 如Activity類TypeMirror typeMirror = element.asType();// 獲取節點的注解信息Router annotation = element.getAnnotation(Router.class);log.i(typeMirror + " | " + activity.asType());//只能指定的類上面使用if (typeUtils.isSubtype(typeMirror, activity.asType())) {//存儲路由相關的信息routerMeta = new RouterMeta(RouterMeta.Type.ACTIVITY, annotation, element);} else if (typeUtils.isSubtype(typeMirror, service.asType())) {//存儲路由相關的信息routerMeta = new RouterMeta(RouterMeta.Type.SERVICE, annotation, element);} else if (typeUtils.isSubtype(typeMirror, fragment.asType()) || typeUtils.isSubtype(typeMirror, v4Fragment.asType())) {//存儲路由相關的信息routerMeta = new RouterMeta(RouterMeta.Type.FRAGMENT, annotation, element);} else {throw new RuntimeException("Just Support Activity Router!");}//檢查是否配置group如果沒有配置 則從path中截取組名checkRouterGroup(routerMeta);} 復制代碼

    然后在我們的API庫,返回fragment

    case FRAGMENT:Class<?> fragment = jumpCard.getDestination();try {Object instance = fragment.getConstructor().newInstance();if (instance instanceof Fragment) {((Fragment) instance).setArguments(jumpCard.getExtras());} else if (instance instanceof android.support.v4.app.Fragment) {((android.support.v4.app.Fragment) instance).setArguments(jumpCard.getExtras());}return instance;} catch (Exception e) {e.printStackTrace();} 復制代碼

    實現效果如下:

    到此為止,我們的路由框架實現了以下功能: 支持直接解析標準URL路由地址進行跳轉,并自動注入參數到目標頁面中 支持多模塊工程使用 支持模塊間的通信 支持獲取其他模塊的fragment

    Android的組件化專題: 組件化配置

    APT實戰

    路由框架原理

    模塊間的業務通信

    總結

    以上是生活随笔為你收集整理的Android组件化专题-路由动态注入跳转参数以及获取其他模块的fragment的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。