Android 組件化】路由組件 ( 頁面跳轉參數依賴注入 )

      網友投稿 801 2025-04-01

      文章目錄

      一、參數自動注入

      二、自定義注解

      三、使用 @Extra 自定義注解

      四、注解處理器解析 @Extra 自定義注解 并生成相應 Activity 對應代碼

      五、博客資源

      組件化系列博客 :

      【Android 組件化】從模塊化到組件化

      【Android 組件化】使用 Gradle 實現組件化 ( Gradle 變量定義與使用 )

      【Android 組件化】使用 Gradle 實現組件化 ( 組件模式與集成模式切換 )

      【Android 組件化】使用 Gradle 實現組件化 ( 組件 / 集成模式下的 Library Module 開發 )

      【Android 組件化】路由組件 ( 路由組件結構 )

      【Android 組件化】路由組件 ( 注解處理器獲取被注解的節點 )

      【Android 組件化】路由組件 ( 注解處理器中使用 JavaPoet 生成代碼 )

      【Android 組件化】路由組件 ( 注解處理器參數選項設置 )

      【Android 組件化】路由組件 ( 構造路由表中的路由信息 )

      【Android 組件化】路由組件 ( 使用 JavaPoet 生成路由表類 )

      【Android 組件化】路由組件 ( 組件間共享的服務 )

      【Android 組件化】路由組件 ( 生成 Root 類記錄模塊中的路由表 )

      【Android 組件化】路由組件 ( 運行時獲取 注解處理器 生成的路由表 )

      【Android 組件化】路由組件 ( 路由框架概述 )

      【Android 組件化】路由組件 ( 頁面跳轉參數傳遞注解 )

      一、參數自動注入

      在 組件化 中 , 使用 路由組件 進行界面跳轉時 , 涉及到參數的傳遞 , 傳遞過去的參數需要在目的地 Activity 的 onCreate 方法中 , 調用 getIntent().getXxxExtra() 獲取到傳遞的值 ;

      如果一次性傳遞 十幾個 , 乃至幾十個參數 , 這樣就需要寫很多次 getIntent().getXxxExtra() 樣式的代碼 , 這里引入注入框架 , 類似于 ButterKnife , 只要在目的 Activity 中的成員屬性上標注注解 , 可以自動生成 getIntent().getXxxExtra() 相關邏輯 , 開發者不必手動編寫此類邏輯 ;

      ButterKnife 的作用是在 Activity 的成員屬性上標注 @BindView 注解 , 自動生成 findViewById 代碼 ;

      二、自定義注解

      自定義 Extra 注解 ,

      @Target({ElementType.FIELD}) 元注解表示該注解用于標注成員字段 ,

      @Retention(RetentionPolicy.CLASS) 元注解表示該注解保留到字節碼編譯時 ,

      注解中定義了一個注解屬性 name , 默認值為 “” ;

      自定義注解代碼示例 :

      package kim.hsl.router_annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * 參數自動注入注解 * 該注解使用在 成員字段 上面 */ @Target({ElementType.FIELD}) @Retention(RetentionPolicy.CLASS) public @interface Extra { /** * 參數名稱 * @return */ String name() default ""; }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      三、使用 @Extra 自定義注解

      在 Activity 中 , 使用 @Route 和 @Extra 自定義注解 ;

      package kim.hsl.library3; import android.os.Bundle; import com.google.android.material.floatingactionbutton.FloatingActionButton; import com.google.android.material.snackbar.Snackbar; import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.widget.Toolbar; import android.view.View; import kim.hsl.router_annotation.Extra; import kim.hsl.router_annotation.Route; @Route(path = "/library3/MainActivity") public class MainActivity extends AppCompatActivity { /** * 姓名 */ @Extra private String name; /** * 年齡 */ @Extra private int age; /** * 身高 */ @Extra private int height; /** * 體重 */ @Extra private int weight; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Toolbar toolbar = findViewById(R.id.toolbar); } }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      25

      26

      27

      28

      29

      30

      31

      32

      33

      34

      35

      36

      37

      38

      39

      40

      41

      42

      43

      44

      45

      46

      47

      48

      49

      50

      四、注解處理器解析 @Extra 自定義注解 并生成相應 Activity 對應代碼

      注解處理器中解析上述注解 , 生成如下代碼 , 生成代碼位置 " D:

      注解處理器中解析上述注解 , 生成如下代碼 , 生成代碼位置 " D:\002_Project\002_Android_Learn\Component\library3\build\generated\ap_generated_sources\debug\out\kim\hsl\library3\MainActivity_Extra.java "

      2_Project

      注解處理器中解析上述注解 , 生成如下代碼 , 生成代碼位置 " D:\002_Project\002_Android_Learn\Component\library3\build\generated\ap_generated_sources\debug\out\kim\hsl\library3\MainActivity_Extra.java "

      2_Android_Learn\Component\library3\build\generated\ap_generated_sources\debug\out\kim\hsl\library3\MainActivity_Extra.java "

      package kim.hsl.library3; import java.lang.Object; import java.lang.Override; import kim.hsl.route_core.template.IExtra; public class MainActivity_Extra implements IExtra { @Override public void loadExtra(Object target) { MainActivity t = (MainActivity)target; t.name = t.getIntent().getStringExtra("name"); t.age = t.getIntent().getIntExtra("age", t.age); t.height = t.getIntent().getIntExtra("height", t.height); t.weight = t.getIntent().getIntExtra("weight", t.weight); } }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      生成上述代碼的注解處理器 :

      package kim.hsl.router_compiler; import com.google.auto.service.AutoService; import com.squareup.javapoet.ArrayTypeName; import com.squareup.javapoet.ClassName; import com.squareup.javapoet.JavaFile; import com.squareup.javapoet.MethodSpec; import com.squareup.javapoet.ParameterSpec; import com.squareup.javapoet.ParameterizedTypeName; import com.squareup.javapoet.TypeName; import com.squareup.javapoet.TypeSpec; import com.squareup.javapoet.WildcardTypeName; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeMap; import javax.annotation.processing.AbstractProcessor; import javax.annotation.processing.Filer; import javax.annotation.processing.Messager; import javax.annotation.processing.ProcessingEnvironment; import javax.annotation.processing.Processor; import javax.annotation.processing.RoundEnvironment; import javax.annotation.processing.SupportedAnnotationTypes; import javax.annotation.processing.SupportedOptions; import javax.annotation.processing.SupportedSourceVersion; import javax.lang.model.SourceVersion; import javax.lang.model.element.Element; import javax.lang.model.element.Modifier; import javax.lang.model.element.TypeElement; import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; import javax.lang.model.util.Elements; import javax.lang.model.util.Types; import javax.tools.Diagnostic; import kim.hsl.router_annotation.Extra; import kim.hsl.router_annotation.Route; import kim.hsl.router_annotation.model.RouteBean; import static javax.lang.model.element.Modifier.PUBLIC; // 注解處理器接收的參數 @SupportedOptions("moduleName") // 自動注冊注解處理器 @AutoService(Processor.class) // 支持的注解類型 @SupportedAnnotationTypes({"kim.hsl.router_annotation.Extra"}) // 支持的 Java 版本 @SupportedSourceVersion(SourceVersion.RELEASE_8) public class ExtraProcessor extends AbstractProcessor { /** * 注解處理器中使用 Messager 對象打印日志 */ private Messager mMessager; /** * 用于寫出生成的 Java 代碼 */ private Filer mFiler; /** * 注解節點工具 */ private Elements mElementUtils; /** * 類工具 */ private Types mTypeUtils; /** * 獲取的 moduleName 參數 */ private String mModuleName; /** * 獲取所有需要注入的節點集合 , 并按照其父節點 Activity 進行分組 * 鍵 ( Key ) : Activity 節點 * 值 ( Value ) : Activity 中被 @Extra 注解的屬性節點 */ private Map> mActivity2Field = new HashMap<>(); /** * 該函數在初始化時調用 , 相當于構造函數 * @param processingEnvironment */ @Override public synchronized void init(ProcessingEnvironment processingEnvironment) { super.init(processingEnvironment); // 獲取打印日志接口 this.mMessager = processingEnvironment.getMessager(); // 測試日志打印 mMessager.printMessage(Diagnostic.Kind.NOTE, "ExtraProcessor : Messager Print Log"); this.mFiler = processingEnvironment.getFiler(); this.mElementUtils = processingEnvironment.getElementUtils(); this.mTypeUtils = processingEnvironment.getTypeUtils(); // 獲取 moduleName 參數 // 先獲取 注解處理器 選項 Map options = processingEnvironment.getOptions(); if (options != null){ mModuleName = options.get("moduleName"); mMessager.printMessage(Diagnostic.Kind.NOTE, "ExtraProcessor : 打印 moduleName 參數 : " + mModuleName); } } /** * 該函數在注解處理器注冊時自動執行, 是處理注解的核心函數 * * Set set 參數 : 該集合表示使用了相關注解的節點的集合 * * @param set * @param roundEnvironment * @return */ @Override public boolean process(Set set, RoundEnvironment roundEnvironment) { mMessager.printMessage(Diagnostic.Kind.NOTE, "ExtraProcessor : " + mModuleName + " process "); if (set == null || set.isEmpty()){ // 如果沒有檢測到注解 , 直接退出 mMessager.printMessage(Diagnostic.Kind.NOTE, "ExtraProcessor : 檢測到注解為空 , 直接退出 mModuleName : " + mModuleName); return false; } // 獲取被 @Extra 注解的屬性節點集合 Set elements = roundEnvironment.getElementsAnnotatedWith(Extra.class); // 采集這些屬性節點集合的 類型 和 變量名稱 for (Element element : elements) { // 獲取這些被 @Extra 標注的字段的父節點 Activity 節點 TypeElement activityElement = (TypeElement) element.getEnclosingElement(); if (mActivity2Field.containsKey(activityElement)) { // 如果該 Activity 父節點存在 , 直接添加到子節點集合中 mActivity2Field.get(activityElement).add(element); } else { // 如果該 Activity 父節點不存在 , 先創建子節點集合 , 再添加到集合中 List childs = new ArrayList<>(); childs.add(element); mActivity2Field.put(activityElement, childs); } mMessager.printMessage(Diagnostic.Kind.NOTE, "ExtraProcessor : " + mModuleName + " 添加注解類型 : " + element.getSimpleName()); } // 至此 , 已經將所有 Activity 以及其下使用 @Extra 標注的屬性都存放在了 // Map> mActivity2Field 集合中 /* 生成 Java 代碼 */ // 獲取 Activity 類型 TypeMirror activityTypeMirror = mElementUtils.getTypeElement("android.app.Activity").asType(); // 獲取 IExtra 接口類型節點 TypeElement IExtra = mElementUtils.getTypeElement("kim.hsl.route_core.template.IExtra"); // 生成 IExtra 接口中 void loadExtra(Object target); 方法的 Object target 參數 ParameterSpec objectParamSpec = ParameterSpec.builder(TypeName.OBJECT, "target").build(); // 遍歷所有需要注入的 類:屬性 for (Map.Entry> entry : mActivity2Field.entrySet()) { // 每個 Map 鍵值對元素都要生成一個對應的 Java 類 // 獲取 Activity 類 TypeElement rawClassElement = entry.getKey(); // 如果該類不是 Activity 子類 , 直接拋出異常 if (!mTypeUtils.isSubtype(rawClassElement.asType(), activityTypeMirror)) { throw new RuntimeException("ExtraProcessor Activity 類型錯誤"); } // 創建 void loadExtra(Object target) 方法 MethodSpec.Builder builder = MethodSpec.methodBuilder("loadExtra") .addAnnotation(Override.class) .addModifiers(Modifier.PUBLIC) .addParameter(objectParamSpec); // 生成類型轉換代碼 : MainActivity t = (MainActivity)target; // 獲取 Activity 類名稱 ClassName className = ClassName.get(rawClassElement); // 類型轉換, 將 Activity 類轉為指定的 Activity 子類類型 builder.addStatement("$T t = ($T)target", className, className); mMessager.printMessage(Diagnostic.Kind.NOTE, "ExtraProcessor : 開始循環 Map 元素個數" + entry.getValue().size()); // 遍歷被 @Extra 標注的屬性字段 for (int i = 0; i < entry.getValue().size(); i++) { Element element = entry.getValue().get(i); buildStatement(element, builder); } mMessager.printMessage(Diagnostic.Kind.NOTE, "ExtraProcessor : 結束循環 Map 元素個數" + entry.getValue().size()); // 生成 java 類名, 原來的 Activity 類名基礎上添加 "_Extra" 后綴 String extraClassName = rawClassElement.getSimpleName() + "_Extra"; // 創建 Java 類 TypeSpec typeSpec = TypeSpec.classBuilder(extraClassName) .addSuperinterface(ClassName.get(IExtra)) // 實現 IExtra 接口 .addModifiers(PUBLIC) // .addMethod(builder.build()) // 設置函數 .build(); // 正式創建 // Java 文件 JavaFile javaFile = JavaFile.builder(className.packageName(), typeSpec).build(); // 寫出生成的 java 代碼 try { javaFile.writeTo(mFiler); } catch (IOException e) { e.printStackTrace(); } mMessager.printMessage(Diagnostic.Kind.NOTE, "ExtraProcessor : 生成文件結束 : " + mModuleName + " " +javaFile.toString()); } return true; } /** * 拼裝如下代碼 * t.a = t.getIntent().getStringExtra("a"); * @param element */ public void buildStatement(Element element, MethodSpec.Builder builder) { TypeMirror typeMirror = element.asType(); int type = typeMirror.getKind().ordinal(); //屬性名 String text 獲得text String fieldName = element.getSimpleName().toString(); //獲得注解 name值 , 默認是傳入的 name 注解屬性值 String extraName = element.getAnnotation(Extra.class).name(); mMessager.printMessage(Diagnostic.Kind.NOTE, "ExtraProcessor : " + mModuleName + " 處理注解類型 : " + typeMirror.toString() + " , 字段名稱 : " + fieldName + " , 注解屬性值 : " + extraName); if (extraName == null || extraName.length() == 0) { // 如果 name 注解屬性值為空 , 則取值 字段名稱 extraName = fieldName; } mMessager.printMessage(Diagnostic.Kind.NOTE, "ExtraProcessor : extraName : " + 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, builder); } else { // 對象類型 addObjectStatement(statement, fieldName, extraName, typeMirror, element, builder); } return; } builder.addStatement(statement, extraName); mMessager.printMessage(Diagnostic.Kind.NOTE, "ExtraProcessor : extraName : " + extraName + " 生成完畢"); } private void addArrayStatement(String statement, String fieldName, String extraName, TypeMirror typeMirror, Element elementm , MethodSpec.Builder builder) { // 獲取 Parcelable 類型 TypeMirror parcelableType = mElementUtils.getTypeElement("android.os.Parcelable").asType(); // 處理數組 switch (typeMirror.toString()) { case "boolean[]": statement += "getBooleanArrayExtra($S)"; break; case "int[]": statement += "getIntArrayExtra($S)"; break; case "short[]": statement += "getShortArrayExtra($S)"; break; case "float[]": statement += "getFloatArrayExtra($S)"; break; case "double[]": statement += "getDoubleArrayExtra($S)"; break; case "byte[]": statement += "getByteArrayExtra($S)"; break; case "char[]": statement += "getCharArrayExtra($S)"; break; case "long[]": statement += "getLongArrayExtra($S)"; break; case "java.lang.String[]": statement += "getStringArrayExtra($S)"; break; default: // 處理 Parcelable 數組 String defaultValue = "t." + fieldName; // object數組 componentType 獲得 object類型 ArrayTypeName arrayTypeName = (ArrayTypeName) ClassName.get(typeMirror); TypeElement typeElement = mElementUtils.getTypeElement(arrayTypeName .componentType.toString()); // 如果不是 Parcelable 拋異常退出 if (!mTypeUtils.isSubtype(typeElement.asType(), parcelableType)) { throw new RuntimeException("不支持的 Extra 類型 : " + typeMirror); } // 字符串格式 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); } private void addObjectStatement(String statement, String fieldName, String extraName, TypeMirror typeMirror, Element element, MethodSpec.Builder builder) { // 獲取 Parcelable 類型 TypeMirror parcelableType = mElementUtils.getTypeElement("android.os.Parcelable").asType(); // 獲取 IService 類型 TypeMirror iServiceType = mElementUtils.getTypeElement("kim.hsl.route_core.template.IService").asType(); if (mTypeUtils.isSubtype(typeMirror, parcelableType)) { statement += "getParcelableExtra($S)"; } else if (typeMirror.toString().equals("java.lang.String")) { statement += "getStringExtra($S)"; } else if (mTypeUtils.isSubtype(typeMirror, iServiceType)) { ClassName routerClassName = ClassName.get("kim.hsl.route_core", "Router"); statement = "t." + fieldName + " = ($T) $T.getInstance().build($S).navigation()"; builder.addStatement(statement, TypeName.get(element.asType()), routerClassName, extraName); return; } else { // List TypeName typeName = ClassName.get(typeMirror); //泛型 if (typeName instanceof ParameterizedTypeName) { //list 或 arraylist ClassName rawType = ((ParameterizedTypeName) typeName).rawType; //泛型類型 List typeArguments = ((ParameterizedTypeName) typeName) .typeArguments; if (!rawType.toString().equals("java.util.ArrayList") && !rawType.toString() .equals("java.util.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 = mElementUtils.getTypeElement(typeArgumentName .toString()); // Parcelable 類型 if (mTypeUtils.isSubtype(typeElement.asType(), parcelableType)) { statement += "getParcelableArrayListExtra($S)"; } else if (typeElement.asType().toString().equals("java.lang.String")) { statement += "getStringArrayListExtra($S)"; } else if (typeElement.asType().toString().equals("java.lang.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); } }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      25

      26

      27

      28

      29

      30

      31

      32

      33

      34

      35

      36

      37

      38

      39

      40

      41

      42

      43

      44

      45

      46

      47

      48

      49

      50

      51

      52

      53

      54

      55

      56

      57

      58

      59

      60

      61

      62

      63

      64

      65

      66

      67

      68

      69

      70

      71

      72

      73

      74

      75

      76

      77

      78

      79

      80

      81

      82

      83

      84

      85

      86

      87

      88

      89

      90

      91

      92

      93

      94

      95

      96

      97

      98

      99

      100

      101

      102

      103

      104

      105

      106

      107

      108

      109

      110

      111

      112

      113

      114

      115

      116

      117

      118

      119

      120

      121

      122

      123

      124

      125

      126

      127

      128

      129

      130

      131

      132

      133

      134

      135

      136

      137

      138

      139

      140

      141

      142

      143

      144

      145

      146

      147

      148

      149

      150

      151

      152

      153

      154

      155

      156

      157

      158

      159

      160

      161

      162

      163

      164

      165

      166

      167

      168

      169

      170

      171

      172

      173

      174

      175

      176

      177

      178

      179

      180

      181

      182

      183

      184

      185

      186

      187

      188

      189

      190

      191

      192

      193

      194

      195

      196

      197

      198

      199

      200

      201

      202

      203

      204

      205

      206

      207

      208

      209

      210

      211

      212

      213

      214

      215

      216

      217

      218

      219

      220

      221

      222

      223

      224

      225

      226

      227

      228

      229

      230

      231

      232

      233

      234

      235

      236

      237

      238

      239

      240

      241

      242

      243

      244

      245

      246

      247

      248

      249

      250

      251

      252

      253

      254

      255

      256

      257

      258

      259

      260

      261

      262

      263

      264

      265

      266

      267

      268

      269

      270

      271

      272

      273

      274

      275

      276

      277

      278

      279

      280

      281

      282

      283

      284

      285

      286

      287

      288

      289

      290

      291

      292

      293

      294

      295

      296

      297

      298

      299

      300

      301

      302

      303

      304

      305

      306

      307

      308

      309

      310

      311

      312

      313

      314

      315

      316

      317

      318

      319

      320

      321

      322

      323

      324

      325

      326

      327

      328

      329

      330

      331

      332

      333

      334

      335

      336

      337

      338

      339

      340

      341

      342

      343

      344

      345

      346

      347

      348

      349

      350

      351

      352

      353

      354

      355

      356

      357

      358

      359

      360

      361

      362

      363

      364

      365

      366

      367

      368

      369

      370

      371

      372

      373

      374

      375

      【Android 組件化】路由組件 ( 頁面跳轉參數依賴注入 )

      376

      377

      378

      379

      380

      381

      382

      383

      384

      385

      386

      387

      388

      389

      390

      391

      392

      393

      394

      395

      396

      397

      398

      399

      400

      401

      402

      403

      404

      405

      406

      407

      408

      409

      410

      411

      412

      413

      414

      415

      五、博客資源

      博客源碼 :

      GitHub : https://github.com/han1202012/Component

      CSDN 下載 :

      Android NAT

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:Excel函數中怎樣替換個別字符串
      下一篇:回車鍵符號沒了,如何恢復?(回車鍵符號怎么去掉)
      相關文章
      91在线亚洲精品专区| 亚洲人成网www| 中文无码亚洲精品字幕| 久久亚洲私人国产精品| 亚洲国产精品高清久久久| 亚洲乱码无码永久不卡在线| 亚洲中文字幕久久精品无码喷水| 狼人大香伊蕉国产WWW亚洲| 亚洲av日韩专区在线观看| 亚洲av永久无码天堂网| 亚洲一区二区三区写真| 亚洲 日韩 色 图网站| 亚洲免费福利在线视频| 亚洲日本乱码卡2卡3卡新区| 亚洲首页国产精品丝袜| 亚洲另类无码一区二区三区| 亚洲成aⅴ人片久青草影院按摩| 亚洲精品无码久久久久秋霞| 亚洲AV无码AV吞精久久| 亚洲AⅤ视频一区二区三区| 国产日韩成人亚洲丁香婷婷| 亚洲中久无码永久在线观看同| 亚洲国产日韩在线视频| 久久久亚洲精品无码| 久久亚洲AV成人无码软件 | 久久亚洲精品成人AV| 亚洲第一页在线观看| 亚洲AV无码一区二区三区在线| 精品国产日韩久久亚洲| 亚洲av日韩精品久久久久久a| 亚洲精品高清在线| 亚洲乱亚洲乱妇无码麻豆| 无码欧精品亚洲日韩一区| 亚洲欧洲日本国产| 亚洲国产精品免费观看| 亚洲AV女人18毛片水真多| 亚洲国产综合人成综合网站| 亚洲午夜国产精品无码老牛影视 | 亚洲第一男人天堂| 爱爱帝国亚洲一区二区三区| 国产亚洲精久久久久久无码77777 国产亚洲精品成人AA片新蒲金 |