java - Android Fragment生命周期问题

标签 java android android-fragments android-lifecycle

我在第一个 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/

相关文章:

android - 来自 Fragment 的 DialogFrag#show() 抛出 "IllegalStateException: Can not perform this action after onSaveInstanceState"

java - 如何读取文件中从行号 n 到行号 m 的行?

android - 启动后台进程时 ADB 进程阻塞

android - 自定义适配器从 fragment 获取空上下文

android - 如何在 Ubuntu 11.10(32 位)上安装 Tegra Android 开发包

android - 使用 Mockito 进行 Retrofit 2 api 调用的单元测试

android - 如何从 Fragment 切换到 Activity?

java - 从带有逗号分隔符错误的文件中读取

java - 将值存储到多维数组中

java - 将长字符串解析为 LocalDate 变量