我在第一个 Activity 的 onCreate() 中实例化我的 Fragment。在本例中可以看到以下应用流程:
- 主 Activity :onCreate()
- Fragment1:onAttach():我在其中获取监听器以从 Activity 获取数据
- Fragment1:onCreateView()
- Fragment2:onAttach()
- Fragment2:onCreateView()
- Fragment3:onAttach()
- Fragment3:onCreateView()
- ...
除非我执行以下步骤,否则我的应用程序运行良好: 1 - 打开应用程序 2 - 按主页按钮 3 - 使用内置优化器应用程序强制终止应用程序 4 - 再次打开应用程序
在本例中,应用程序是:
- fragment 1:onAttach()
- 主 Activity :onCreate()
- Fragment1:onCreateView()
- ...
因此,我在 onAttach() 方法中获得的监听器无效,并且在我使用该接口(interface)时导致 NullPointerException !我不明白如何解决它。我尝试在 onCreatedActivity() 中获取回调,但这导致我遇到其他问题。
如何修复它?
公共(public)类 ForecastFragment 扩展 Fragment 实现 OnNewDataSolcastListener、Animation.AnimationListener、OnFailGetDataSolcast {
private ScaleAnimation mStartingAnimation;
private ViewGroup mBubble;
private Solcast mSolcast;
private TextView mTxtConso;
private TextView mTxtConso2;
private TextView mTxtPresentationConso;
private ImageView mImgErrorSolcast;
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
Log.e(getClass().getSimpleName(), "onAttach()");
if(getActivity() instanceof Solcast.GetSolcastListener)
mSolcast = ((Solcast.GetSolcastListener) getActivity()).getSolcast();
else
throw new RuntimeException(getClass().getSimpleName() + " have to implement " + Solcast.GetSolcastListener.class.getSimpleName());
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
Log.e(getClass().getSimpleName(), "onCreateView()");
final View rootView = inflater.inflate(R.layout.content_main, container, false);
//init la GUI pour les fonctions qui auront besoin de ces View
mTxtConso = rootView.findViewById(R.id.txtValeurProduction);
mTxtConso2 = rootView.findViewById(R.id.txtValeurProduction2);
mTxtPresentationConso = rootView.findViewById(R.id.txtPresentationProduction);
mBubble = rootView.findViewById(R.id.bubbleMain);
mImgErrorSolcast = rootView.findViewById(R.id.imgErrorSolcast);
mImgErrorSolcast.setVisibility(View.GONE);
//some stuff...
//FAIL HERE : mSolcast null
mSolcast.setSearchDates(start, end);
return rootView;
}
}
感谢您的帮助
编辑 1:
按照 Luis Cardoza Bird 的建议,我将代码放在 onViewCreated() 中。但我面临着另一个问题,我在原来的帖子中很快提到过。我在 onViewCreated() 末尾启动一系列动画。首先,在启动时,气泡变大,然后在后台线程下载 JSON 文件时开始第二个动画(由 mStartingAnimation 表示),在最后一个动画结束时,我想停止onNewDataSolcast() 回调中的 mStartingAnimation。但我在这个函数中得到一个 NullPointerException 。我不明白,因为我之前已经开始了,所以我怎么可能得到 NullPointerException ? 我正常打开应用程序时没有这个问题。
这是新代码:
public class ForecastFragment extends Fragment implements OnNewDataSolcastListener, Animation.AnimationListener, OnFailGetDataSolcast{
private ScaleAnimation mStartingAnimation;
private ViewGroup mBubble;
private Solcast mSolcast;
private TextView mTxtConso;
private TextView mTxtConso2;
private TextView mTxtPresentationConso;
private ImageView mImgErrorSolcast;
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
Log.e(getClass().getSimpleName(), "onAttach()");
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
Log.e(getClass().getSimpleName(), "onCreateView()");
return inflater.inflate(R.layout.content_main, container, false);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
if(getActivity() instanceof Solcast.GetSolcastListener)
mSolcast = ((Solcast.GetSolcastListener) getActivity()).getSolcast();
else
throw new RuntimeException(getClass().getSimpleName() + " have to implement " + Solcast.GetSolcastListener.class.getSimpleName());
View rootView = getView();
assert rootView != null;
//init la GUI pour les fonctions qui auront besoin de ces View
mTxtConso = rootView.findViewById(R.id.txtValeurProduction);
mTxtConso2 = rootView.findViewById(R.id.txtValeurProduction2);
mTxtPresentationConso = rootView.findViewById(R.id.txtPresentationProduction);
mBubble = rootView.findViewById(R.id.bubbleMain);
mImgErrorSolcast = rootView.findViewById(R.id.imgErrorSolcast);
mImgErrorSolcast.setVisibility(View.GONE);
//on prépare la future animation pour la bulle qui respire
mStartingAnimation = new ScaleAnimation(1.05f, 1f, 1.05f, 1f, ScaleAnimation.RELATIVE_TO_SELF, 0.5f, ScaleAnimation.RELATIVE_TO_SELF, 0.5f);
mStartingAnimation.setDuration(1200);
mStartingAnimation.setInterpolator(new OvershootInterpolator());
mStartingAnimation.setRepeatCount(Animation.INFINITE);
//some stuff
mSolcast.setSearchDates(start, end);
final ScaleAnimation anim = new ScaleAnimation(0f, 1f, 0, 1f, ScaleAnimation.RELATIVE_TO_SELF, 0.5f, ScaleAnimation.RELATIVE_TO_SELF, 0.5f);
anim.setDuration(500);
anim.setInterpolator(new LinearInterpolator());
anim.setAnimationListener(this);
mBubble.startAnimation(anim);
}
/*
Appelée lorsque les données JSON ont été reçues puis traitées.
Renvoi la liste des énergies @listEnergy associées à leur date dans @listeDate
*/
@Override
public void onNewDataSolcast(ArrayList<Solcast.SolcastData> solcastData) {
//Les données JSON ont été traitées, triées, etc... On renvoi le résultat vers la GUI
Log.e("ForecastFragment:onNewDataSolcast", "New data");
//mStartingAnimation is null : NullPointerException here !
**mStartingAnimation.cancel();**
mBubble.clearAnimation();
}
//animation callbacks
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
//Lorsque la bulle, au démarrage, a fini de grossir on démarre le téléchargement JSON. Cela peut prendre quelques secondes,
//donc on fait l'animation de la bulle qui "respire" en boucle jusqu'à réception des données
//on fait apparaitre le texte "consomation estimée..."
ObjectAnimator anim2 = ObjectAnimator.ofFloat(mTxtPresentationConso, "alpha", 0.0f, 1.0f);
anim2.setInterpolator(new LinearInterpolator());
anim2.setDuration(2000);
anim2.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animator) {
}
@Override
public void onAnimationEnd(Animator animator) {
//start animation - works well
mBubble.startAnimation(mStartingAnimation);
//will call onNewDataSolcast() callback at the end of the operations
mSolcast.readJSON();
}
@Override
public void onAnimationCancel(Animator animator) {
}
@Override
public void onAnimationRepeat(Animator animator) {
}
});
anim2.start();
}
@Override
public void onAnimationRepeat(Animation animation) {
}
}
最佳答案
基本上,第一次调用 onCreate 时的 fragment 会被调用,但是为了解决您的问题,最好的建议是使用 onViewCreated,因为此时 fragment 将已经创建所需的上下文。
public class ForecastFragment extends Fragment implements OnNewDataSolcastListener, Animation.AnimationListener, OnFailGetDataSolcast {
private ScaleAnimation mStartingAnimation;
private ViewGroup mBubble;
private Solcast mSolcast;
private TextView mTxtConso;
private TextView mTxtConso2;
private TextView mTxtPresentationConso;
private ImageView mImgErrorSolcast;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
Log.e(getClass().getSimpleName(), "onCreateView()");
final View rootView = inflater.inflate(R.layout.content_main, container, false);
//init la GUI pour les fonctions qui auront besoin de ces View
return rootView;
}
@Override
public View onViewCreated(){
if(getActivity() instanceof Solcast.GetSolcastListener)
mSolcast = ((Solcast.GetSolcastListener) getActivity()).getSolcast();
else
throw new RuntimeException(getClass().getSimpleName() + " have to implement " + Solcast.GetSolcastListener.class.getSimpleName());
mTxtConso = rootView.findViewById(R.id.txtValeurProduction);
mTxtConso2 = rootView.findViewById(R.id.txtValeurProduction2);
mTxtPresentationConso = rootView.findViewById(R.id.txtPresentationProduction);
mBubble = rootView.findViewById(R.id.bubbleMain);
mImgErrorSolcast = rootView.findViewById(R.id.imgErrorSolcast);
mImgErrorSolcast.setVisibility(View.GONE);
//some stuff...
//FAIL HERE : mSolcast null
mSolcast.setSearchDates(start, end);
}
关于java - Android Fragment生命周期问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60993497/