Android проблема жизненного цикла фрагмента - PullRequest
0 голосов
/ 02 апреля 2020

Я создаю свои фрагменты в onCreate () моего первого действия. В этом случае in может видеть следующий поток приложения:

  • MainActivity: onCreate ()
  • Fragment1: onAttach (): где я получаю слушателя для получения данных из Activity
  • Fragment1: onCreateView ()
  • Fragment2: onAttach ()
  • Fragment2: onCreateView ()
  • Fragment3: onAttach ()
  • Fragment3: onCreateView ()
  • ...

Мое приложение работает очень хорошо, за исключением следующих случаев: 1 - открыть приложение 2 - нажать кнопку возврата домой 3 - принудительно убить приложение со встроенным оптимизатором приложение 4 - снова откройте приложение

В этом случае приложение выглядит так:

  • Fragment1: onAttach ()
  • MainActivity: onCreate ()
  • Fragment1: onCreateView ()
  • ...

И, следовательно, получатель, который я получаю в методе onAttach () , не является действительный и приводит к NullPointerException, когда я использую интерфейс! Я не понимаю, как я могу это исправить. Я пытался получить обратный вызов в onCreatedActivity () , но это приводит меня к другой проблеме.

Как я могу это исправить?

publi c class 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;
}

}

Спасибо за вашу помощь

EDIT 1 :

Как подсказал Луис Кардоза Берд, я поместил свой код в onViewCreated (). Но я столкнулся с другой проблемой, о которой я быстро упомянул в оригинальном сообщении. Я начинаю цепочку анимаций в конце onViewCreated (). Сначала при запуске растет пузырь, затем запускается вторая анимация (представленная mStartingAnimation ), когда фоновый поток загружает файл JSON, и в конце последней анимации я хочу остановить mStartingAnimation в обратном вызове onNewDataSolcast () . Но я получаю исключение 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) {

}

}

1 Ответ

0 голосов
/ 02 апреля 2020

Обычно вызывается фрагмент при первом вызове onCreate, однако для решения вашей проблемы лучше всего использовать onViewCreated, потому что в этот момент фрагмент будет иметь требуемый контекст, уже созданный.

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);

}

...