【问题标题】:ViewLifeCycleOwner returning null when going from Main, to background to MainThread againViewLifeCycleOwner 在从 Main 到后台再到 MainThread 时返回 null
【发布时间】:2021-05-01 18:24:05
【问题描述】:

我需要在适配器解析其视图后几毫秒开始观察,以便它们正确接收信号。

此方法在 onViewCreated() 之后执行;

                pageControllerAdapter.submitList(stringVisitors, () -> {
                    if (!currentPage.hasActiveObservers()) {
                        Post.delayed(
                                () -> {
                                    Post.onMain(
                                            () -> {
                                                currentPage.observe(getViewLifecycleOwner(),
                                                        page -> {
                                                            selector.setSelected(page);
                                                            binding.searchPages.setCurrentItem(page, true);
                                                        }
                                                );
                                            }
                                    );

                                },
                                150L,
                                TimeUnit.MILLISECONDS
                        );
                    }
                });

Post.delayed()Executors.newSingleThreadScheduledExecutor().schedule() 方法,Post.onMain()new Handler(Looper.getMainLooper()); 用于 Runnable 发布

有些奇怪的事情正在发生……:

第一次执行代码时一切正常,但在配置更改后出现IllegalStateException

@MainThread
    @NonNull
    public LifecycleOwner getViewLifecycleOwner() {
        if (mViewLifecycleOwner == null) {
            throw new IllegalStateException("Can't access the Fragment View's LifecycleOwner when "
                    + "getView() is null i.e., before onCreateView() or after onDestroyView()");
        }
        return mViewLifecycleOwner;
    }

但是...如果我打电话给getViewLifeCycleOwner();在进入.getMainLooper() 线程之前,在Post.delayed()Post.onMain() 之间像这样:

                        Post.delayed(
                                () -> {
                                    getViewLifecycleOwner();
                                    Post.onMain(
                                            () -> {
                                                currentPage.observe(getViewLifecycleOwner(),
                                                        page -> {
                                                            selector.setSelected(page);
                                                            binding.searchPages.setCurrentItem(page, true);
                                                        }
                                                );
                                            }
                                    );

                                },
                                150L,
                                TimeUnit.MILLISECONDS
                        );

代码有效....

我怀疑发生了什么,这是……:

/**
     * The provider that owns this Lifecycle.
     * Only WeakReference on LifecycleOwner is kept, so if somebody leaks Lifecycle, they won't leak
     * the whole Fragment / Activity. However, to leak Lifecycle object isn't great idea neither,
     * because it keeps strong references on all other listeners, so you'll leak all of them as
     * well.
     */
    private final WeakReference<LifecycleOwner> mLifecycleOwner;

WeakReference 正在 Post.delayed()(预定的执行程序)内进行 GC,因此当需要再次在 mainThread 中执行该方法时,该引用已被收集,但是当第二次执行方法在后台调度执行器中执行,即使引用根本没有被使用,方法getViewLifeCycleOwner()所涉及的所有引用的副本都被线程保留并在返回mainThread时逃脱垃圾回收。

我的预感正确吗?

【问题讨论】:

    标签: java android multithreading android-lifecycle weak-references


    【解决方案1】:

    所以这不是正在发生的事情......,是的,但部分。 新线程不是在“收集”WeakReference,而是在“延长”它的生命周期。 如何? getViewLifeCycle() 方法在延迟方法规定的 150 毫秒之前执行时,有助于绕过 IllegalStateException() 并带来 LifecycleRegistry 的副本,该副本在方法执行时已经被销毁......感谢上帝,LiveData 组件是当生命周期已经被破坏并且一切都结束时,请执行return;

    真正的问题与空状态、初始状态和先前保存的状态有关......

    在配置更改发生之前已经存在于堆栈中的 Fragment 再次被相同的 Fragment 替换,一切都是因为上层组件忽略了相等性,并且这种销毁速度比由延迟方法。

    这是在Executors.newSingleThreadScheduledExecutor().schedule() 可以访问视图之前破坏视图的原因。

    起初我认为问题在于通用枚举的相等检查(因为它忽略了新对象,但这是相反的问题所以..),但允许重复操作通过的事情......实际上,所述组件上的“初始状态”正在触发配置更改(更准确地说:onViewCreated),因此相等性检查无法推断 TRUE 最后一个动作/片段已经存在于堆栈中......

    解决方案是检查新旧之间的 Fragment class() 是否相等,以防止重复事务。

    另一种选择是为配置更改制定一个特殊情况,并让组件知道这种状态,但重复的事务/操作通常在任何代码 IMO 中都是一个不好的迹象,所以最好的做法是完全防止重复操作。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-01-15
      • 1970-01-01
      • 1970-01-01
      • 2011-06-15
      • 2015-07-18
      • 1970-01-01
      • 1970-01-01
      • 2021-03-27
      相关资源
      最近更新 更多