延续上一篇 MonkeyLei:Android - 模块化, 组件化, 插件化, 热修复 - 组件化工程构建 + 页面路由多种方式实践 , 我们进行搞下组件之间的通信. 比如登录成功后怎么通知其他页面刷新:
方式可能有很多, 列举几种:
sharedpreferences, 这种适合一些长期本地存储的值 (比如用户登录账号信息)
basemodule 里面新建一个公共数据类, 存储全局数据, 临时通信时使用, 提供 set/get 方法, 就是所谓的下沉到底层模块
基于上一篇的 IAppComponent 接口, 扩展数据存储接口, 在每个模块的 XxxxApplication 类提供数据给其他模块, 但是只能达到该 Application 类, 还是需要通知到其他指定页面
greenrobot/EventBus 通知刷新 (比较简单好用, 有时候需要注意是不是采用黏性广播)
alibaba/ARouter 的接口调用方式 (首次使用了下, 猜想了下感觉就是维护了一个指定 path 的接口对象, 而且还是个单例的接口对象, 之后始终只有一个该实例被使用; 而且该接口还限制了必须是实现了 IProvider, 只有该 IProvider 类型才能编译通过; 回头瞅瞅源码就造了)
可能还有其他方式吧~~~
直接看代码, 注释都写了:
a0. 注意别忘记引入 Eventbus 库
image
image
image
a1. base 模块定义一些 Eventbus 的事件类, 以及 Arouter 的 Provider 接口
image
image
a2. 然后 login 模块里面实现 Arouter 数据接口
login/src/.../LoginProvider.java - 添加 @Route 注解
- package com.skl.login;
- import Android.content.Context;
- import Android.util.Log;
- import com.alibaba.Android.arouter.facade.annotation.Route;
- import com.skl.basemodule.common_interface.IDataCallBack;
- @Route(path = "/login/provider")
- public class LoginProvider implements IDataCallBack {
- private Object content;
- @Override
- public void setSomething(Object obj) {
- this.content = obj;
- }
- @Override
- public Object getSomething() {
- return content;
- }
- @Override
- public void init(Context context) {
- // TODO 可以在 init 方法中进行一些接口首次被调用时的初始化操作
- Log.e("LoginProvider", "init!");
- }
- }
a3. 完事了, 我们就可以点击登录, 然后成功后采用各种方式进行通知 (有些方式做个说明就行, 具体自己可以简单试试);
- login/src/.../LoginActivity.java
- /**
- * 登录 + 可以保存数据到本地 (采用 sharedpreferences 的方式存储)
- * TODO 注意: 这里为了模拟组件间的接口调用, 采用其他方式
- *
- * @param view
- */
- public void logining(View view) {
- // - 通知个人中心刷方式 1\. 登录成功后, 本地保存登录信息, 每次切换到个人中心页面都进行个人信息刷新; 解决: 采用 Sharedpreferences 存储
- // -- 通知个人中心刷方式 1.1. 下沉到底层模块 basemodule 里, 所有业务组件可依赖, 这样就解决了组件之间数据共享的问题; 解决: 类似 CompomentsService 那样定义公共类, 提供公共开放静态接口 (set/get)...
- // - 通知个人中心刷方式 2\. 主动调用刷新; 解决: 其实也是通过扩展 IAppComponent 接口, 但是只能到达组件的 XxxxApplication 类, 还是需要通知到指定页面
- // -TODO 通知个人中心刷新方式 3\. Eventbus 通知刷新
- EventBus.getDefault().post(new MessageEvent("login_success", "name:hl,age:22"));
- // -TODO 通知个人中心刷方式 4\. ARouter 路由通信 - 这里路由设置相关信息, 个人中心获取进行刷新
- IDataCallBack provider = (IDataCallBack) ARouter.getInstance().build("/login/provider").navigation();
- if (null != provider) {
- provider.setSomething("name:hl,age:22");
- }
- finish();
- // TODO - 这里用登录成功来演示了一下组件的通信, 但是要注意的是:
- // 我们登录成功的信息是持久化的, 需要 shared 保存的哈, 不然每次重新进入就没了!
- }
a4. 然后主页面, 以及个人信息展示页面均可以注册 Eventbus 事件, 或者通过 Arouter 方式的 IDataCallBack 接口对象来获取数据
App/src/.../MainActivity.java - 部分代码
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- EventBus.getDefault().register(this);
- }
- /**
- * Eventbus 接收登录等通知事件
- * @param event
- */
- @Subscribe(threadMode = ThreadMode.MAIN)
- public void onMessageEvent(MessageEvent event) {
- if (event.getKey().equals("login_success")){
- Log.e("MainActivity", "user_info=" + event.getContent());
- }
- }
- @Override
- protected void onStart() {
- super.onStart();
- Log.e("MainActivity", "onStart");
- }
- @Override
- protected void onResume() {
- super.onResume();
- Log.e("MainActivity", "onResume");
- IDataCallBack provider = (IDataCallBack) ARouter.getInstance().build("/login/provider").navigation();
- if (null != provider){
- Log.e("MainActivity", "user_info=" + provider.getSomething());
- // TODO 此时可以获取数据设置到界面, 这里我们演示 ARoute 的这个接口调用来实现组件通信哈!!
- // 如果采用 Eventbus 貌似就不用每次这里做判断了
- }
- }
- @Override
- protected void onDestroy() {
- super.onDestroy();
- EventBus.getDefault().unregister(this);
- }
- personal/src/...PersonalActivity.java
- package com.skl.personal;
- import Android.support.v7.App.AppCompatActivity;
- import Android.os.Bundle;
- import Android.util.Log;
- import Android.view.View;
- import Android.widget.TextView;
- import com.alibaba.Android.arouter.facade.annotation.Route;
- import com.alibaba.Android.arouter.launcher.ARouter;
- import com.skl.basemodule.common_interface.IDataCallBack;
- @Route(path = "/ppx/personal")
- public class PersonalActivity extends AppCompatActivity {
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_personal);
- }
- /**
- * 获取登录页面个人信息并展示
- * @param view
- */
- public void getLoginInfo(View view) {
- IDataCallBack provider = (IDataCallBack) ARouter.getInstance().build("/login/provider").navigation();
- if (null != provider){
- ((TextView)view).setText("" + provider.getSomething());
- }
- }
- }
[图片上传中...(image-67da36-1570520271713-0)]
我看了下, 大部分好像都是 Eventbus 或者路由.. 像登录注册可能更多的是 share 存储. 下沉到基础模块的情况应该也是看哪些数据, 根据项目实际情况, 我们需要酌情选择清晰易维护的实现方式. 适合的才是最好的?
工程地址: https://gitee.com/heyclock/doc/tree/master / 组件化
如果采用 Arouter, 有必须深入下一些用法:
- https://blog.csdn.net/panyongjie2577/article/details/89344394
- https://blog.csdn.net/superxlcr/article/details/77966142
- https://blog.csdn.net/hzw2017/article/details/84204833
厉害点的, 自己琢磨分析封装路由, 参考 Arouter 或者 WMRouter
https://www.jianshu.com/p/82b994fe532c
组件化的工作, 首先工程的构建 (App,basemodule,application/library's module, and other library), 其次路由相关配置, 然后组件通信. 这是主要的三个工作, 我们采用三方库, 最终目的也是为了让组件的通信不产生耦合, 直观的感受就是随时可以剥离到一个组件的依赖, 而不会影响程序的编译运行.... 组件化比较适合多人协同开发, 像我们大部分都是一个人, 两个人, 或许就不用搞什么组件化了, 顶多就是 App 模块下分多子模块进行开发, 以后如果想剥离为组件, 多子模块还是有好处的!
早期的我们有时候都不搞子模块, 页面统一放到 App/src/..../actiivty, 或者 App/src/..../fragment, 适配器放到 App/src/..../adapter... 总之就是一堆就是了... 随着技术项目经验的沉淀, 还是需要有一定的改变和提升才行!!! 有一天我们还是会搞大项目的, 只要坚持学习, 努力提升自己, 我目前比菜, 也是从去年彻底投入 Android, 也希望可以自律, 努力坚持, 一起加油吧! 我目前一般都是争取看官方的, 然后结合网友的, 推荐优先官方走起. 到一定阶段, 可以抽时间看源码!
就这样吧, 一起努力....
来源: http://www.jianshu.com/p/755c7694893c