问题描述
最近在项目中遇到一个问题,在项目中,Fragment中的一个图标,需要在点击缩放动画完成后,跳转到另一个界面,但是经常会出现getActivity()或getContext()方法返回值为空的问题。在网上查找了很多解决方案,大概有以下几种:
1. 根据fragment的生命周期,将方法的调用写到onStart()方法内部。我将方法的调用写到了onResume()方法中,都同样会出现空指针。
2. 不使用getActivity()和getContext()方法,重写onAttach()方法,自定义一个Context,获取onAttach()时,传入的context。试了这个方法,一样会出现异常。
3. 使用applicationContext(),试了这个方法,同样会出现异常,异常的信息为Fragment not attached to Activity。
4. 还有的说是因为Activity被回收,需要对onSaveBundle()方法做相关处理,但是我是在当前Acitivity刚打开的时候就会出现这个问题,并没有进行切换。
问题求解
使用了第二种方式,自定义了一个Context,接收onAttach()方法中传入的context,然后在onDetach()方法中释放引用 context = null; 同样出现了空指针异常。
@Override
public void onResume() {
super.onResume();
// 设置点击事件
imgType.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(context != null) { // 判断是否已经添加到了Activity中
LogZS.d(TAG+"->onClick","Context值为"+context.toString());
showRoom();
}
}
});
}
private void showRoom(){
// 点击反馈的动画
ValueAnimator valueAnimator = ValueAnimator.ofFloat(1.0f,1.1f,1.0f);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float value = (float) animation.getAnimatedValue();
imgType.setScaleX(value);
imgType.setScaleY(value);
}
});
valueAnimator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
LogZS.d(TAG+"->onAnimationStart","动画开始");
}
@Override
public void onAnimationEnd(Animator animation) {
LogZS.d(TAG+"->onAnimationEnd","Context为:"+context.toString());
Intent intent = new Intent(context, RoomDetailActivity.class); // 报错位置
intent.putExtra("roomNum", grpNo);
startActivity(intent);
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
valueAnimator.setDuration(350);
valueAnimator.start();
}
通过日志打印看到,在方法调用前,context是不为空的,动画可以执行,日志有输出,但是在动画执行完之后,context为空。
所以我猜测,应该是动画执行的时候触发了Fragment的onDetach()方法释放了context,于是加了打印的日志。
@Override
public void onDetach() {
super.onDetach();
context = null;
LogZS.d(TAG+"->onDetach","Context被清空");
}
日志打印的结果,发现”Context被清空”的信息调用了多次,也就是说onDetach()方法被调用了多次,我是ViewPager中显示的fragment,
所以猜测问题原因可能是每次viewPager刷新数据源adapter.notifyDataSetChange()时,导致的fragment调用了onDetach()方法,
于是在数据源刷新出增加日志输出。
LogZS.e(TAG + "->loadRoom", "LoadRoom被调用");
adapter.notifyDataSetChanged();
结果”loadRoom被调用”打印的次数和”Context被清空的次数相同”。
所以问题的原因就是数据源刷新的时候,viewPager中的fragment从activity上分离,所以才会出现异常。
解决方案
在知道了问题原因的基础下,使用以上任何一中解决方案都没有问题,前提是,在代码执行之前,要调用isAdd()方法,进行判断,确保fragment
与Activity的状态是关联的状态。