Jetpack系列组件--皮皮虾客户端
2019-09-26 本文已影响0人
蓅哖伊人为谁笑
1.Navigation
- 谷歌的野心,页面路由导航框架。支持
Fragment
、Activity
、DialogFragment
的导航行为。
2.Navigation关键类
- 下面这张图看一下
Navigation
关键类图关系
NavHostFragment
:作为内容区域的宿主container.
NavigationController
:作为页面路由导航的控制器
NavigatorProvider
:是导航器提供者。实际上是一个
HashMap<String,Navigator>
NavGraph
:收集了所有的路由节点Destination
NavGrahpNavigator
:是个比较特殊的导航器。当解析到navigation
资源文件中navigation
标签时会由它创建NavGraph
对象。另外它的navigate
不执行具体的导航行为,而是分发给FragmentNavigator
、DialogFragmentNavigagtor
、ActivityNavigator
来执行具体的导航行为。
ActivityNavigator
和FragmentNavigator
、DialogFragmentNavigagtor
倒是一致的,为了创建各自类型的节点Destination
和提供导航行为而生。他们都会在NavHostFragment#onCreate
中被创建添加到NavigationController#NavigatorProvider
中。
以上就是简单地对Navigation
框架几个关键类作用的解释。
-
Navigation类图关系
3.Navigation高级用法
-
关于
Navigation
的用法百度上铺天盖地的都是清一色的文章和用法。不过恶心之处在于必须把路由页面写在资源文件中,不利于灵活配置、页面可见的权限控制。基于此皮皮虾客户端采用了注解处理器
标记页面节点、手动创建NavGraph
的形式来实现页面路由结构图。 -
NavProcessor
注解处理器生成页面路由JSON文件,文件生成在assets目录下。
@AutoService(Processor.class)
@SupportedSourceVersion(SourceVersion.RELEASE_8)
@SupportedAnnotationTypes({"com.mooc.libnavannotation.FragmentDestination", "com.mooc.libnavannotation.ActivityDestination"})
public class NavProcessor extends AbstractProcessor {
private Messager messager;
private Filer filer;
private static final String OUTPUT_FILE_NAME = "destination.json";
@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
messager = processingEnv.getMessager();
filer = processingEnv.getFiler();
}
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
Set<? extends Element> fragmentElements = roundEnv.getElementsAnnotatedWith(FragmentDestination.class);
Set<? extends Element> activityElements = roundEnv.getElementsAnnotatedWith(ActivityDestination.class);
if (!fragmentElements.isEmpty() || !activityElements.isEmpty()) {
HashMap<String, JSONObject> destMap = new HashMap<>();
handleDestination(fragmentElements, FragmentDestination.class, destMap);
handleDestination(activityElements, ActivityDestination.class, destMap);
//app/src/main/assets
FileOutputStream fos = null;
OutputStreamWriter writer = null;
try {
FileObject resource = filer.createResource(StandardLocation.CLASS_OUTPUT, "", OUTPUT_FILE_NAME);
String resourcePath = resource.toUri().getPath();
messager.printMessage(Diagnostic.Kind.NOTE, "resourcePath:" + resourcePath);
String appPath = resourcePath.substring(0, resourcePath.indexOf("app") + 4);
String assetsPath = appPath + "src/main/assets/";
File file = new File(assetsPath);
if (!file.exists()) {
file.mkdirs();
}
File outPutFile = new File(file, OUTPUT_FILE_NAME);
if (outPutFile.exists()) {
outPutFile.delete();
}
outPutFile.createNewFile();
String content = JSON.toJSONString(destMap);
fos = new FileOutputStream(outPutFile);
writer = new OutputStreamWriter(fos, "UTF-8");
writer.write(content);
writer.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (writer != null) {
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
return true;
}
private void handleDestination(Set<? extends Element> elements, Class<? extends Annotation> annotationClaz, HashMap<String, JSONObject> destMap) {
for (Element element : elements) {
TypeElement typeElement = (TypeElement) element;
String pageUrl = null;
String clazName = typeElement.getQualifiedName().toString();
int id = Math.abs(clazName.hashCode());
boolean needLogin = false;
boolean asStarter = false;
boolean isFragment = false;
Annotation annotation = typeElement.getAnnotation(annotationClaz);
if (annotation instanceof FragmentDestination) {
FragmentDestination dest = (FragmentDestination) annotation;
pageUrl = dest.pageUrl();
asStarter = dest.asStarter();
needLogin = dest.needLogin();
isFragment = true;
} else if (annotation instanceof ActivityDestination) {
ActivityDestination dest = (ActivityDestination) annotation;
pageUrl = dest.pageUrl();
asStarter = dest.asStarter();
needLogin = dest.needLogin();
isFragment = false;
}
if (destMap.containsKey(pageUrl)) {
messager.printMessage(Diagnostic.Kind.ERROR, "不同的页面不允许使用相同的pageUrl:" + clazName);
} else {
JSONObject object = new JSONObject();
object.put("id", id);
object.put("needLogin", needLogin);
object.put("asStarter", asStarter);
object.put("pageUrl", pageUrl);
object.put("className", clazName);
object.put("isFragment", isFragment);
destMap.put(pageUrl, object);
}
}
}
}
- 根据解析出来的
json
文件生成NavGrahp
对象,并绑定到NavController
上.这样一来咱们就结局了只能在资源文件中写死路由节点的问题了。
public static void build(NavController controller) {
NavigatorProvider provider = controller.getNavigatorProvider();
NavGraph navGraph = new NavGraph(new NavGraphNavigator(provider));
FragmentNavigator fragmentNavigator = provider.getNavigator(FragmentNavigator.class);
ActivityNavigator activityNavigator = provider.getNavigator(ActivityNavigator.class);
HashMap<String, Destination> destConfig = AppConfig.getDestConfig();
Iterator<Destination> iterator = destConfig.values().iterator();
while (iterator.hasNext()) {
Destination node = iterator.next();
if (node.isFragment) {
FragmentNavigator.Destination destination = fragmentNavigator.createDestination();
destination.setId(node.id);
destination.setClassName(node.className);
destination.addDeepLink(node.pageUrl);
navGraph.addDestination(destination);
} else {
ActivityNavigator.Destination destination = activityNavigator.createDestination();
destination.setId(node.id);
destination.setComponentName(new ComponentName(AppGlobals.getApplication().getPackageName(), node.className));
destination.addDeepLink(node.pageUrl);
navGraph.addDestination(destination);
}
if (node.asStarter) {
navGraph.setStartDestination(node.id);
}
}
controller.setGraph(navGraph);
}
更多Jetpack系列组件 就在皮皮虾客户端