引入
一个应用中有许多页面,有些页面是需要登录才能看的,当我们进行页面跳转时会先判断用户是否登录,如果已经登录,则正常跳转,如果没有登录,则跳转到登录页面先登录,但凡是有注册,登录的APP,这样的操作,大家应该都很熟悉吧。一般情况下,我们的逻辑是这样的:
if (TextUtils.isEmpty(HeaderUtils.getSessionId())) {//还没登录,先跳转登录页面
Intent intent = new Intent(this, LoginActivity.class);
startActivity(intent);
} else {//已经登录了,跳转订单页面
Intent intent = new Intent(this, OrderActivity.class);
startActivity(intent);
}
上面的做法需要在每一个目标页面重复做登陆检查,这样设计的扩展性并不友好。在这里介绍阿里的ARouter路由框架,可以更加优雅的实现登录拦截功能。
ARoute功能介绍
- 支持直接解析标准URL进行跳转,并自动注入参数到目标页面中
- 支持多模块工程使用
- 支持添加多个拦截器,自定义拦截顺序
- 支持依赖注入,可单独作为依赖注入框架使用
- 支持InstantRun
- 支持MultiDex(Google方案)
- 映射关系按组分类、多级管理,按需初始化
- 支持用户指定全局降级与局部降级策略
- 页面、拦截器、服务等组件均自动注册到框架
- 支持多种方式配置转场动画
- 支持获取Fragment
- 完全支持Kotlin以及混编()
- 支持第三方 App 加固(使用 arouter-register 实现自动注册)
- 支持生成路由文档
使用方法
1.gradle配置
android {
defaultConfig {
...
javaCompileOptions {
annotationProcessorOptions {
arguments = [AROUTER_MODULE_NAME: project.getName()]
}
}
}
}
dependencies {
...
implementation 'com.alibaba:arouter-api:1.4.0'
annotationProcessor 'com.alibaba:arouter-compiler:1.2.1'
}
2.Application初始化sdk
if (BuildConfig.DEBUG) {
// 这两行必须写在init之前,否则这些配置在init过程中将无效
ARouter.openLog(); // 打印日志
ARouter.openDebug();// 开启调试模式(如果在InstantRun模式下运行,必须开启调试模式!线上版本需要关闭,否则有安全风险)}
}
ARouter.init(this);// 尽可能早,推荐在Application中初始化
3.添加注解
public class BaseActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//在baseActivity自动注入属性
ARouter.getInstance().inject(this);
}
}
//对应的Activity 添加@Route注解 path路径 这里的路径需要注意的是至少需要有两级,/xx/xx
@Route(path = RoutePath.FIRST_PATH)
public class FirstActivity extends BaseActivity {
@Autowired
public String msg;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_first);
((TextView)findViewById(R.id.tv_msg)).setText(msg);
}
}
4.拦截器的使用面向切面编程
// 在跳转过程中处理登陆事件,这样就不需要在目标页重复做登陆检查
// 拦截器会在跳转之间执行,多个拦截器会按优先级顺序依次执行
@Interceptor(name = "login", priority = 6)
public class LoginInterceptorImpl implements IInterceptor {
@Override
public void process(Postcard postcard, InterceptorCallback callback) {
String path = postcard.getPath();
LogUtils.e(path);
boolean isLogin = SPUtils.getInstance().getBoolean(RoutePath.SP_IS_LOGIN, false);
if (isLogin) { // 如果已经登录不拦截
callback.onContinue(postcard);
} else { // 如果没有登录
switch (path) {
// 不需要登录的直接进入这个页面
case RoutePath.LOGIN_PATH:
case RoutePath.FIRST_PATH:
callback.onContinue(postcard);
break;
// 需要登录的直接拦截下来
default:
callback.onInterrupt(null);
break;
}
}
}
@Override
public void init(Context context) {//此方法只会走一次
LogUtils.e("路由登录拦截器初始化成功");
}
}
//启动Activity
ARouter.getInstance().build(RoutePath.SECOND_PATH)
.withString("msg", "ARouter传递过来的需要登录的参数msg")
.navigation(this,new LoginNavigationCallbackImpl());//第二个参数是路由跳转的回调
public class LoginNavigationCallbackImpl implements NavigationCallback {
@Override //找到了
public void onFound(Postcard postcard) {
}
@Override //找不到了
public void onLost(Postcard postcard) {
}
@Override //跳转成功了
public void onArrival(Postcard postcard) {
}
@Override
public void onInterrupt(Postcard postcard) {
String path = postcard.getPath();
LogUtils.v(path);
Bundle bundle = postcard.getExtras();
// 被登录拦截了下来了
// 需要调转到登录页面,把参数跟被登录拦截下来的路径传递给登录页面,登录成功后再进行跳转被拦截的页面
ARouter.getInstance().build(RoutePath.LOGIN_PATH)
.with(bundle)
.withString(RoutePath.PATH, path)
.navigation();
}
}