Android实战

Android模块化之登录业务处理

2017-06-28  本文已影响834人  低情商的大仙

前面介绍过Android模块化的基本方法,能够保证每个模块单独运行。如果没看过,戳这里:Android模块化简单教程。但是这些只是最基本的,一个项目模块化的过程中会遇到许许多多的问题,最重要的就是一个登录问题,当我们单独运行某个模块的时候,我们的前提是必须进行登录操作,如何使得每个模块运行之前都运行登录模块呢?这里有两种方案,示例代码看这里

方案一:BaseActivity拦截(本方案的代码看git历史记录)

  1. 在登录模块中将登录状态记录到全局数据中心中
    DataCenter.getInstance().setLogin(true);
  2. 在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配置的地址)带过去,这样登录完毕后才能跳转回当前页面。

  1. 注册登录后的跳转地址
    在第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了。

  1. 处理登录模块的跳转
@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的使用

上一篇下一篇

猜你喜欢

热点阅读