Android 学习之那些年我们遇到的BUG9:Lifecycle.Event.ON_RESUME 提前触发了

BUG:自定义 View 中实现了 LifecycleObserver 接口,编写了一个 onResume(…) 函数,并给它加上了注解“@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)”,但是所在的 Fragment 还没有处于 onResume() 状态,View 的 onResume(…) 方法就触发了

产生的背景:

  1. 实现了 LifecycleObserver 接口的自定义 View
  2. 自定义 View 中有一个加了 @OnLifecycleEvent(Lifecycle.Event.ON_RESUME) 注解的方法 onResume(…)
  3. 在 MainActivity 中有一个 ViewPager,里面承载了三个 Fragment
  4. 在第三个 Fragment 的布局中使用该自定义 View
  5. 启动应用后发生崩溃,查看错误日志,说 onResume(…) 中使用了未初始化的 ImageView
public class UserHeader extends ConstraintLayout implements LifecycleObserver {
		// ...
    private RoundedImageView roundedImageView;
    // ...
  	public UserHeader(Context context) {
        super(context);
        init(context, null);
    }
  	// ...
  	private void init(Context context, AttributeSet attrs) {
        // ...
        // 加载自定义布局
        LayoutInflater.from(context).inflate(R.layout.layout_xxx, this);
      	// ...
        if (getContext() instanceof XXXActivity) {
            ((XXXActivity) getContext()).getLifecycle().addObserver(this);
        }
        //实例化组件
        roundedImageView = (RoundedImageView) findViewById(R.id.xxx);
        // ...
    }
  
  	@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    public void onResume() {
        // ...
        if (!TextUtils.isEmpty(userString)) {
            // ...
        } else {
            // 发生崩溃的位置
            roundedImageView.setImageResource(mNotLoggedInHeader);
            // ...
        }
    }
}

排查过程:

  1. LifeCycle 的 ON_RESUME 触发了,说明其观察的 Context 的 onResume 触发了,控件是写在 Fragment 中,在没有仔细阅读自定义 View 的前提下,天真的认为是因为 Fragment 走了 onResume,导致触发,所以想起 Fragment 懒加载问题,打算去排查(其实 Fragment 要是真的触发了 onResume,那么 roundedImageView 也不会没有初始化了)
  • 检查 Fragment 的生命周期打印,发现并没有执行到 onResume
  • 检查 VP 的 adapter,确实使用了 BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT 那么说明只有当 VP 切换到第三个 Fragment 时,对应的它的 onResume 才会触发
  1. 既然不是 Fragment 的生命周期导致的 LifeCycle 的 ON_RESUME 触发,那说明调用 addObserver(…) 的对象另有其人,经过查看代码与打印日志,发现是承载 Fragments 的活动 MainActivity,这也不难理解崩溃造成的原因了:
  • 一启动应用,进入 MainActivity 后,它的 onResume 函数就触发了,进而出发了 View 的 onResume(…) 方法。
  • 那为什么在执行 View 的 onResume(…) 方法时 roundedImageView 没有初始化呢,原因在于 addObserver(this) 操作早于 findViewById(…) ,一旦 view 被 addObserver(…) 后,之前产生的事件都会一一触发,直接走了 View 的 onResume(…) 方法,而此时 roundedImageView 的初始化操作还在后面没有执行,先调用了 setImageResource(…) 方法,产生崩溃。

解决方法:

偷了个懒,将 addObserver(…) 操作放在了 findViewById(…) 之后,虽然暂时解决了,但还是存在隐患,万一哪天另外一个同事修改代码的时候,在后面写了初始化方法呢!但是由于是基础库改动需要十分小心而且没有太多时间深入研究,只好写上注释,⚠️警告后人!!日后有时间,要好好考虑一下这个部分的实现了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值