Android模块化之登录业务处理
前面介绍过Android模块化的基本方法,能够保证每个模块单独运行。如果没看过,戳这里:Android模块化简单教程。但是这些只是最基本的,一个项目模块化的过程中会遇到许许多多的问题,最重要的就是一个登录问题,当我们单独运行某个模块的时候,我们的前提是必须进行登录操作,如何使得每个模块运行之前都运行登录模块呢?这里有两种方案,示例代码看这里。
方案一:BaseActivity拦截(本方案的代码看git历史记录)
- 在登录模块中将登录状态记录到全局数据中心中
DataCenter.getInstance().setLogin(true);
- 在BaseActivity中判断是否登录
if(!DataCenter.getInstance().isLogin()){
String curUrl = ConstantRouter.getCurRouter(this.getClass().getSimpleName());
ARouter.getInstance().build(ConstantRouter.LOGIN_ACTIVITY)
.withString("targetUrl",curUrl)
.navigation();
finish();
}
在BaseActivity中,首先判断是否登录了,如果登录了自然继续走下去,如果没有登录过,那么则要跳转到登录页面去登录,并结束当前页面,这里注意,跳转到登录页面时要把当前页面的地址(ARouter配置的地址)带过去,这样登录完毕后才能跳转回当前页面。
- 注册登录后的跳转地址
在第2步中,我们要将当前页面的url传入到LoginActivity中,但是,我们是在BaseActivity中处理这个跳转的,而每个url是在子activity中配置的,BaseActivity中是拿不到这个url的。为了解决这个问题,我们统一静态配置登录时跳转的路由表:
public class ConstantRouter {
public static Map<String,String>activityRouterMap = new HashMap<>();
//主页
public static final String APP_MAINACTIVITY = "/app/MainActivity";
//即时通讯首页
public static final String IM_MAINACTIVITY = "/im/InstantMessagingMainActivity";
//新房首页
public static final String NEW_HOUSE_MAINACTIVITY = "/new_house/NewHouseMainActivity";
//二手房首页
public static final String SECOND_HOUSE_MAINACTIVITY = "/second_house/SecondHouseMainActivity";
/**
* 登录
*/
public static final String LOGIN_ACTIVITY = "/common_business/LoginActivity";
static{
activityRouterMap.put(getActivityName(APP_MAINACTIVITY),APP_MAINACTIVITY);
activityRouterMap.put(getActivityName(IM_MAINACTIVITY),IM_MAINACTIVITY);
activityRouterMap.put(getActivityName(NEW_HOUSE_MAINACTIVITY),NEW_HOUSE_MAINACTIVITY);
activityRouterMap.put(getActivityName(SECOND_HOUSE_MAINACTIVITY),SECOND_HOUSE_MAINACTIVITY);
activityRouterMap.put(getActivityName(LOGIN_ACTIVITY),LOGIN_ACTIVITY);
}
private static String getActivityName(String routerUrl){
int pos = routerUrl.lastIndexOf("/");
return routerUrl.substring(pos+1);
}
public static String getCurRouter(String activityName){
return activityRouterMap.get(activityName);
}
}
配置ARouter的url时,我们遵从一个原则,该url结尾必然是该Activity的类名称,然后我们将该Activity的名称和他的ARouter的url建立一个静态映射,这样,在BaseActivity中,我们就能够通过运行时的类名获得它的url:
String curUrl = ConstantRouter.getCurRouter(this.getClass().getSimpleName());
这样就可以实现将当前页面的url传给LoginActivity了。
- 处理登录模块的跳转
@Route(path = "/common_business/LoginActivity")
public class LoginActivity extends CommonBaseActivity{
@Autowired
String targetUrl;
@BindView(R2.id.progressBar)
ProgressBar progressBar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
ARouter.getInstance().inject(this);
if(targetUrl == null){
//默认跳转到MainActivity
targetUrl = ConstantRouter.APP_MAINACTIVITY;
}
//此处用来模拟登录事件
progressBar.postDelayed(new Runnable() {
@Override
public void run() {
DataCenter.getInstance().setLogin(true);
ARouter.getInstance().build(targetUrl).navigation();
LoginActivity.this.finish();
}
},2000);
}
}
在LoginActivity中登录完成后,直接跳转到之前的页面即可。
方案二:登录模块跳转判断
本方案核心思想就是每个模块统一先走登录流程,登录完成后再根据当前运行的是哪个模块跳转到该模块的首页。
1.在每个module的单独运行时的AndroidManifest.xml中指定登录模块为启动activity。
<application
android:allowBackup="true"
android:icon="@mipmap/new_house_ic_launcher"
android:label="@string/new_house_app_name"
android:supportsRtl="true"
android:name="com.baronzhang.android.commonbusiness.base.BaseApplication"
tools:replace="label"
android:theme="@style/NewHouseAppTheme">
<activity android:name="com.baronzhang.android.commonbusiness.base.login.LoginActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="com.baronzhang.android.newhouse.NewHouseMainActivity"
android:label="@string/new_house_label_home_page">
</activity>
</application>
2.判断当前运行的是那个Module
由于LoginActivity是在CommonBusiness模块中的,只是一个子module而已,我们要在这个模块中获取当前运行的module是比较困难的,这里提供一种方法,我们可以在每个module的debug时的AndroidManifest.xml中指定一个label,然后子module中可以取到这个label,从而可以判断当前运行的是哪个模块。
<application
android:allowBackup="true"
android:icon="@mipmap/new_house_ic_launcher"
android:label="@string/new_house_app_name"
android:supportsRtl="true"
android:name="com.baronzhang.android.commonbusiness.base.BaseApplication"
tools:replace="label"
android:theme="@style/NewHouseAppTheme">
<activity android:name="com.baronzhang.android.commonbusiness.base.login.LoginActivity">
这里要确保每个module的label不一样,不然会出现跳转错误。
3.注册路由表
每个module都有自己的label,然后我们将该label和该模块首页的url建立一个映射,形成路由表,方便跳转。
public class ConstantRouter {
//各个模块首页和跳转地址的映射
public static Map<String,String>activityRouterMap = new HashMap<>();
//主页
public static final String APP_MAINACTIVITY = "/app/MainActivity";
//即时通讯首页
public static final String IM_MAINACTIVITY = "/im/InstantMessagingMainActivity";
//新房首页
public static final String NEW_HOUSE_MAINACTIVITY = "/new_house/NewHouseMainActivity";
//二手房首页
public static final String SECOND_HOUSE_MAINACTIVITY = "/second_house/SecondHouseMainActivity";
/**
* 登录
*/
public static final String LOGIN_ACTIVITY = "/common_business/LoginActivity";
static{
activityRouterMap.put(BaseApplication.getApplication().getString(R.string.label_app),APP_MAINACTIVITY);
activityRouterMap.put(BaseApplication.getApplication().getString(R.string.label_instant_messaging),IM_MAINACTIVITY);
activityRouterMap.put(BaseApplication.getApplication().getString(R.string.label_second_house),SECOND_HOUSE_MAINACTIVITY);
activityRouterMap.put(BaseApplication.getApplication().getString(R.string.label_new_house),NEW_HOUSE_MAINACTIVITY);
}
public static String getCurRouter(String label){
return activityRouterMap.get(label);
}
}
4.在LoginActivity中根据label进行跳转
/**
* 获取当前登录完毕要跳转到哪个模块首页
* @return
*/
private String getCurModuleUrl(){
String label = null;
try {
label = getResources().getString(
getPackageManager().getApplicationInfo(getPackageName(), 0).labelRes);
return ConstantRouter.getCurRouter(label);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
return null;
}
targetUrl = getCurModuleUrl();
if(targetUrl == null){
targetUrl = ConstantRouter.APP_MAINACTIVITY;
}
//此处用来模拟登录事件
progressBar.postDelayed(new Runnable() {
@Override
public void run() {
DataCenter.getInstance().setLogin(true);
ARouter.getInstance().build(targetUrl).navigation();
LoginActivity.this.finish();
}
},2000);
总结
两种方案,方案一有一个缺点,就是在未登录情况下,模块首页会先跳转到登录页然后结束自己,这样会导致一个一闪而过的情况,还是有点明显的,当然,这个只在开发时会出现,发布后肯定是以一整个App发布出去,不会出现单独运行Module情况,自然不会出现这种情况。所以,我采用的是第二种方案,只要确保每个module的label不重复即可。
最后可以继续看下我的另一篇文章:Android模块化之ButterKnife和Dagger2的使用