前言
现在大多数的App都会在重构的时候想到组件化或者说模块化,方便App解耦和优化。在我的理解里面组件化即将每个功能相同的模块一个个的装起来,然后以library的形式供我们的主app模块调用,而在主app模块中不会去进行任何的业务逻辑,只管打包好了,而除了主app模块,其他模块各回各家,各找各妈,干自己的业务逻辑去,简单的说组件化就是让library和application之间可以互相切换,libray可以作为单独的App运行也可以作为依赖库给主app调用;这种构建思想提升开发效率,减低代码的维护成本,减少代码的耦合度,让他人简单易懂。
组件化流程
模块虽然都独立出来了,但是如果每个模块都有想要调用其他模块的想法,那该怎么做呢?所以就要通过如上图所示中的Router这个中间人来替他们拉红线了?。
组件化Demo
说了这么多,开始写下demo
创建module
1.右击项目,点击Module
2.如果是功能模块,要选择下图的红框选,其实也可以不选吧,如果仅仅是想作为libray的话
3.这边要注意的是名字要有标准性的,就不要嫌麻烦取一样的名字了
4.统一每一个模块的SDK等版本,和设置模块是库还是app,在总项目的gradle.properties下设置
5.记得导入依赖
导入自己创建的模块即可
6.每个模块下的build.gradle下配置如下内容
7.清单文件也需要判断
8.创建中间人
ARouter.java该类进行其他模块的跳转通信
package com.hwt.arouter;
import android.app.Activity;
import android.app.Application;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import dalvik.system.DexFile;
/**
* author:arrowHwt
* Date:2019/7/14
* Time:20:16
*/
public class ARouter {
private static ARouter instance = new ARouter();
//装载Activity的容器
private Map<String,Class<? extends Activity>> activityList;
private Context context;
private ARouter(){
activityList = new HashMap<>();
}
public static ARouter getInstance(){
return instance;
}
public void init(Application application){
this.context = application.getApplicationContext();
List<String> classNames = getClassName("com.hwt.util");
for (String className: classNames) {
try {
Class<?> aClass = Class.forName(className);
//判断是否是IRouter的实现类
if (IRouter.class.isAssignableFrom(aClass)){
IRouter iRouter = (IRouter) aClass.newInstance();
iRouter.putActivity();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
public void putActivity(String path,Class<? extends Activity> clazz){
if (path != null && clazz != null){
activityList.put(path,clazz);
}
}
public void jumpActivity(String path, Bundle bundle){
//Activity的class对象
Class<? extends Activity> aClass = activityList.get(path);
if (aClass == null){
return;
}
Intent intent = new Intent().setClass(context,aClass);
if (bundle != null){
intent.putExtra("bundle",bundle);
}
context.startActivity(intent);
}
/**
* 通过包名拿到Class
* @param packageName
* @return
*/
private List<String> getClassName(String packageName) {
List<String> classList = new ArrayList<>();
String path = null;
try {
path = context.getPackageManager().getApplicationInfo(context.getPackageName(),0).sourceDir;
DexFile dexFile = new DexFile(path);
Enumeration entries = dexFile.entries();
while (entries.hasMoreElements()){
String name = (String) entries.nextElement();
if (name.contains(packageName)){
classList.add(name);
}
}
} catch (Exception e) {
e.printStackTrace();
}
return classList;
}
}
9.通过注解,注解处理器(选择JavaLibrart,因为注解和注解处理器是java的)进行获取每个模块的类名,从而通过反射机制拿到每个模块中需要通信的类的所有信息
10.添加注解依赖与步骤5一样,导入要用到该注解和注解处理器的模块中
注意:依赖注解处理器需要像下图一样使用annotationProcessor导入
11.自定义自己的注解
12.编写注解处理器
注解处理器的作用是自动生成类,以下是自动生成以时间为名字的跳转Activity的工具类
AnnotationComplier.java
package com.hwt.annotation_complier;
import com.google.auto.service.AutoService;
import com.hwt.annotation.BindPath;
import java.io.IOException;
import java.io.Writer;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Filer;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.tools.JavaFileObject;
/**
* author:arrowHwt
* Date:2019/7/14
* Time:21:06
* 注解处理器
*/
@AutoService(Processor.class) //注册注解处理器
public class AnnotationComplier extends AbstractProcessor {
//生成文件对象
Filer filer;
@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
filer = processingEnv.getFiler();
}
/**
* 声明注解处理器要处理哪些注解
*
* @return
*/
@Override
public Set<String> getSupportedAnnotationTypes() {
Set<String> types = new HashSet<>();
types.add(BindPath.class.getCanonicalName());
return types;
}
/**
* 声明注解处理支持的Java sdk的版本
*
* @return
*/
@Override
public SourceVersion getSupportedSourceVersion() {
return processingEnv.getSourceVersion();
}
/**
* 注解处理器的核心方法
*
* @param annotations
* @param roundEnv
* @return
*/
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
//通过这个API就能拿到所有模块中所有用到BindPath注解的节点
Set<? extends Element> elementsAnnotatedWith = roundEnv.getElementsAnnotatedWith(BindPath.class);
//初始化数据
Map<String, String> map = new HashMap<>();
for (Element e : elementsAnnotatedWith) {
TypeElement typeElement = (TypeElement) e;
String key = typeElement.getAnnotation(BindPath.class).value();
String value = typeElement.getQualifiedName().toString();
map.put(key,value);
}
//开始写文件
if (map.size() > 0){
Writer writer = null;
//创建类名
String utilName = "ActivityUtil" + System.currentTimeMillis();
try {
JavaFileObject sourceFile = filer.createSourceFile("com.hwt.util."+utilName);
writer = sourceFile.openWriter();
writer.write("package com.hwt.util;\n" +
"\n" +
"import android.app.Activity;\n" +
"\n" +
"import com.hwt.arouter.ARouter;\n" +
"import com.hwt.arouter.IRouter;\n" +
"\n" +
"/**\n" +
" * author:arrowHwt\n" +
" * Date:2019/7/14\n" +
" * Time:20:35\n" +
" */\n" +
"public class "+ utilName+" implements IRouter {\n" +
" @Override\n" +
" public void putActivity() {");
Iterator<String> iterator = map.keySet().iterator();
while (iterator.hasNext()){
String key = iterator.next();
String value = map.get(key);
writer.write("ARouter.getInstance().putActivity(\""+key+"\","+
value+".class);\n");
writer.write("}\n}");
}
} catch (IOException e) {
e.printStackTrace();
}finally {
if (writer != null){
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
return false;
}
}
13.最后在想要跳转的地方加入BindPath注解,然后再调用ARouter中的jumpActivity进行跳转
package com.hwt.login;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import com.hwt.annotation.BindPath;
import com.hwt.arouter.ARouter;
@BindPath("login/login")
public class LoginActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
}
public void jumpActivity(View view) {
ARouter.getInstance().jumpActivity("member/member",null);
}
}