标签:start 输出 undle substr port 理解 来讲 tostring on()
Android应用组件化各个组件页面之间要实现跳转使用路由是一个很好的选择。本文将实现一个比较轻量级的路由组件,主要涉及以下知识:
本文将使用Java注解来实现一个简单的路由组件,主要从这几方面来讲解:
由于使用AnnotationProcessor,所以整个路由可分为以下模块:
由于我们的路由组件相对简单,主要定义以下注解:
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.TYPE)
public @interface UriDestination {
String name();
DestinationUri uri();
DestinationArgument[] out() default {};
DestinationArgument[] in() default {};
}
该注解主要用来注解Activity,声明一个路由目标的信息,各参数说明如下:
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.ANNOTATION_TYPE)
public @interface DestinationUri {
String authority() default "imxingzhe.com";
String scheme() default "xingzhe";
String path() default "";
}
该路由主要用于声明路由目标的Uri信息,各参数说明如下:
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.ANNOTATION_TYPE)
public @interface DestinationArgument {
String key();
boolean require() default false;
Class<?> type();
}
该注解主要用于声明路由的输入、输出参数信息,各参数说明如下:
public interface DestinationAction {
Context getContext();
int getFlags();
int getRequestCode();
boolean getUriOnly();
Bundle getArguments();
}
Action
可理解为一次跳转动作,使用端通过Builder模式生成Action
实例,然后再通过DestinationService
执行给定的动作。
public interface DestinationService {
void start(DestinationAction destinationAction);
}
此接口只包含一个start
方法用于执行DestinationAction
逻辑。主要实现跳转方式是使用类式ContentProvider
的UriMatcher方式来实现。首先声明一个抽象Service:
public abstract class AbstractUriDestinationService implements DestinationService {
private final static UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
private static boolean isDestinationDefinitionResolved;
@Override
public void start(DestinationAction ){
...
}
...
protected abstract List<DestinationDefinition> getDestinationDefinitions();
}
方法getDestinationDefinitions
由子类来实现,主要提供此路由目标的相关信息, DestinationDefinition
类如下:
public class DestinationDefinition {
private final String name;
private final Class<?> destination;
private final List<DestinationArgumentDefinition> inArgumentDefinitions;
private final List<DestinationArgumentDefinition> outArgumentDefinitions;
public DestinationDefinition(String name, Class<?> destination, List<DestinationArgumentDefinition> inArgumentDefinitions, List<DestinationArgumentDefinition> outArgumentDefinitions) {
this.name = name;
this.destination = destination;
this.inArgumentDefinitions = inArgumentDefinitions;
this.outArgumentDefinitions = outArgumentDefinitions;
}
public String getName() {
return name;
}
public Class<?> getDestination() {
return destination;
}
public List<DestinationArgumentDefinition> getInArgumentDefinitions() {
return inArgumentDefinitions;
}
public List<DestinationArgumentDefinition> getOutArgumentDefinitions() {
return outArgumentDefinitions;
}
}
AbstractUriDestinationService
类中的start方法实现真正的跳转逻辑:
public abstract class AbstractUriDestinationService implements DestinationService {
private final static UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
private static boolean isDestinationDefinitionResolved;
@Override
public void start(DestinationAction destinationAction) {
List<DestinationDefinition> destinationDefinitions = getDestinationDefinitions();
resolveDestinationDefinition(destinationDefinitions);
Context context = destinationAction.getContext();
if (context == null) {
throw new IllegalArgumentException("content == null");
}
PackageManager packageManager = context.getPackageManager();
if (destinationAction instanceof UriDestinationAction) {
Uri uri = ((UriDestinationAction) destinationAction).getUri();
int index = matcher.match(uri);
if (UriMatcher.NO_MATCH == index || index >= destinationDefinitions.size()) {
throw new IllegalStateException("Not found destination for : " + uri);
}
DestinationDefinition destinationDefinition = destinationDefinitions.get(index);
List<DestinationArgumentDefinition> destinationArgumentDefinitions = destinationDefinition.getInArgumentDefinitions();
for (DestinationArgumentDefinition argumentDefinition : destinationArgumentDefinitions) {
Bundle args = destinationAction.getArguments();
if (argumentDefinition.isRequire() && !args.containsKey(argumentDefinition.getKey())) {
throw new IllegalArgumentException("No such key: " + argumentDefinition.getKey());
}
}
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(uri);
if (packageManager.resolveActivity(intent, 0) == null) {
if (destinationAction.getUriOnly()) {
throw new IllegalStateException("Not found activity for : " + uri);
} else {
intent = new Intent(context, destinationDefinition.getDestination());
if (packageManager.resolveActivity(intent, 0) == null) {
throw new IllegalStateException("Not found activity for : " + uri);
}
}
}
intent.addFlags(destinationAction.getFlags());
Bundle args = destinationAction.getArguments();
if (args != null) {
intent.putExtras(args);
}
if (context instanceof Activity) {
((Activity) context).startActivityForResult(intent, destinationAction.getRequestCode());
} else {
context.startActivity(intent);
}
} else {
throw new IllegalStateException("Not support operate");
}
}
private static void resolveDestinationDefinition(List<DestinationDefinition> destinationDefinitions) {
if (isDestinationDefinitionResolved) {
return;
}
int index = 0;
for (DestinationDefinition destinationDefinition : destinationDefinitions) {
if (destinationDefinition instanceof UriDestinationDefinition) {
Uri uri = ((UriDestinationDefinition) destinationDefinition).getUri();
String stringForUri = uri.toString();
String path = uri.getPath();
int pathIndex = stringForUri.indexOf(path);
if (pathIndex != -1) {
path = stringForUri.substring(
pathIndex,
stringForUri.length()
);
}
matcher.addURI(uri.getAuthority(), path, index++);
}
}
isDestinationDefinitionResolved = true;
}
protected abstract List<DestinationDefinition> getDestinationDefinitions();
}
这样通过实现AbstractUriDestinationService
类,提供相应的DestinationDefinition
就可以实现路由的跳转功能,由于使用的注册我们可以使用AnnotationProcessor
来处理注解生成DestinationService
的实现类。
源码下载: https://github.com/yjwfn/AndroidRouterSample
标签:start 输出 undle substr port 理解 来讲 tostring on()
原文地址:https://www.cnblogs.com/xwgblog/p/9372398.html