Android 组件化】路由组件 ( 生成 Root 类记录模块中的路由表 )

网友投稿 601 2022-05-30

文章目录

一、Root 表作用

二、生成 Root 表

三、完整注解处理器代码 及 生成的 Java 代码 ( 仅供参考 )

1、注解处理器代码

2、app 模块中的注解类生成的 Java 源码

3、library2 模块中的注解类生成的 Java 源码

四、博客资源

组件化系列博客 :

【Android 组件化】从模块化到组件化

【Android 组件化】使用 Gradle 实现组件化 ( Gradle 变量定义与使用 )

【Android 组件化】使用 Gradle 实现组件化 ( 组件模式与集成模式切换 )

【Android 组件化】使用 Gradle 实现组件化 ( 组件 / 集成模式下的 Library Module 开发 )

【Android 组件化】路由组件 ( 路由组件结构 )

【Android 组件化】路由组件 ( 注解处理器获取被注解的节点 )

【Android 组件化】路由组件 ( 注解处理器中使用 JavaPoet 生成代码 )

【Android 组件化】路由组件 ( 注解处理器参数选项设置 )

【Android 组件化】路由组件 ( 构造路由表中的路由信息 )

【Android 组件化】路由组件 ( 使用 JavaPoet 生成路由表类 )

【Android 组件化】路由组件 ( 组件间共享的服务 )

一、Root 表作用

注解处理器 为每个 Module 模块生成一个路由表 , 该模块下凡是被 @Route 标注的路由节点都在该路由表中维护 ;

package kim.hsl.router; import java.lang.Override; import java.lang.String; import java.util.Map; import kim.hsl.library2.StringService; import kim.hsl.route_core.template.IRouteGroup; import kim.hsl.router_annotation.model.RouteBean; public class Router_Group_library2 implements IRouteGroup { @Override public void loadInto(Map atlas) { atlas.put("library2", new RouteBean(RouteBean.Type.ISERVICE, StringService.class, "/library2/StringService", "library2")); } }

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

模块名称是 app , 则路由表的名称是 Router_Group_app.java ;

一个模块中的路由表可能有多个 , 需要为若干路由表再生成一个 Root 表, 用于作为路由表的导航 ;

生成的 Root 表样式 : 其中 “app” 是组名 , Router_Group_app.class 是 app 组对应的路由表类 ;

package kim.hsl.router; import java.lang.Class; import java.lang.Override; import java.lang.String; import java.util.Map; import kim.hsl.route_core.template.IRouteGroup; import kim.hsl.route_core.template.IRouteRoot; public class Router_Root_app implements IRouteRoot { @Override public void loadInto(Map> routes) { routes.put("app", Router_Group_app.class); } }

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

二、生成 Root 表

定义 IRouteRoot 接口 , 所有的 Root 类都实现该接口 , 该接口定义在 route-core 模块中 ;

package kim.hsl.route_core.template; import java.util.Map; public interface IRouteRoot { void loadInto(Map> routes); }

1

2

3

4

5

6

7

IRoot 接口定义位置 :

首先 , 获取 IRouteGroup 和 IRouteRoot 接口的节点 ;

// 获取 kim.hsl.route_core.template.IRouteGroup 类节点 TypeElement iRouteGroup = mElementUtils.getTypeElement("kim.hsl.route_core.template.IRouteGroup"); // 获取 kim.hsl.route_core.template.IRouteRoot 类节点 TypeElement iRouteRoot = mElementUtils.getTypeElement("kim.hsl.route_core.template.IRouteRoot");

1

2

3

4

其次 , 生成 loadInto 函数的参数 Map> routes ;

// 生成参数类型名称 // Map> routes> ParameterizedTypeName routesTypeName = ParameterizedTypeName.get( ClassName.get(Map.class), ClassName.get(String.class), ParameterizedTypeName.get( ClassName.get(Class.class), WildcardTypeName.subtypeOf(ClassName.get(iRouteGroup)) ) ); // 生成参数 // Map> routes> routes ParameterSpec rootParameterSpec = ParameterSpec.builder(routesTypeName, "routes") .build();

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

再次 , 生成函数及函数体 ;

// 生成函数 // public void loadInfo(Map> routes> routes) MethodSpec.Builder loadIntoMethodBuilder = MethodSpec.methodBuilder("loadInto") .addAnnotation(Override.class) .addModifiers(Modifier.PUBLIC) .addParameter(rootParameterSpec); // 生成函数体 for (Map.Entry entry : mRootMap.entrySet()) { loadIntoMethodBuilder.addStatement( "routes.put($S, $T.class)", entry.getKey(), ClassName.get("kim.hsl.router", entry.getValue()) ); }

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

最后 , 生成 Router_Root_app 类 , 并写出到文件中 ;

// 生成 Root 类 String rootClassName = "Router_Root_" + mModuleName; // 创建 Java 类 TypeSpec typeSpec = TypeSpec.classBuilder(rootClassName) .addSuperinterface(ClassName.get(iRouteRoot)) .addModifiers(PUBLIC) .addMethod(loadIntoMethodBuilder.build()) .build(); // 生成 Java 源文件 JavaFile javaFile = JavaFile.builder("kim.hsl.router", typeSpec).build(); // 写出到文件中 try { javaFile.writeTo(mFiler); } catch (IOException e) { e.printStackTrace(); }

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

三、完整注解处理器代码 及 生成的 Java 代码 ( 仅供参考 )

1、注解处理器代码

package kim.hsl.router_compiler; import com.google.auto.service.AutoService; 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.TypeSpec; import com.squareup.javapoet.WildcardTypeName; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; 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.TypeMirror; import javax.lang.model.util.Elements; import javax.lang.model.util.Types; import javax.tools.Diagnostic; 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.Route"}) // 支持的 Java 版本 @SupportedSourceVersion(SourceVersion.RELEASE_8) public class RouterProcessor extends AbstractProcessor { /** * 注解处理器中使用 Messager 对象打印日志 */ private Messager mMessager; /** * 用于写出生成的 Java 代码 */ private Filer mFiler; /** * 注解节点工具 */ private Elements mElementUtils; /** * 类工具 */ private Types mTypeUtils; /** * 获取的 moduleName 参数 */ private String mModuleName; /** * 管理路由信息 * 键 ( Key ) : 路由分组名称 * 值 ( Value ) : 路由信息集合 */ private HashMap> mGroupMap = new HashMap<>(); /** * 管理 路由表信息 * 键 ( Key ) : 组名 * 值 ( Value ) : 类名 */ private Map mRootMap = new TreeMap<>(); /** * 该函数在初始化时调用 , 相当于构造函数 * @param processingEnvironment */ @Override public synchronized void init(ProcessingEnvironment processingEnvironment) { super.init(processingEnvironment); // 获取打印日志接口 this.mMessager = processingEnvironment.getMessager(); // 测试日志打印 mMessager.printMessage(Diagnostic.Kind.NOTE, "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, "打印 moduleName 参数 : " + mModuleName); } } /** * 该函数在注解处理器注册时自动执行, 是处理注解的核心函数 * * Set set 参数 : 该集合表示使用了相关注解的节点的集合 * * @param set * @param roundEnvironment * @return */ @Override public boolean process(Set set, RoundEnvironment roundEnvironment) { if (set == null || set.isEmpty()){ // 如果没有检测到注解 , 直接退出 return false; } // 获取被 @Route 注解的节点 // 这些 注解节点 都是类节点 , TypeElement 类型的 Set routeElements = roundEnvironment.getElementsAnnotatedWith(Route.class); generateRouteClass(routeElements); // 生成 路由组件 分组表 对应的 Java 路由表 类 generateGroupTable(); // 生成 Root 路由表 , 组名 <-> 路由表类 generateRootTable(); return true; } /** * 生成 Root 表 */ private void generateRootTable() { // 获取 kim.hsl.route_core.template.IRouteGroup 类节点 TypeElement iRouteGroup = mElementUtils.getTypeElement("kim.hsl.route_core.template.IRouteGroup"); // 获取 kim.hsl.route_core.template.IRouteRoot 类节点 TypeElement iRouteRoot = mElementUtils.getTypeElement("kim.hsl.route_core.template.IRouteRoot"); // 生成参数类型名称 // Map> routes> ParameterizedTypeName routesTypeName = ParameterizedTypeName.get( ClassName.get(Map.class), ClassName.get(String.class), ParameterizedTypeName.get( ClassName.get(Class.class), WildcardTypeName.subtypeOf(ClassName.get(iRouteGroup)) ) ); // 生成参数 // Map> routes> routes ParameterSpec rootParameterSpec = ParameterSpec.builder(routesTypeName, "routes") .build(); // 生成函数 // public void loadInfo(Map> routes> routes) MethodSpec.Builder loadIntoMethodBuilder = MethodSpec.methodBuilder("loadInto") .addAnnotation(Override.class) .addModifiers(Modifier.PUBLIC) .addParameter(rootParameterSpec); // 生成函数体 for (Map.Entry entry : mRootMap.entrySet()) { loadIntoMethodBuilder.addStatement( "routes.put($S, $T.class)", entry.getKey(), ClassName.get("kim.hsl.router", entry.getValue()) ); } // 生成 Root 类 String rootClassName = "Router_Root_" + mModuleName; // 创建 Java 类 TypeSpec typeSpec = TypeSpec.classBuilder(rootClassName) .addSuperinterface(ClassName.get(iRouteRoot)) .addModifiers(PUBLIC) .addMethod(loadIntoMethodBuilder.build()) .build(); // 生成 Java 源文件 JavaFile javaFile = JavaFile.builder("kim.hsl.router", typeSpec).build(); // 写出到文件中 try { javaFile.writeTo(mFiler); } catch (IOException e) { e.printStackTrace(); } } /** * 生成 路由组件 分组表 对应的 Java 类 */ private void generateGroupTable() { // 获取要生成的类 需要实现的接口节点 TypeElement iRouteGroup = mElementUtils.getTypeElement( "kim.hsl.route_core.template.IRouteGroup"); // 打印类节点全类名 mMessager.printMessage(Diagnostic.Kind.NOTE, "打印 路由表 需要实现的接口节点 iRouteGroup : " + iRouteGroup.getQualifiedName()); // 生成参数类型 Map atlas ParameterizedTypeName atlasType = ParameterizedTypeName.get( ClassName.get(Map.class), ClassName.get(String.class), ClassName.get(RouteBean.class) ); // 生成参数 Map atlas ParameterSpec atlasValue = ParameterSpec.builder(atlasType, "atlas").build(); // 遍历 HashMap> mGroupMap = new HashMap<>() 路由分组 // 为每个 路由分组 创建一个类 for (Map.Entry> entry : mGroupMap.entrySet()){ // 创建函数 loadInto MethodSpec.Builder methodBuilder = MethodSpec.methodBuilder("loadInto") .addModifiers(Modifier.PUBLIC) .addAnnotation(Override.class) .addParameter(atlasValue); // 函数体中的代码生成 // 获取 ArrayList 数据 ArrayList groupRoutes = entry.getValue(); // 组名 String groupName = ""; // 生成函数体代码 for (RouteBean routeBean : groupRoutes){ // 获取组名 groupName = routeBean.getRouteGroup(); // $S 表示字符串 // $T 表示类 // $L 表示字面量 , 原封不动的字符串替换 methodBuilder.addStatement("atlas.put($S, new $T($T.$L, $T.class, $S, $S))", // $S 字符串 : "main" routeBean.getRouteGroup(), // $T 类名 : RouteBean ClassName.get(RouteBean.class), // $T 类名 : Type ClassName.get(RouteBean.Type.class), // $L 字面量 : ACTIVITY routeBean.getType(), // $T 类名 : kim.hsl.component.MainActivity 类 ClassName.get((TypeElement) routeBean.getElement()), // $S 字符串 : "/app/MainActivity" routeBean.getRouteAddress(), // $S 字符串 : "app" routeBean.getRouteGroup()); } // 创建类 // 构造类名 Router_Group_main String groupClassName = "Router_Group_" + groupName; // 创建类 TypeSpec typeSpec = TypeSpec.classBuilder(groupClassName) .addSuperinterface(ClassName.get(iRouteGroup)) .addModifiers(PUBLIC) .addMethod(methodBuilder.build()) .build(); // 生成 Java 源码文件 JavaFile javaFile = JavaFile.builder("kim.hsl.router", typeSpec).build(); // 将 Java 源文件写出到相应目录中 try { mMessager.printMessage(Diagnostic.Kind.NOTE, "输出文件 : " + groupClassName); javaFile.writeTo(mFiler); } catch (IOException e) { e.printStackTrace(); mMessager.printMessage(Diagnostic.Kind.NOTE, "输出文件出现异常"); }finally { mMessager.printMessage(Diagnostic.Kind.NOTE, "输出文件完毕"); } // 统计路由表信息 mRootMap.put(groupName, groupClassName); } } private void generateRouteClass(Set routeElements) { // 获取 android.app.Activity 类型的注解节点 TypeElement activityElement = mElementUtils.getTypeElement("android.app.Activity"); // 获取 组件间共享服务 的接口, 该接口仅用于表示组件类型 TypeElement iServiceElement = mElementUtils.getTypeElement("kim.hsl.route_core.template.IService"); // 处理 @Route(path = "app/MainActivity") 节点 for (Element element : routeElements) { // 获取 Route 注解 Route route = element.getAnnotation(Route.class); // 路由表中的单个路由对象 RouteBean routeBean = null; // 判断 typeMirror 注解节点是否是 Activity 类型 if (mTypeUtils.isSubtype(element.asType(), activityElement.asType())) { // 该节点是 android.app.Activity 类型的 routeBean = new RouteBean( RouteBean.Type.ACTIVITY, // 路由对象类型 element, // 路由节点 null, // 类对象 route.path(), // 路由地址 route.group()); // 路由组 }else if (mTypeUtils.isSubtype(element.asType(), iServiceElement.asType())) { // 该节点是 kim.hsl.route_core.template.IService 类型的 routeBean = new RouteBean( RouteBean.Type.ISERVICE, // 路由对象类型 element, // 路由节点 null, // 类对象 route.path(), // 路由地址 route.group()); // 路由组 }else{ // 该节点不是 android.app.Activity 类型的 throw new RuntimeException("@Route 注解节点类型错误"); } // 检查路由地址 checkRouteAddress(routeBean); // 打印路由信息 mMessager.printMessage(Diagnostic.Kind.NOTE, "打印路由信息 : " + routeBean.toString()); // 处理路由信息分组 routeGroup(routeBean); } } /** * 处理路由信息分组 * @param routeBean */ private void routeGroup(RouteBean routeBean) { // 首先从 groupMap 集合中获取该分组的所有 路由信息 ArrayList routeBeans = mGroupMap.get(routeBean.getRouteGroup()); if (routeBeans == null){ // 如果从 mGroupMap 获取的该分组的路由信息集合为空 // 则创建新集合, 放置路由信息, 并加入到 mGroupMap 中 routeBeans = new ArrayList<>(); routeBeans.add(routeBean); mGroupMap.put(routeBean.getRouteGroup(), routeBeans); }else{ // 从 mGroupMap 获取的路由分组对应的路由信息集合不为空 // 直接添加 路由信息 即可 routeBeans.add(routeBean); } } /** * 验证路由地址 * @Route(path = "/app/MainActivity") * @param routeBean */ private void checkRouteAddress(RouteBean routeBean){ // 获取路由地址 String routeAddress = routeBean.getRouteAddress(); // 获取路由分组 String routeGroup = routeBean.getRouteGroup(); // 验证路由地址是否以 "/" 开头 if (!routeAddress.startsWith("/")) { throw new RuntimeException("路由地址 " + routeAddress + " 格式错误"); } // 如果路由地址的分组为空 , // 则截取第 0 和 第 1 个 "/" 之间的字符串作为分组名称 if (routeGroup == null || "".equals(routeGroup)){ String group = routeAddress.substring( routeAddress.indexOf("/", 0) + 1, routeAddress.indexOf("/", 1) ); if (group == null || "".equals(group)){ throw new RuntimeException("路由地址 " + routeAddress + " 获取分组错误"); } // 打印组名 mMessager.printMessage(Diagnostic.Kind.NOTE, "打印路由地址 " + routeAddress + " 的组名为 " + group); // 正式设置路由地址分组 routeBean.setRouteGroup(group); } } }

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

【Android 组件化】路由组件 ( 生成 Root 类记录模块中的路由表 )

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

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

2、app 模块中的注解类生成的 Java 源码

Module 模块中 , 使用注解生成的源码 , 都在对应模块的 " build\generated\ap_generated_sources\debug\out\ " 目录中 ;

app 中的注解类 :

@Route(path = "/app/MainActivity") public class MainActivity extends Activity { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } }

1

2

3

4

5

6

7

8

生成的 路由表 源码 : 生成源码路径 D:\002_Project\002_Android_Learn\Component\app\build\generated\ap_generated_sources\debug\out\kim\hsl\router\Router_Group_app.java ;

package kim.hsl.router; import java.lang.Override; import java.lang.String; import java.util.Map; import kim.hsl.component.MainActivity; import kim.hsl.route_core.template.IRouteGroup; import kim.hsl.router_annotation.model.RouteBean; public class Router_Group_app implements IRouteGroup { @Override public void loadInto(Map atlas) { atlas.put("app", new RouteBean(RouteBean.Type.ACTIVITY, MainActivity.class, "/app/MainActivity", "app")); } }

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

生成的 Root 表源码 : 生成源码路径 D:\002_Project\002_Android_Learn\Component\app\build\generated\ap_generated_sources\debug\out\kim\hsl\router\Router_Root_app.java ;

package kim.hsl.router; import java.lang.Class; import java.lang.Override; import java.lang.String; import java.util.Map; import kim.hsl.route_core.template.IRouteGroup; import kim.hsl.route_core.template.IRouteRoot; public class Router_Root_app implements IRouteRoot { @Override public void loadInto(Map> routes) { routes.put("app", Router_Group_app.class); } }

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

3、library2 模块中的注解类生成的 Java 源码

Module 模块中 , 使用注解生成的源码 , 都在对应模块的 " build\generated\ap_generated_sources\debug\out\ " 目录中 ;

library2 中的注解类 :

package kim.hsl.library2; import android.util.Log; import kim.hsl.base.ComponentService; import kim.hsl.router_annotation.Route; @Route(path = "/library2/StringService") public class StringService implements ComponentService { @Override public void doSomething() { Log.i("StringService", "library2 组件中的 StringService 服务 "); } }

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

生成的 路由表 源码 : 生成源码路径 D:\002_Project\002_Android_Learn\Component\library2\build\generated\ap_generated_sources\debug\out\kim\hsl\router\Router_Group_library2.java ;

package kim.hsl.router; import java.lang.Override; import java.lang.String; import java.util.Map; import kim.hsl.library2.StringService; import kim.hsl.route_core.template.IRouteGroup; import kim.hsl.router_annotation.model.RouteBean; public class Router_Group_library2 implements IRouteGroup { @Override public void loadInto(Map atlas) { atlas.put("library2", new RouteBean(RouteBean.Type.ISERVICE, StringService.class, "/library2/StringService", "library2")); } }

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

生成的 Root 表源码 : 生成源码路径 D:\002_Project\002_Android_Learn\Component\library2\build\generated\ap_generated_sources\debug\out\kim\hsl\router\Router_Root_library2.java ;

package kim.hsl.router; import java.lang.Class; import java.lang.Override; import java.lang.String; import java.util.Map; import kim.hsl.route_core.template.IRouteGroup; import kim.hsl.route_core.template.IRouteRoot; public class Router_Root_library2 implements IRouteRoot { @Override public void loadInto(Map> routes) { routes.put("library2", Router_Group_library2.class); } }

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

四、博客资源

博客源码 :

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

CSDN 下载 :

Android NAT

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:计算机网络之数据链路层
下一篇:虚拟化系列介绍(一)
相关文章