Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Occasional NPE when accessing fragment's view

I occasionally get NullPointerException when entering fragment. It happens when the app was in the background for a long time and then I open it and swipe to this fragment.

public class SummaryFragment extends Fragment implements FragmentLifecycle {

    private static final String TAG = "DTAG";
    private DateFormat dateFormatName;
    private Preference prefs;
    private List<String> monthList;
    private TextView totalTimeFullTv;
    private TextView totalTimeNetTv;
    private TextView averageTimeTv;
    private TextView overUnderTv;
    private TextView minTimeTv;
    private TextView maxTimeTv;
    private TextView vacationsTv;
    private TextView sickTv;
    private TextView headlineTv;
    private TextView overUnderTvH;
    private OnFragmentInteractionListener mListener;

    public SummaryFragment() {
        // Required empty public constructor
    }


    public static SummaryFragment newInstance(String param1, String param2) {
        SummaryFragment fragment = new SummaryFragment();
        return fragment;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        View RootView = inflater.inflate(R.layout.fragment_summary, container, false);

        dateFormatName = new SimpleDateFormat(getResources().getString(R.string.month_text));
        monthList = Arrays.asList(new DateFormatSymbols().getMonths());
        prefs = new Preference(GeneralAdapter.getContext());


        totalTimeFullTv = RootView.findViewById(R.id.textView_sum_ttf);
        totalTimeNetTv = RootView.findViewById(R.id.textView_sum_ttn);
        averageTimeTv = RootView.findViewById(R.id.textView_sum_av);
        overUnderTv = RootView.findViewById(R.id.textView_sum_ou);
        overUnderTvH = RootView.findViewById(R.id.textView_sum_ou_h);


        minTimeTv = RootView.findViewById(R.id.textView_sum_min);
        maxTimeTv = RootView.findViewById(R.id.textView_sum_max);
        vacationsTv = RootView.findViewById(R.id.textView_sum_vac);
        sickTv = RootView.findViewById(R.id.textView_sum_sick);
        headlineTv= RootView.findViewById(R.id.textView_sum_headline);

        return RootView;
    }

    private void refreshData() {

        if (prefs == null)
        {
            prefs = new Preference(GeneralAdapter.getContext());
        }

        String month = prefs.getString(Preference.CURRENT_MONTH);

        MonthData monthData = Calculators.CalculateLocalData(MainActivity.db.getAllDays(month));

        totalTimeFullTv.setText(monthData.getTotalTimeFull()); //Crash here
        totalTimeNetTv.setText(monthData.getTotalTimeNet());
        averageTimeTv.setText(monthData.getAverageTime());
        overUnderTv.setText(monthData.getOverUnder());
        if (monthData.getOverUnderFloat()<0)
        {
            overUnderTvH.setText(R.string.sum_over_time_neg);
            overUnderTv.setTextColor(ContextCompat.getColor(GeneralAdapter.getContext(),R.color.negative_color));
        }
        else
        {
            overUnderTvH.setText(R.string.sum_over_time_pos);
            overUnderTv.setTextColor(ContextCompat.getColor(GeneralAdapter.getContext(),R.color.positive_color));
        }

        minTimeTv.setText(monthData.getMinTime());
        maxTimeTv.setText(monthData.getMaxTime());
        vacationsTv.setText(""+monthData.getVacations());
        sickTv.setText(""+monthData.getSick());
        headlineTv.setText(month);
    }

    public void onButtonPressed(Uri uri) {
        if (mListener != null) {
            mListener.onFragmentInteraction(uri);
        }
    }

    @Override
    public void onAttachFragment(Fragment childFragment) {
        super.onAttachFragment(childFragment);

    }

    @Override
    public void onDetach() {
        super.onDetach();
        mListener = null;
    }

    @Override
    public void onPauseFragment() {

    }

    @Override
    public void onResumeFragment()
    {
        refreshData();
    }


    public interface OnFragmentInteractionListener {
        // TODO: Update argument type and name
        void onFragmentInteraction(Uri uri);
    }
}

MainActivity viewPager:

viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            int currentPosition = 0;

            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
            }

            @Override
            public void onPageSelected(int position) {

                FragmentLifecycle fragmentToHide = (FragmentLifecycle) adapter.getItem(currentPosition);
                fragmentToHide.onPauseFragment();

                FragmentLifecycle fragmentToShow = (FragmentLifecycle) adapter.getItem(position);
                fragmentToShow.onResumeFragment(); //Crash start

                currentPosition = position;
            }

            @Override
            public void onPageScrollStateChanged(int state) {

            }
        });

Log:

                                            E/AndroidRuntime: FATAL EXCEPTION: main
                                               Process: michlind.com.workcalendar, PID: 25038
                                               java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.TextView.setText(java.lang.CharSequence)' on a null object reference
                                                   at michlind.com.workcalendar.mainfragments.SummaryFragment.refreshData(SummaryFragment.java:99)
                                                   at michlind.com.workcalendar.mainfragments.SummaryFragment.onResumeFragment(SummaryFragment.java:147)
                                                   at michlind.com.workcalendar.activities.MainActivity.onPageSelected(MainActivity.java:84)
                                                   at android.support.v4.view.ViewPager.dispatchOnPageSelected(ViewPager.java:1941)
                                                   at android.support.v4.view.ViewPager.scrollToItem(ViewPager.java:680)
                                                   at android.support.v4.view.ViewPager.setCurrentItemInternal(ViewPager.java:664)
                                                   at android.support.v4.view.ViewPager.onTouchEvent(ViewPager.java:2257)
                                                   at android.view.View.dispatchTouchEvent(View.java:11776)
                                                   at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2962)
                                                   at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2643)
                                                   at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2968)
                                                   at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2657)
                                                   at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2968)
                                                   at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2657)
                                                   at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2968)
                                                   at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2657)
                                                   at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2968)
                                                   at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2657)
                                                   at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2968)
                                                   at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2657)
                                                   at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2968)
                                                   at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2657)
                                                   at com.android.internal.policy.DecorView.superDispatchTouchEvent(DecorView.java:448)
                                                   at com.android.internal.policy.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1829)
                                                   at android.app.Activity.dispatchTouchEvent(Activity.java:3307)
                                                   at android.support.v7.view.WindowCallbackWrapper.dispatchTouchEvent(WindowCallbackWrapper.java:68)
                                                   at com.android.internal.policy.DecorView.dispatchTouchEvent(DecorView.java:410)
                                                   at android.view.View.dispatchPointerEvent(View.java:12015)
                                                   at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:4795)
                                                   at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:4609)
                                                   at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4147)
                                                   at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:4200)
                                                   at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4166)
                                                   at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:4293)
                                                   at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4174)
                                                   at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:4350)
                                                   at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4147)
                                                   at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:4200)
                                                   at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4166)
                                                   at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4174)
                                                   at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4147)
                                                   at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:6661)
                                                   at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:6635)
                                                   at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:6596)
                                                   at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:6764)
                                                   at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:186)
                                                   at android.os.MessageQueue.nativePollOnce(Native Method)
                                                   at android.os.MessageQueue.next(MessageQueue.java:325)
                                                   at android.os.Looper.loop(Looper.java:142)
                                                   at android.app.ActivityThread.main(ActivityThread.java:6494)

UPDATE:

I eventually used:

@Override
public void onPageSelected(int position) {

    Fragment fragment = adapter.getFragment(position);
    if (fragment != null) {
        fragment.onResume();
    }
}

At my MainActivity, and used onResume() at each fragment. And this solution for the adapter: http://thedeveloperworldisyours.com/android/update-fragment-viewpager/

like image 497
Dim Avatar asked Jan 03 '18 20:01

Dim


2 Answers

The problem is, that you are trying to access views too early: view hierarchy is not created at that point yet.

If you post an event, that would take place on the next frame, you are guaranteed, that view hierarchy would be already setup:

@Override
public void onResumeFragment() {
    new Handler().post(new Runnable() {
        @Override
        public void run() {
            refreshData();
        }
    });
}
like image 179
azizbekian Avatar answered Nov 05 '22 01:11

azizbekian


I faced the same problem when I had implemented custom life cycles for ViewPager. I think you are using FragmentStatePagerAdapter to populate fragments with ViewPager. As we know FragmentStatePagerAdapter destroys all the fragments when they lose focus. We need to provide same object for every page using singleton pattern.

In your code, Fragment creation can be like below for singleton pattern.

private SummaryFragment mInstance;

private SummaryFragment() {
        // Required empty public constructor
    }

public static SummaryFragment newInstance(String param1, String param2) {
        if(mInstance == null)
        mInstance = new SummaryFragment();
        return mInstance;
    }

Doing this has solved my problem. If this does not work for you? Can you share your PagerAdapter class.

like image 21
Nagoor babu Avatar answered Nov 05 '22 01:11

Nagoor babu