已做非空判断仍崩溃:WeakReference持有的Fragment空指针问题
为什么WeakReference判断非空后仍出现空指针?
这问题我之前排查过好几次,核心坑点就是WeakReference的回收特性加上代码里的竞态条件,咱们一步步理清楚:
问题根源:WeakReference的本质与竞态条件
你用WeakReference包裹DateTimePickerDialogFragment的初衷应该是避免内存泄漏,但WeakReference的特性是:只要对象没有被任何强引用持有,GC随时会把它回收掉。
看你的代码流程:
- 创建WeakReference并赋值给
mCurrentDialogFragment,此时只有WeakReference指向新创建的DialogFragment - 你调用
mCurrentDialogFragment.get()设置监听器,这时候会产生一个临时强引用,但执行完监听器设置后,这个临时引用就消失了 - 你做了
mCurrentDialogFragment != null && mCurrentDialogFragment.get() != null的非空判断,这时候get()确实能拿到对象 - 但从判断结束到执行
mCurrentDialogFragment.get().setArguments(bundle)的这段极短时间里,GC可能已经触发,把没有强引用的DialogFragment回收了!再次调用get()自然就返回null,导致空指针崩溃。
简单说:判断和实际调用之间存在时间窗口,GC可以在这个窗口里把对象收走,这就是典型的竞态条件问题。
解决方案:用强引用临时持有对象
解决思路很简单:在判断非空后,把WeakReference里的对象赋值给一个强引用变量,后续所有操作都用这个强引用,这样GC就不会在操作过程中回收它了。修改后的代码如下:
protected void showDateTimePickerDialog() { mCurrentDialogFragment = new WeakReference<AppCompatDialogFragment>(new DateTimePickerDialogFragment()); DateTimePickerDialogFragment dialog = (DateTimePickerDialogFragment) mCurrentDialogFragment.get(); if (dialog != null) { dialog.setOnDateTimeSelectedListener( new DateTimePickerDialogFragment.OnDateTimeSelectedListener() { @Override public void onCancelled() { } @Override public void onDateTimeSet(int year, int monthOfYear, int dayOfMonth, int hourOfDay, int minute) { ... } }); DateTime dt = new DateTime(mCalendarTimeLineAdapter.convertPositionToMs( mViewPager.getCurrentItem())); Pair<Boolean, SublimeOptions> optionsPair = TimeUtils.getDateTimePickerOptionsForDiary(mScheduleRange, new DateTime(dt), mCalendarTimeLineAdapter.getCalendarTodayPosition()); Bundle bundle = new Bundle(); bundle.putParcelable(DateTimePickerDialogFragment.BUNDLE_KEY_DATETIME_OPTIONS, optionsPair.second); dialog.setArguments(bundle); dialog.setStyle(android.support.v4.app.DialogFragment.STYLE_NO_TITLE, 0); dialog.show(getSupportFragmentManager(), TAG); } }
另外还有个额外建议:如果这个DialogFragment是当前页面需要主动展示的,其实可以考虑直接用强引用持有它,只要在页面的onDestroy生命周期里把引用置为null,就不会造成内存泄漏,反而能避免WeakReference带来的这类问题。
内容的提问来源于stack exchange,提问作者anthony
相关产品推荐
相关产品推荐

