前言
在日常开发中,遇到需要登录后才能跳转的目标页面时,大多数写法如下:
if(登录校验逻辑) {
已登录,跳转至目标页。
} else {
未登录或登录过期时,跳转至登录页面。
}
针对未登录或登录过期时,跳转到登录页面进行登录,登录完成后要么发送一条广播,要么借助一些主流的三方框架(如:RxJava, EventBus等)来通知登录状态,获取到登录状态后跳转到目标页面,这种写法看似简单,但写的多了,就变得冗余了,自定义一个RouteHelper来优化这种跳转流程。
场景流程图
定义一个Intent包装类
Activity与Activity之间跳转时,根据业务需求往往都会传递一些数据,这些数据通过Bundle来存储。,定义一个RouteMeta对象,用来收集跳转到目标页时所需信息。
public class RouteMeta extends ContextWrapper {
private final Bundle bundle;
private final Class<?> destination;
private boolean isNeedAuth = false;
// 认证类型,AuthMode
public static final String EXTRA_AUTH_MODE = "auth_mode";
// 在打开某个页面时,如果需要登录,此时账户为退登状态,先打开登陆页面,登录成功后再跳转目标页面。
static final String AFTER_AUTH_JUMP_TO_TARGET_PAGE = "jump_to_target_page";
public RouteMeta(@NonNull Context base, @NonNull Class<?> destination) {
this(base, destination, null);
}
public RouteMeta(@NonNull Context base, @NonNull Class<?> destination, @Nullable Bundle extras) {
super(base);
this.destination = destination;
this.bundle = (null == extras ? new Bundle() : extras);
}
public Class<?> getDestination() {
return destination;
}
public Bundle getBundle() {
return bundle;
}
/**
* 是否需要登录
* @param isNeedAuth true:需要登录,false:不需要登录
* @return current
*/
public RouteMeta setNeedAuth(boolean isNeedAuth) {
this.isNeedAuth = isNeedAuth;
return this;
}
public boolean isNeedAuth() {
return isNeedAuth;
}
/**
* @param key a String, or null
* @param value a String, or null
* @return current
*/
public RouteMeta withString(@Nullable String key, @Nullable String value) {
bundle.putString(key, value);
return this;
}
/**
* @param key a String, or null
* @param value a boolean
* @return current
*/
public RouteMeta withBoolean(@Nullable String key, boolean value) {
bundle.putBoolean(key, value);
return this;
}
/**
* @param key a String, or null
* @param value a short
* @return current
*/
public RouteMeta withShort(@Nullable String key, short value) {
bundle.putShort(key, value);
return this;
}
/**
* @param key a String, or null
* @param value an int
* @return current
*/
public RouteMeta withInt(@Nullable String key, int value) {
bundle.putInt(key, value);
return this;
}
/**
* @param key a String, or null
* @param value a long
* @return current
*/
public RouteMeta withLong(@Nullable String key, long value) {
bundle.putLong(key, value);
return this;
}
/**
* @param key a String, or null
* @param value a double
* @return current
*/
public RouteMeta withDouble(@Nullable String key, double value) {
bundle.putDouble(key, value);
return this;
}
/**
* @param key a String, or null
* @param value a byte
* @return current
*/
public RouteMeta withByte(@Nullable String key, byte value) {
bundle.putByte(key, value);
return this;
}
/**
* @param key a String, or null
* @param value a char
* @return current
*/
public RouteMeta withChar(@Nullable String key, char value) {
bundle.putChar(key, value);
return this;
}
/**
* @param key a String, or null
* @param value a float
* @return current
*/
public RouteMeta withFloat(@Nullable String key, float value) {
bundle.putFloat(key, value);
return this;
}
/**
* @param key a String, or null
* @param value a CharSequence, or null
* @return current
*/
public RouteMeta withCharSequence(@Nullable String key, @Nullable CharSequence value) {
bundle.putCharSequence(key, value);
return this;
}
/**
* @param key a String, or null
* @param value a Parcelable object, or null
* @return current
*/
public RouteMeta withParcelable(@Nullable String key, @Nullable Parcelable value) {
bundle.putParcelable(key, value);
return this;
}
/**
* @param key a String, or null
* @param value an array of Parcelable objects, or null
* @return current
*/
public RouteMeta withParcelableArray(@Nullable String key, @Nullable Parcelable[] value) {
bundle.putParcelableArray(key, value);
return this;
}
/**
* @param key a String, or null
* @param value an ArrayList of Parcelable objects, or null
* @return current
*/
public RouteMeta withParcelableArrayList(@Nullable String key, @Nullable ArrayList<? extends Parcelable> value) {
bundle.putParcelableArrayList(key, value);
return this;
}
/**
* @param key a String, or null
* @param value a SparseArray of Parcelable objects, or null
* @return current
*/
public RouteMeta withSparseParcelableArray(@Nullable String key, @Nullable SparseArray<? extends Parcelable> value) {
bundle.putSparseParcelableArray(key, value);
return this;
}
/**
* @param key a String, or null
* @param value an ArrayList object, or null
* @return current
*/
public RouteMeta withIntegerArrayList(@Nullable String key, @Nullable ArrayList<Integer> value) {
bundle.putIntegerArrayList(key, value);
return this;
}
/**
* @param key a String, or null
* @param value an ArrayList object, or null
* @return current
*/
public RouteMeta withStringArrayList(@Nullable String key, @Nullable ArrayList<String> value) {
bundle.putStringArrayList(key, value);
return this;
}
/**
* @param key a String, or null
* @param value an ArrayList object, or null
* @return current
*/
public RouteMeta withCharSequenceArrayList(@Nullable String key, @Nullable ArrayList<CharSequence> value) {
bundle.putCharSequenceArrayList(key, value);
return this;
}
/**
* @param key a String, or null
* @param value a Serializable object, or null
* @return current
*/
public RouteMeta withSerializable(@Nullable String key, @Nullable Serializable value) {
bundle.putSerializable(key, value);
return this;
}
/**
* @param key a String, or null
* @param value a byte array object, or null
* @return current
*/
public RouteMeta withByteArray(@Nullable String key, @Nullable byte[] value) {
bundle.putByteArray(key, value);
return this;
}
/**
* @param key a String, or null
* @param value a short array object, or null
* @return current
*/
public RouteMeta withShortArray(@Nullable String key, @Nullable short[] value) {
bundle.putShortArray(key, value);
return this;
}
/**
* @param key a String, or null
* @param value a char array object, or null
* @return current
*/
public RouteMeta withCharArray(@Nullable String key, @Nullable char[] value) {
bundle.putCharArray(key, value);
return this;
}
/**
* @param key a String, or null
* @param value a float array object, or null
* @return current
*/
public RouteMeta withFloatArray(@Nullable String key, @Nullable float[] value) {
bundle.putFloatArray(key, value);
return this;
}
/**
* @param key a String, or null
* @param value a CharSequence array object, or null
* @return current
*/
public RouteMeta withCharSequenceArray(@Nullable String key, @Nullable CharSequence[] value) {
bundle.putCharSequenceArray(key, value);
return this;
}
/**
* @param key a String, or null
* @param value a Bundle object, or null
* @return current
*/
public RouteMeta withBundle(@Nullable String key, @Nullable Bundle value) {
bundle.putBundle(key, value);
return this;
}
/**
* 导航到目标页。
*/
public void navigation() {
// 1、无需登录,直接打开页面。
if (!isNeedAuth()) {
Intent intent = new Intent(this, getDestination());
if (getBundle() != null) intent.putExtras(getBundle());
startActivity(intent);
return;
}
// 2、需要登录,Token有效,直接登录。
if (AccountHelper.getDefault().isAuthToken()) {
Intent intent = new Intent(this, getDestination());
if (getBundle() != null) intent.putExtras(getBundle());
startActivity(intent);
return;
}
// 3、需要登录,Token无效跳转到登录页面。
Intent intent = new Intent(this, RouteHelper.getDefault().getAuthPage());
intent.putExtra(EXTRA_AUTH_MODE, AuthMode.PHONE_LOGIN.name());
intent.putExtra(AFTER_AUTH_JUMP_TO_TARGET_PAGE, getDestination().getCanonicalName());
if (getBundle() != null) intent.putExtras(getBundle());
startActivity(intent);
}
}
Tips:
AccountHelper为数据存储类,存储Token及登录信息相关,可根据自身项目需求修改AccountHelper调用处代码。
AuthMode认证类型,我的项目存在多种登录方式,这里是定义的一个枚举类,这个根据自身项目业务调整。
RouteHelper
在RouteHelper中向外暴漏相关API。
public class RouteHelper {
// 设置一个Auth页面,当需要认证时跳转至该页面。
private Class<?> authPage;
private volatile static RouteHelper helper = null;
private RouteHelper() {}
public static RouteHelper getDefault() {
if (helper == null) {
synchronized (RouteHelper.class) {
if (helper == null) {
helper = new RouteHelper();
}
}
}
return helper;
}
public void init(@NonNull IRouteAuthPage iRoutePage) {
this.authPage = iRoutePage.createAuth();
}
Class<?> getAuthPage() {
return authPage;
}
/**
* 跳转Activity
* @param tClass 目标Activity
*/
public RouteMeta with(@NonNull Context context, @NonNull Class<?> tClass) {
if (authPage == null) throw new NullPointerException("RouteHelper未初始化~");
return new RouteMeta(context, tClass);
}
/**
* 跳转Activity
* @param tClass 目标Activity
* @param extras 跳转Activity时携带的Bundle对象。
*/
public RouteMeta with(@NonNull Context context, @NonNull Class<?> tClass, @Nullable Bundle extras) {
if (authPage == null) throw new NullPointerException("RouteHelper未初始化~");
return new RouteMeta(context, tClass, extras);
}
/**
* 跳转到认证页面
*/
public void withAuth(@NonNull Context context) {
withAuth(context, AuthMode.PHONE_LOGIN);
}
/**
* 跳转到认证页面,{@link AuthMode} 认证类型
*/
public void withAuth(@NonNull Context context, @NonNull AuthMode mode) {
if (authPage == null) throw new NullPointerException("RouteHelper未初始化~");
Intent intent = new Intent(context, authPage);
intent.putExtra(RouteMeta.EXTRA_AUTH_MODE, mode.name());
context.startActivity(intent);
}
/**
* 登录逻辑完成后调用
*/
public void authComplete(@Nullable Activity activity) {
if (activity == null) return;
Bundle bundle = activity.getIntent().getExtras();
String targetPage = bundle != null ? bundle.getString(RouteMeta.AFTER_AUTH_JUMP_TO_TARGET_PAGE) : "";
if (targetPage != null && !targetPage.isEmpty()) {
try {
bundle.remove(RouteMeta.AFTER_AUTH_JUMP_TO_TARGET_PAGE);
Class<?> tClass = Class.forName(targetPage);
activity.startActivity(new Intent(activity, tClass).putExtras(bundle));
activity.overridePendingTransition(0, 0);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
activity.finish();
}
}
自定义接口
自定义一个接口,返回一个Class,初始化RouteHelper时设置登录Activity。
public interface IRouteAuthPage {
Class<?> createAuth();
}
RouteHelper使用
- 初始化并指定登录Activity
public class AppContext extends Application {
@Override
public void onCreate() {
super.onCreate();
// 初始化页面路由并指定认证Activity
RouteHelper.getDefault().init(() -> AuthActivity.class);
}
}
- 在登录完成后调用如下代码,确保自动跳转到目标页
RouteHelper.getDefault().authComplete(this);
- 普通跳转
RouteHelper.getDefault().with(this, GoodsDetailActivity.class)
.withString("test", "商品详情") // 向目标页传递参数
.navigation();
- 打开目标页需要登录
RouteHelper.getDefault().with(this, OrderDetailActivity.class)
.setNeedAuth(true) // 该参数标记是否需要登录
.withString("test", "订单详情") // 向目标页传递参数
.navigation();