参考资料
ARouter官方项目地址
https://github.com/alibaba/ARouter
探索Android路由框架-ARouter之基本使用(一)
https://www.jianshu.com/p/6021f3f61fa6
配置ARouter
在app
下的build.gradle中添加如下配置即可完成
javaCompileOptions {
annotationProcessorOptions {
arguments = [moduleName :project.getName() ]
}
}
dependencies
{
implementation 'com.alibaba:arouter-api:1.3.1'
annotationProcessor 'com.alibaba:arouter-compiler:1.1.4'
}
初始化与销毁
初始化
将ARouter的初始化工作放在MyApplication中, 这里需要注意的是我们一定要将这个MyApplication配置到Androidmanifest.xml
文件中去,否则初始化不会生效。
import android.app.Application;
import com.alibaba.android.arouter.launcher.ARouter;
public class MyApplication extends Application {
private boolean isDebug = true;
@Override
public void onCreate()
{
super.onCreate();
if(isDebug)
{
ARouter.openDebug();
ARouter.openLog();
}
//注解初始化ARoute
ARouter.init(this);
}
}
<application
android:name="cheery.arouter.demo.MyApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
</application>
销毁
放在主Activity的onDestroy()方法或者程序退出的代码中即可
@Override
public void onDestroy()
{
super.onDestroy();
ARouter.getInstance().destroy();
}
路由注解与跳转
- 因为是路由,所以
至少有两级
,也就是说至少有两个Activity或者或一个Activity和多个Fragment被注册进了路由中,这也才能进行Activity的跳转和fragment之间的切换.
- 配置路由使用
@Route
注解来完成,标准的语法是@Route(path = "/xx/xx")
- 在需要注册路由的地方配置完
@Route
注解属性后,使用ARouter.getInstance().inject(this);
来进行路由注册。
Activity之间的跳转
路径定义
创建一个常量类,里面保存我们所有的路由路径
public class Constant {
public final static String HOME_MAIN_ACTIVITY_URL = "/Home/MainActivity";
public final static String HOME_SIMPLE_ACTIVITY_URL = "/Home/SimpleActivity";
public final static String HOME_SECOND_ACTIVITY_URL = "/Home/SecondActivity";
public final static String HOME_FIRST_FRAGMENT_URL = "/Home/FirstFragment";
public final static String HOME_SECOND_FRAGMENT_URL = "/Home/SecondFragment";
public final static String HOME_THIRD_FRAGMENT_URL = "/Home/ThirdFragment";
}
代码示例
我们定义两个Activity,分别为MainActivity和SimpleActivity, 内容如下
@Route(path = Constant.HOME_MAIN_ACTIVITY_URL)
public class MainActivity extends AppCompatActivity {
private static String TAG = "MainActivity";
private final static int PushToSimpleActivity = 1001;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ARouter.getInstance().inject(this);
}
}
@Route(path = Constant.HOME_SIMPLE_ACTIVITY_URL)
public class SimpleActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_simple);
ARouter.getInstance().inject(this);
}
}
使用如下几种方式都可以进行简单的路由跳转
ARouter.getInstance().build(Constant.HOME_SIMPLE_ACTIVITY_URL).navigation();
Uri uri = Uri.parse(Constant.HOME_SIMPLE_ACTIVITY_URL);
ARouter.getInstance().build(uri).navigation();
Uri uri = Uri.parse(Constant.HOME_SIMPLE_ACTIVITY_URL);
ARouter.getInstance()
.build(uri)
.navigation(v.getContext(), new NavigationCallback() {
@Override
public void onFound(Postcard postcard) {
Log.i(TAG, "onFound");
}
@Override
public void onLost(Postcard postcard) {
Log.i(TAG, "onLost");
}
@Override
public void onArrival(Postcard postcard) {
Log.i(TAG, "onArrival");
}
@Override
public void onInterrupt(Postcard postcard) {
Log.i(TAG, "onInterrupt");
}
});
正常情况下,我们跳转完成后,Logcat下回输出如下日志
I/MainActivity: onFound
I/MainActivity: onArrival
如果跳转的途中被我们自定义的拦截器拦截了,会输出
I/MainActivity: onFound
I/MainActivity: onInterrupt
I/MainActivity: onArrival
如果需要跳转的路由节点未注册,则会输出
I/MainActivity: onLost
Fragment之间的切换
Fragment注入路由
@Route(path = Constant.HOME_FIRST_FRAGMENT_URL)
public class FirstFragment extends Fragment {
View view;
@Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState){
super.onCreateView(inflater,
container, savedInstanceState);
if(null == view)
{
view =
inflater.inflate(R.layout.first_fragment, null);
}
return view;
}
}
@Route(path = Constant.HOME_SECOND_FRAGMENT_URL)
public class SecondFragment extends Fragment {
View view;
@Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState){
super.onCreateView(inflater,
container, savedInstanceState);
if(null == view)
{
view =
inflater.inflate(R.layout.second_fragment, null);
}
return view;
}
}
@Route(path = Constant.HOME_THIRD_FRAGMENT_URL)
public class ThirdFragment extends Fragment {
View view;
@Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState){
super.onCreateView(inflater,
container, savedInstanceState);
if(null == view){
view = inflater.inflate(R.layout.third_fragment, null);
}
return view;
}
}
Fragment的获取与切换
我们可以通过制定路由路径来对Fragment进行获取, 如:
String url = Constant.HOME_FIRST_FRAGMENT_URL;
Fragment fragment = (Fragment)ARouter.getInstance().build(url).navigation();
进行Fragment切换
int index = 0;
public void OnClickSwitchFragmentView(View v)
{
if(index < 2){
index++;
}else{
index = 0;
}
String url = Constant.HOME_FIRST_FRAGMENT_URL;
switch(index){
case 0:
url = Constant.HOME_FIRST_FRAGMENT_URL;
break;
case 1:
url = Constant.HOME_SECOND_FRAGMENT_URL;
break;
case 2:
url = Constant.HOME_THIRD_FRAGMENT_URL;
break;
default:
url = Constant.HOME_FIRST_FRAGMENT_URL;
break;
}
Fragment fragment =
(Fragment)ARouter.getInstance().build(url).navigation();
FragmentTransaction fragmentTransaction =
getFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.middleLayout, fragment);
fragmentTransaction.commit();
}
带参数的跳转
路由跳转的时候,可以传入常用的基本类型,也可以传入实现了**Parcelable
接口的类示例和类示例数组。我们只需要实现Parcelable
接口**就可以了,无需手动在一行行实现赋值拷贝工作。
示例代码
import android.os.Parcel;
import android.os.Parcelable;
public class Student implements Parcelable {
private String name;
private int age;
public Student(String name, int age)
{
this.setName(name);
this.setAge(age);
}
protected Student(Parcel in) {
name = in.readString();
age = in.readInt();
}
public static final
Creator<Student> CREATOR = new Creator<Student>() {
@Override
public Student createFromParcel(Parcel in) {
return new Student(in);
}
@Override
public Student[] newArray(int size) {
return new Student[size];
}
};
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);
dest.writeInt(age);
}
}
进行带参数的跳转操作
ARouter.getInstance().build(Constant.HOME_SIMPLE_ACTIVITY_URL)
.withBoolean("loginResult", true)
.withDouble("amount", 20000.5)
.withString("name", "张超")
.withInt("age", 28)
.with("student", new Student("张飞", 32))
.navigation();
接收传递的参数
传统的Intent传值的方式,我们需要使用getIntent.getXXX
的方式来进行值得获取,ARouter为我们提供了一种更加方便的获取传值的方式,使用**@Autowired(name = "参数名")
**这种自动装载的方式来完成传值的获取与反序列化转换
,装载完毕后就可以进行自由使用这些传递过来的参数了。
注意: 使用@Autowired
自动装载注解,name后参数名称一定要和传入参数的名称一致,否则自动装载失败
,使用参数值是可能会引发异常[通常发生在自定义数据类型中,会出现空指针异常]。
示例代码
@Route(path = Constant.HOME_SIMPLE_ACTIVITY_URL)
public class SimpleActivity extends AppCompatActivity {
//必须制定传递过来的参数名称,然后进行自动装载
@Autowired(name = "age")
int age;
@Autowired(name = "name")
String name;
@Autowired(name = "amount")
double amount;
@Autowired(name = "loginResult")
boolean loginResult;
@Autowired(name = "student")
Student student;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_simple);
ARouter.getInstance().inject(this);
if(age <= 0)
{
return;
}
Toast.makeText(this,
"姓名: " + name +
", 年龄: " + age +
", 余额: " + amount +
", 登录结果: " + loginResult +
", 学生姓名: " + student.getName() +
", 学生年龄: " + student.getAge(),
Toast.LENGTH_LONG).show();
}
}
路由回调
通过在navigation
方法中传入Context
和requestCode
来实现路由的回调请求
private final static int PushToSimpleActivity = 1001;
ARouter.getInstance().build(Constant.HOME_SIMPLE_ACTIVITY_URL)
.navigation(MainActivity.this, PushToSimpleActivity);
在SimpleActivity中进行回调,这里还是和传统的一样,可以设置resultCode和回调Intent.
public void OnClickFinishActivityView(View v){
setResult(200);
finish();
}
在路由的发起者MainActivity
中进行回调监听
protected void onActivityResult(int requestCode,
int resultCode, Intent data){
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode){
case PushToSimpleActivity:
if(resultCode == 200)
{
Toast.makeText(this, "收到回调了",
Toast.LENGTH_LONG).show();
}
break;
}
}
拦截器
基本语法
- 实现
IInterceptor
接口来自定义一个拦截器
- 通过
@Interceptor(priority=x)
来进行拦截器注入,这里的priority
不能发生重复, 否则会报下面的错误
Compilation failed; see the compiler error output for details.
`priority`的值越小优先级越高。
- 拦截器可以对路由的跳转进行截断,然后重新跳转到一个新的位置。常用操作如:在用户未登录的状态下,跳转到登录界面。
- 拦截器中可以获取到当前跳转的路由群组和路径地图信息。
定义拦截器
代码示例
@Interceptor(priority = 1)
public class LoginInterceptor implements IInterceptor {
private final static String TAG = "LoginInterceptor";
@Override
public void process(Postcard postcard,
InterceptorCallback callback) {
Log.i(TAG, "LoginInterceptor called process");
Log.i(TAG, "group: " + postcard.getGroup() +
", path: " + postcard.getPath());
if(postcard.getPath().equals(
Constant.HOME_SIMPLE_ACTIVITY_URL)){
Log.i(TAG, "路由跳转被登录拦截器拦截了");
}
//拦截,然后抛出异常
void onInterrupt(exception);
}
@Override
public void init(Context context) {
Log.i(TAG, "LoginInterceptor is init");
}
}
@Interceptor(priority = 10)
public class AccountInterceptor implements IInterceptor {
private final static String TAG = "AccountInterceptor";
@Override
public void process(Postcard postcard,
InterceptorCallback callback) {
Log.i(TAG, "AccountInterceptor called process");
Log.i(TAG, "group: " + postcard.getGroup() +
", path: " + postcard.getPath());
callback.onContinue(postcard);
}
@Override
public void init(Context context) {
Log.i(TAG, "AccountInterceptor is init");
}
}
在注入了两个拦截器后,我们的每一次路由跳转都会经过拦截器的处理来决定是继续跳转还是异常截断重新自定义跳转。