MVPArms框架学习遇到的一个问题——普通Activity配合Fragment出现空指针

时间:2021-03-07 21:13:11

MVPArms

一个整合了大量主流开源项目高度可配置化的 Android MVP 快速集成框架

https://github.com/JessYanCoding/MVPArms
为了简化开发,使用了MVPArms作为开发框架,同时也是学习封装的一个经典样板。

我也是在努力吸收其精华中,在使用中遇到一个空指针的问题,然后debug调试下,顺藤摸瓜找到了线索。
MVPArms框架学习遇到的一个问题——普通Activity配合Fragment出现空指针
问题是这样的,一个Activity +ViewPager 去加载Fragment,Fragment使用框架提供的BaseFragment去实现MVP,请求网络数据 并绑定Fragment的生命周期。看似正常的操作下却隐藏着一个致命的bug ,我断开网络,关闭界面,本应解绑销毁的Observer却没解绑,从而执行了doFinally,而此时mRootView已经销毁,因此引发了空指针问题。

看到崩溃 很是郁闷,纳闷为何没有执行销毁呢?跟进RxLifecycleUtils.bindToLifecycle(mRootView)也看到返回了结果,也就是说此操作是成功的。我们来看一下这里执行了什么操作

 public static <T> LifecycleTransformer<T> bindToLifecycle(@NonNull IView view) {
        Preconditions.checkNotNull(view, "view == null");
        if (view instanceof Lifecycleable) {
            return bindToLifecycle((Lifecycleable) view);
        } else {
            throw new IllegalArgumentException("view isn't Lifecycleable");
        }
    }

继续跟进

public static <T> LifecycleTransformer<T> bindToLifecycle(@NonNull Lifecycleable lifecycleable) {
        Preconditions.checkNotNull(lifecycleable, "lifecycleable == null");
        if (lifecycleable instanceof ActivityLifecycleable) {
            return RxLifecycleAndroid.bindActivity(((ActivityLifecycleable) lifecycleable).provideLifecycleSubject());
        } else if (lifecycleable instanceof FragmentLifecycleable) {
            return RxLifecycleAndroid.bindFragment(((FragmentLifecycleable) lifecycleable).provideLifecycleSubject());
        } else {
            throw new IllegalArgumentException("Lifecycleable not match");
        }
    }

可以看到 实现 FragmentLifecycleable接口的Activity/Fragment都执行了provideLifecycleSubject(),这是一个接口提供的方法,为Activity/Fragment实现RxLifecycle进行的规范。
查阅BaseFragment/BaseActivity
MVPArms框架学习遇到的一个问题——普通Activity配合Fragment出现空指针

MVPArms框架学习遇到的一个问题——普通Activity配合Fragment出现空指针
发现其提供了的是一个Subject,啥?你不知道啥是Subject?给你的地址:
https://mcxiaoke.gitbooks.io/rxdocs/content/Subject.html

其实简单来讲就是 它既是观察者 又是 被观察者,你可以用它来实现简单的EventBus,详细可搜索RxBus。

好,继续往下,知道了生命周期的是怎么发送的了,就得往下找是 在哪 发送的。
点击方法,看看都是那些地方使用了咱们的Subject

MVPArms框架学习遇到的一个问题——普通Activity配合Fragment出现空指针

最后那三个是 绑定时候用的,刚才咱们见过 RxLifecycleUtils了,他就是个Utils,给我们开发绑定用的,看上面两个的定义 也能知道个是做什么的,这就很符合命名规范(笑)。
- ActivityLifecycleForRxLifecycle

接收到Activity生命周期时 发送事件 通知 做了RxLifecycle相关绑定的观察者


  • FragmentLifecycleForRxLifecycle

接收到Fragment生命周期时 发送事件 通知 做了RxLifecycle相关绑定的观察者
点进去一看,果不其然
MVPArms框架学习遇到的一个问题——普通Activity配合Fragment出现空指针

里面分发了各个生命周期事件(前提是Fragment实现了FragmentLifecycleable接口,不然就没有Subject),来看obtainSubject()方法

 private Subject<FragmentEvent> obtainSubject(Fragment fragment) {
        return ((FragmentLifecycleable) fragment).provideLifecycleSubject();
    }

就是拿到我们刚才说的Subject。自己发给自己- _ -。 好,在哪发 和 在哪接收 的事件 都找到了,那为啥我没收到事件呢?莫急,继续看一下FragmentLifecycleForRxLifecycle在哪里使用到了。
MVPArms框架学习遇到的一个问题——普通Activity配合Fragment出现空指针

除了第一个ActivityLifecycleForRxLifecycle 为自己创建的类,其他均为Dagger2自己生成的,所以直接来看ActivityLifecycleForRxLifecycle,Duang~~
MVPArms框架学习遇到的一个问题——普通Activity配合Fragment出现空指针

聪明的你一眼就看出问题来了,是的,只有满足两个条件方能完成对Fragment生命周期回调的注册

 @Override
    public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
        if (activity instanceof ActivityLifecycleable) {
            obtainSubject(activity).onNext(ActivityEvent.CREATE);
            if (activity instanceof FragmentActivity) {
                ((FragmentActivity) activity).getSupportFragmentManager().registerFragmentLifecycleCallbacks(mFragmentLifecycle.get(), true);
            }
        }
    }

而我外部的Activity只是 AppCompatActivity,并没有实现ActivityLifecycleable,因为 这个Activity不做数据请求,只负责界面管理,资源可控。所以原因就是 Fragment的生命周期没有监听到。那么就好办了 实现ActivityLifecycleable 呗。不过 在仔细瞅瞅,发现BaseActivity 的注释

/**
* ================================================
* 因为 Java 只能单继承,所以如果要用到需要继承特定 {@link Activity} 的三方库,那你就需要自己自定义 {@link Activity}
* 继承于这个特定的 {@link Activity},然后再按照 {@link BaseActivity} 的格式,将代码复制过去,记住一定要实现{@link IActivity}
* ================================================
*/
以及 useFragment 的注释

 /** * 这个Activity是否会使用Fragment,框架会根据这个属性判断是否注册{@link android.support.v4.app.FragmentManager.FragmentLifecycleCallbacks} * 如果返回false,那意味着这个Activity不需要绑定Fragment,那你再在这个Activity中绑定继承于 {@link com.jess.arms.base.BaseFragment} 的Fragment将不起任何作用 * * @return */
    @Override
    public boolean useFragment() {
        return true;
    }

发现 在ActivityLifecycle(Application.ActivityLifecycleCallbacks 默认实现类)的
onActivityCreated()方法中registerFragmentCallbacks(Activity activity)通过判断是否实现了IActivity以及userFragment==true 来进行注册Fragment 生命周期的监听,不过这里指的是Fragment正常生命周期,而非是RxLifecycle

  private void registerFragmentCallbacks(Activity activity) {

        boolean useFragment = activity instanceof IActivity ? ((IActivity) activity).useFragment() : true;
        if (activity instanceof FragmentActivity && useFragment) {

            ((FragmentActivity) activity).getSupportFragmentManager().registerFragmentLifecycleCallbacks(mFragmentLifecycle.get(), true);

            if (mExtras.containsKey(ConfigModule.class.getName())) {
                List<ConfigModule> modules = (List<ConfigModule>) mExtras.get(ConfigModule.class.getName());
                for (ConfigModule module : modules) {
                    module.injectFragmentLifecycle(mApplication, mFragmentLifecycles.get());
                }
                mExtras.remove(ConfigModule.class.getName());
            }

            //注册框架外部, 开发者扩展的 Fragment 生命周期逻辑
            for (FragmentManager.FragmentLifecycleCallbacks fragmentLifecycle : mFragmentLifecycles.get()) {
                ((FragmentActivity) activity).getSupportFragmentManager().registerFragmentLifecycleCallbacks(fragmentLifecycle, true);
            }
        }
    }

所以说到底,实现ActivityLifecycleable 即可。

其实 这个问题 是我没有 认真 阅读源码 导致,不过也借此了解了框架的是如何实现生命周期的监听。

MVPArms 框架 很优秀,实际开发中择需使用,单这封装思想得让我学上好一段时间。 ヾ(◍°∇°◍)ノ゙ 加油 ——记一次崩溃调查。