Контекст недоступен во фрагменте .onStart () метод - PullRequest
0 голосов
/ 27 октября 2018

Я использую MPAndroidCharts внутри фрагмента, и это позволяет мне генерировать необходимые таблицы, которые я хочу отобразить.Часть библиотеки MPAndroidCharts требует следующего для инициализации диаграмм, у меня есть этот код в моем методе Fragment .onStart():

barColors.add(ContextCompat.getColor(getActivity().getApplicationContext(),R.color.bar_one));
barColors.add(ContextCompat.getColor(getActivity().getApplicationContext(), R.color.bar_two));
barColors.add(ContextCompat.getColor(getActivity().getApplicationContext(), R.color.bar_three));
barColors.add(ContextCompat.getColor(getActivity().getApplicationContext(), R.color.bar_four));
barColors.add(ContextCompat.getColor(getActivity().getApplicationContext(), R.color.bar_five));

Время от времени я получаю сообщение об ошибке ниже, и я не уверенпочему, это происходит не каждый раз, когда я открываю мероприятие, в котором размещен фрагмент, но иногда происходит.Я полагаю, что контекст фрагмента еще не активен, но я не могу подтвердить:

java.lang.NullPointerException: попытка вызвать виртуальный метод 'android.content.Context android.content.ContextWrapper.getApplicationContext ()' нассылка на нулевой объект в com.troychuinard.livevotingudacity.Fragment.PollFragment.updatePollResultAnswersDynamically (PollFragment.java:355) в com.troychuinard.livevotingudacity.Fragment.PollFragment.access $ 1300 (Pollroytragment comrajj..PollFragment $ 3.onDataChange (PollFragment.java:304) на com.google.firebase.database.obfuscated.zzap.zza (com.google.firebase: firebase-database @@ 16.0.2: 75) на com.google.firebase.database.obfuscated.zzca.zza (com.google.firebase: firebase-database @@ 16.0.2: 63) на com.google.firebase.database.obfuscated.zzcd $ 1.run (com.google.firebase: firebase-база данных @@ 16.0.2: 55) на android.os.Handler.handleCallback (Handler.java:751) на android.os.Handler.dispatchMessage (Handler.java:95) на android.os.Looper.loop (Looper.java:154) на android.app.ActivityThread.main (ActivityThread.java:6119) на java.lang.reflect.Method.invoke (собственный метод) на com.android.internal.os.ZygoteInit$ MethodAndArgsCaller.run (ZygoteInit.java:886) на com.android.internal.os.ZygoteInit.main (ZygoteInit.java:776)

ОБНОВЛЕНИЕ: соответствующий код фрагмента см. Ниже:

@Override
public void onStart() {
    super.onStart();
    valueEventListener = new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {

            int numberOfPollAnswersAtIndexBelowDate = (int) dataSnapshot.child(ANSWERS_LABEL).getChildrenCount();
            updatePollResultAnswersDynamically(numberOfPollAnswersAtIndexBelowDate, dataSnapshot);

            //Simply displaying, no need for mutable transaction
            int voteCountTotal = 0;
            ArrayList<Long> pollAnswersTotals = new ArrayList<Long>();
            for (int x = 0; x < numberOfPollAnswersAtIndexBelowDate; x++) {
                pollAnswersTotals.add(x, (Long) dataSnapshot.child(ANSWERS_LABEL).child(String.valueOf(x + 1)).child(VOTE_COUNT_LABEL).getValue());
                voteCountTotal += pollAnswersTotals.get(x);
            }

            DecimalFormat formatter = new DecimalFormat("#,###,###");
            String totalFormattedVotes = formatter.format(voteCountTotal);
            mTotalVoteCounter.setText(getResources().getString(R.string.votes) + String.valueOf(totalFormattedVotes));

        }

        @Override
        public void onCancelled(DatabaseError databaseError) {

        }
    };

    mSelectedPollRef.addValueEventListener(valueEventListener);

}

Метод:

private void updatePollResultAnswersDynamically(int numberOfAnswers, DataSnapshot dataSnapshot) {

//        mPollResults.clearValues();

        pollResultChartValues = new ArrayList<BarEntry>();

        for (int i = 0; i < numberOfAnswers; i++) {
            Long chartLongResultvalue = (Long) dataSnapshot.child(ANSWERS_LABEL).child(String.valueOf(numberOfAnswers - i)).child(VOTE_COUNT_LABEL).getValue();
            float chartFloatResultvalue = chartLongResultvalue.floatValue();
            pollResultChartValues.add(new BarEntry(chartFloatResultvalue, i));
        }

        data = new BarDataSet(pollResultChartValues, "Poll Results");

//        data.setColors(new int[]{getResources().getColor(R.color.black)});
        //TODO: Check attachment to Activity; when adding a color, the getResources.getColor states
        //TODO: that the fragment was detached from the activity; potentially add this method to onCreateView() to avoid;
//        ArrayList<Integer> barColors = new ArrayList<>();
//        barColors.add(R.color.bar_one);
//        barColors.add(R.color.bar_two);
//        barColors.add(R.color.bar_three);
//        barColors.add(R.color.bar_four);
//        barColors.add(R.color.bar_five);

        mBarColors.clear();

        mBarColors.add(ContextCompat.getColor(getActivity().getApplicationContext(),R.color.bar_one));
        mBarColors.add(ContextCompat.getColor(getActivity().getApplicationContext(), R.color.bar_two));
        mBarColors.add(ContextCompat.getColor(getActivity().getApplicationContext(), R.color.bar_three));
        mBarColors.add(ContextCompat.getColor(getActivity().getApplicationContext(), R.color.bar_four));
        mBarColors.add(ContextCompat.getColor(getActivity().getApplicationContext(), R.color.bar_five));
        data.setColors(mBarColors);

        data.setAxisDependency(YAxis.AxisDependency.LEFT);
        MyDataValueFormatter f = new MyDataValueFormatter();
        data.setValueFormatter(f);


        //xAxis is a inverted yAxis since the graph is horizontal
        XAxis xAxis = mPollResults.getXAxis();
        xAxis.setDrawGridLines(false);
        xAxis.setDrawAxisLine(false);
        xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);
        if ((getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_XLARGE) {
            xAxis.setTextSize(20);
        } else if ((getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_LARGE) {
            xAxis.setTextSize(16);
        }

        //yAxis is an inverted xAxis since the graph is horizontal
        YAxis yAxisLeft = mPollResults.getAxisLeft();
        yAxisLeft.setDrawGridLines(false);
        yAxisLeft.setEnabled(false);
        YAxis yAxisRight = mPollResults.getAxisRight();
        yAxisRight.setDrawGridLines(false);
        yAxisRight.setEnabled(false);


        Legend legend = mPollResults.getLegend();
        legend.setEnabled(false);


        //TODO: This figure needs to be dynamic and needs to adjust based on the number of users in the application
        //TODO: Or does it? Right now, it scales without it

        dataSets = new ArrayList<IBarDataSet>();

        dataSets.add(data);


        //Poll Answer Options get added here
        ArrayList<String> yVals = new ArrayList<String>();
        for (int x = 0; x < numberOfAnswers; x++) {
            String pollResult = (String) dataSnapshot.child(ANSWERS_LABEL).child(String.valueOf((numberOfAnswers) - x)).child("answer").getValue();
            yVals.add(x, pollResult);
        }

        BarData testBarData = new BarData(yVals, dataSets);
        //TODO: Fix all text sizes using this method
        if ((getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_XLARGE) {
            testBarData.setValueTextSize(22);
        } else if ((getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_LARGE) {
            testBarData.setValueTextSize(14);
        } else if ((getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_NORMAL) {
            testBarData.setValueTextSize(12);
        } else if ((getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_SMALL) {
            testBarData.setValueTextSize(12);
        }

        mPollResults.getXAxis().setLabelRotationAngle(-15);
        mPollResults.getXAxis().setSpaceBetweenLabels(5);
        mPollResults.setTouchEnabled(false);
        mPollResults.setPinchZoom(false);
        mPollResults.setData(testBarData);
        data.notifyDataSetChanged();
        mPollResults.notifyDataSetChanged();
        mPollResults.invalidate();
    }

Ответы [ 2 ]

0 голосов
/ 27 октября 2018

Вы имеете дело с двумя разными жизненными циклами компонентов, которые не знают друг о друге:

  1. Жизненный цикл вашего фрагмента , который не всегда имеет прикрепленный контекст (действие)
  2. Жизненный цикл вашего Firebase ValueEventListener, который привязан к чтению из вашей базы данных.

Как пишутся вещи, ни ваш фрагмент, ни ваш ValueEventListener не знают о жизненном цикле другого.

Несколько способов решить эту проблему:

Удалите свой ValueEventListener из onStop

Поскольку onStart происходит после onAttach, а onStop происходит раньше, чем onDetach, вы можетеудалите свой ValueEventListener в onStop.Таким образом, ваша регистрация слушателя будет симметричной.Конечно, вы пропустите DataSnapshots, пока ваш фрагмент отделен от контекста.Если все в порядке, это, вероятно, будет работать нормально.

Передайте контекст приложения вашему конструктору Fragment

Другой подход заключается в том, чтобы ваш Fragment взял контекст в своем конструкторе.и удерживайте его в переменной-члене и ссылайтесь на него вместо вызова getActivity().

ПРИМЕЧАНИЕ : если вы передадите Context в конструкторе, обязательно удалите контекст приложения из переданного в Context и сделайте ссылку на него, чтобы избежать утечки контекста действия.Вы можете сделать это, позвонив по номеру context.getApplicationContext();

0 голосов
/ 27 октября 2018

Вы должны переместить всю контекстную инициализацию в метод onAttach(Context context).Фрагменты должны быть присоединены к контексту, прежде чем они смогут использовать метод getActivity().В противном случае этот метод возвратит ноль.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...