Java ViewLifeCycleOwner再次从主线程转到后台到主线程时返回null
我需要在适配器解析其视图后的几毫秒内开始观察,以便它们正确接收信号 此方法在onViewCreated()之后执行 其中Java ViewLifeCycleOwner再次从主线程转到后台到主线程时返回null,java,android,multithreading,android-lifecycle,weak-references,Java,Android,Multithreading,Android Lifecycle,Weak References,我需要在适配器解析其视图后的几毫秒内开始观察,以便它们正确接收信号 此方法在onViewCreated()之后执行 其中Post.delayed()是一个Executors.newSingleThreadScheduledExecutor().schedule()方法,而Post.onMain()是一个新处理程序(Looper.getMainLooper())用于可运行的过帐 奇怪的事情正在发生…: 第一次执行代码时,一切正常,但在配置更改后,会发生IllegalStateException:
Post.delayed()
是一个Executors.newSingleThreadScheduledExecutor().schedule()
方法,而Post.onMain()
是一个新处理程序(Looper.getMainLooper())代码>用于可运行的过帐
奇怪的事情正在发生…:
第一次执行代码时,一切正常,但在配置更改后,会发生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;
/**
*拥有此生命周期的提供程序。
*只保留LifecycleOwner上的WeakReference,所以如果有人泄漏Lifecycle,他们就不会泄漏
*整个片段/活动。但是,泄露生命周期对象也不是什么好主意,
*因为它在所有其他侦听器上保留强引用,所以您会将所有侦听器作为
*嗯。
*/
私人最终财产所有者;
WeakReference正在Post.delayed()
(调度执行器)中被GC'd,因此当需要在主线程中再次执行该方法时,该引用已被收集,但当在后台调度执行器中执行该方法的第二次执行时,即使根本不使用引用,线程也会保留方法getViewLifeCycleOwner()
中涉及的所有引用的副本,并在返回到mainThread
时退出垃圾收集
我的预感正确吗?所以这不是正在发生的事情…,是的,只是部分。
新的线程不是在“收集”WeakReference,而是在“延长”它的寿命。
怎么用?getViewLifeCycle()方法在延迟方法指定的150毫秒之前执行时,有助于绕过IllegalStateException(),并带来LifecycleRegistry的副本,该副本在方法执行时已被销毁。。。谢天谢地,LiveData组件可以完成返回代码>当生命周期已经被破坏并且一切都结束时
真正的问题与空状态、初始状态和以前保存的状态有关
在配置更改发生之前,堆栈中已经存在的片段再次被相同的片段替换,这一切都是因为上层组件忽略了相等性,这种破坏比延迟方法指定的150毫秒要快
这就是在Executors.newSingleThreadScheduledExecutor().schedule()
可以访问该视图之前销毁该视图的原因
起初我以为问题出在泛型枚举的相等性检查上(因为它忽略了新对象,但这是相反的问题,所以…),但允许重复操作通过的事情。。。实际上,所述组件上的“启动状态”在配置更改时触发(更准确地说:onViewCreated),因此相等性检查无法推断堆栈上已存在真实的最后一个操作/片段
解决方案是检查新旧之间的Fragment class()相等性,以防止重复事务
另一种选择是对配置更改进行特殊处理,并使组件了解此状态,但在任何代码IMO中,重复的事务/操作通常都是一个不好的迹象,因此最好的做法是防止重复操作
/**
* 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;