按照ARouter学习之三——注解解析器(arouter-compiler源码)的结尾,似乎这应该是学习之四,但我选择标题起为之一,虽说是后面才写,但毕竟学习的话都是先学会用,再去弄懂原理。而总结顺序,则是根据好奇心的顺序来整理。
本文的初衷:搞懂在项目中怎样引入ARouter并加以使用
目录
引入ARouter建立依赖
该小节的内容均引自github上的文档,若需要请稳步:https://github.com/alibaba/ARouter/blob/master/README_CN.md
build.gradle文件内容如下:
android {
defaultConfig {
...
javaCompileOptions {
annotationProcessorOptions {
arguments = [AROUTER_MODULE_NAME: project.getName()]
}
}
}
}
dependencies {
// 替换成最新版本, 需要注意的是api
// 要与compiler匹配使用,均使用最新版可以保证兼容
compile 'com.alibaba:arouter-api:x.x.x'
annotationProcessor 'com.alibaba:arouter-compiler:x.x.x'
...
}
最可能早的注册ARouter,在MyApplication中进行初始化
if (isDebug()) { // 这两行必须写在init之前,否则这些配置在init过程中将无效
ARouter.openLog(); // 打印日志
ARouter.openDebug(); // 开启调试模式(如果在InstantRun模式下运行,必须开启调试模式!线上版本需要关闭,否则有安全风险)
}
ARouter.init(mApplication); // 尽可能早,推荐在Application中初始化
至此,完成依赖的建立,接下来就可以正常使用。
各类简单的跳转
通过前两篇的源码阅读RouteType类,我们知道ARouter支持跳转的对象包括:Activity、Fragment、Service,本节来看看如何使用ARouter框架来进行这样的跳转。其步骤可拆分成两步:添加注解和发起路由操作。
添加注解:
// 在支持路由的页面上添加注解(必选)
// 这里的路径需要注意的是至少需要有两级,/xx/xx
@Route(path = "/test/activity")
public class YourActivity extend Activity {
...
}
注意path必须不能少于两级,若只是[/xx]的话,则ARouter会抛出数组越界异常,原因是在源码中获取路由“组”指明确指出的。下一篇文章重点分析为什么发起路由操作时就可以进行跳转时,会分析到这块的代码。请稳步我之前的文章(在学习ARouter源码前自己挖的坑)ARouter报错:Failed to extract default group! String index out of range: -2
然后,就可以发起路由操作了。
// 1. 应用内简单的跳转(通过URL跳转在'进阶用法'中)
ARouter.getInstance().build("/test/activity").navigation();
// 2. 跳转并携带参数
ARouter.getInstance().build("/test/1")
.withLong("key1", 666L)
.withString("key3", "888")
.withObject("key4", new Test("Jack", "Rose"))
.navigation();
简而言之,就是获取ARouter单例后,调用build传入路径,若有参数,则通过withType添加键值对,最后调用naigation()方法即可。
我怎么知道这些的呢?这是我必须告诉读者的,鱼与渔。ARouter的github上的指南以及它的源码。
上面是跳转到Activity,并传递简单的参数,下面列下跳转Fragment和Service的代码,实质实际是完全一样的。
@Route(path = "/test/fragment")
public class BlankFragment extends Fragment {
@Autowired
String name;
...
}
case R.id.getFragment:
Fragment fragment = (Fragment) ARouter.getInstance().build("/test/fragment").navigation();
Toast.makeText(this, "找到Fragment:" + fragment.toString(), Toast.LENGTH_SHORT).show();
break;
import com.alibaba.android.arouter.facade.template.IProvider;
//需要继承IProvider
public interface HelloService extends IProvider {
void sayHello(String name);
}
//接口实现类
@Route(path = "/yourservicegroupname/hello")
public class HelloServiceImpl implements HelloService {
Context mContext;
@Override
public void sayHello(String name) {
Toast.makeText(mContext, "Hello " + name, Toast.LENGTH_SHORT).show();
}
/**
* Do your init work in this method, it well be call when processor has been load.
*
* @param context ctx
*/
@Override
public void init(Context context) {
mContext = context;
Log.e("testService", HelloService.class.getName() + " has init.");
}
}
发起Service路由,有两种方式,一种通过路由路径,一种通过类
case R.id.navByName:
((HelloService) ARouter.getInstance().build("/yourservicegroupname/hello").navigation()).sayHello("mike");
break;
case R.id.navByType:
ARouter.getInstance().navigation(HelloService.class).sayHello("mike");
break;
目标界面接收参数
前面通过.withString()等方法传入了对应类似的数据,目标界面需要代码实现这个数据的接收。有两种方式:一通过注解;二通过Intent本身接收。下面摘录ARouter源码中Demo工程的Test1Activity.java来说明这两种方式。
@Route(path = "/test/activity1", name = "测试用 Activity")
public class Test1Activity extends AppCompatActivity {
@Autowired(desc = "姓名")
String name = "jack";
@Autowired
int age = 10;
@Autowired
int height = 175;
@Autowired(name = "boy", required = true)
boolean girl;
@Autowired
char ch = 'A';
//方式一,并附默认值
@Autowired
float fl = 12.00f;
@Autowired
double dou = 12.01d;
@Autowired
TestSerializable ser;
@Autowired
TestParcelable pac;
@Autowired
TestObj obj;
@Autowired
List<TestObj> objList;
@Autowired
Map<String, List<TestObj>> map;
private long high;
@Autowired
String url;
@Autowired
HelloService helloService;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test1);
ARouter.getInstance().inject(this); //方式一:通过注解,必须添加该句
//方式二:为下方注释掉的代码,它取Intent本身的bundle,其实方式一本质也是
//只是被注解解释处理了。
// No more getter ...
// name = getIntent().getStringExtra("name");
// age = getIntent().getIntExtra("age", 0);
// girl = getIntent().getBooleanExtra("girl", false);
// high = getIntent().getLongExtra("high", 0);
// url = getIntent().getStringExtra("url");
}
}
截止目前,我们完成了构建依赖和路由跳转及参数传递。下面看下高级用法。
ARouter进阶高级用法
1.通过URL跳转
// 新建一个Activity用于监听Schame事件,之后直接把url传递给ARouter即可
public class SchameFilterActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 直接通过ARouter处理外部Uri
Uri uri = getIntent().getData();
ARouter.getInstance().build(uri).navigation(this, new NavCallback() {
@Override
public void onArrival(Postcard postcard) {
finish();
}
}
}
//---------AndroidManifest.xml---------//
<activity android:name=".activity.SchameFilterActivity">
<!-- Schame -->
<intent-filter>
<data
android:host="m.aliyun.com"
android:scheme="arouter"/>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
</intent-filter>
</activity>
2.解析高级参数:List、Map、对象
ARouter对高级对象的参数传递也是支持,实现如下
// 为每一个参数声明一个字段,并使用 @Autowired 标注
// URL中不能传递Parcelable类型数据,通过ARouter api可以传递Parcelable对象
@Route(path = "/test/activity")
public class Test1Activity extends Activity {
@Autowired
public String name;
@Autowired
int age;
// 通过name来映射URL中的不同参数
@Autowired(name = "girl")
boolean boy;
// 支持解析自定义对象,URL中使用json传递
@Autowired
TestObj obj;
// 使用 withObject 传递 List 和 Map 的实现了
// Serializable 接口的实现类(ArrayList/HashMap)
// 的时候,接收该对象的地方不能标注具体的实现类类型
// 应仅标注为 List 或 Map,否则会影响序列化中类型
// 的判断, 其他类似情况需要同样处理
@Autowired
List<TestObj> list;
@Autowired
Map<String, List<TestObj>> map;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ARouter.getInstance().inject(this);
// ARouter会自动对字段进行赋值,无需主动获取
Log.d("param", name + age + boy);
}
}
// 如果需要传递自定义对象,新建一个类(并非自定义对象类),然后实现 SerializationService,并使用@Route注解标注(方便用户自行选择序列化方式),例如:
@Route(path = "/yourservicegroupname/json")
public class JsonServiceImpl implements SerializationService {
@Override
public void init(Context context) {
}
@Override
public <T> T json2Object(String text, Class<T> clazz) {
return JSON.parseObject(text, clazz);
}
@Override
public String object2Json(Object instance) {
return JSON.toJSONString(instance);
}
}
3.处理跳转结果
// 使用两个参数的navigation方法,可以获取单次跳转的结果
ARouter.getInstance().build("/test/1").navigation(this, new NavigationCallback() {
@Override
public void onFound(Postcard postcard) {
...
}
@Override
public void onLost(Postcard postcard) {
...
}
});
4.预处理服务
// 实现 PretreatmentService 接口,并加上一个Path内容任意的注解即可
@Route(path = "/xxx/xxx")
public class PretreatmentServiceImpl implements PretreatmentService {
@Override
public boolean onPretreatment(Context context, Postcard postcard) {
// 跳转前预处理,如果需要自行处理跳转,该方法返回 false 即可
}
@Override
public void init(Context context) {
}
}
5.详细API说明
// 构建标准的路由请求
ARouter.getInstance().build("/home/main").navigation();
// 构建标准的路由请求,并指定分组
ARouter.getInstance().build("/home/main", "ap").navigation();
// 构建标准的路由请求,通过Uri直接解析
Uri uri;
ARouter.getInstance().build(uri).navigation();
// 构建标准的路由请求,startActivityForResult
// navigation的第一个参数必须是Activity,第二个参数则是RequestCode
ARouter.getInstance().build("/home/main", "ap").navigation(this, 5);
// 直接传递Bundle
Bundle params = new Bundle();
ARouter.getInstance()
.build("/home/main")
.with(params)
.navigation();
// 指定Flag
ARouter.getInstance()
.build("/home/main")
.withFlags();
.navigation();
// 获取Fragment
Fragment fragment = (Fragment) ARouter.getInstance().build("/test/fragment").navigation();
// 对象传递
ARouter.getInstance()
.withObject("key", new TestObj("Jack", "Rose"))
.navigation();
// 觉得接口不够多,可以直接拿出Bundle赋值
ARouter.getInstance()
.build("/home/main")
.getExtra();
// 转场动画(常规方式)
ARouter.getInstance()
.build("/test/activity2")
.withTransition(R.anim.slide_in_bottom, R.anim.slide_out_bottom)
.navigation(this);
// 转场动画(API16+)
ActivityOptionsCompat compat = ActivityOptionsCompat.
makeScaleUpAnimation(v, v.getWidth() / 2, v.getHeight() / 2, 0, 0);
// ps. makeSceneTransitionAnimation 使用共享元素的时候,需要在navigation方法中传入当前Activity
ARouter.getInstance()
.build("/test/activity2")
.withOptionsCompat(compat)
.navigation();
// 使用绿色通道(跳过所有的拦截器)
ARouter.getInstance().build("/home/main").greenChannel().navigation();
// 使用自己的日志工具打印日志
ARouter.setLogger();
// 使用自己提供的线程池
ARouter.setExecutor();
小结
使用一个框架来讲,还是相对简单。就像刚开始学习Java一样,人家API就是这么定义,根据你想实现的效果去找到对应的API,然后进行实现即可。
PS:高级进阶用法是不全面的,详细请稳步github上的文档。中文地址:https://github.com/alibaba/ARouter/blob/master/README_CN.md
看完后,来打我吧。哈哈,因为本文除了部分源码外,多数出自github上的文档,但这也是学习一个框架最官方的方法(假设没有前辈整理)。
下一篇是最难的,源码功能分析,解释为什么API就生效,完成了我们想要的路由跳转和参数传递等功能。