0

I have an Android application with a ViewPager that allows swiping between tabs. When I swipe between tabs I call functions inside the newly active Fragment to update text on that Fragment, and it sometimes throws a NullPointerException but I cannot replicate it on my device. Was wondering if someone could take a look at the code & stack trace below and possibly assist - it would be greatly appreciated. I am not sure if I am missing something or not doing this correctly?

My first thought this morning was that maybe I should be running this on a separate thread as to not disturb the main UI thread or maybe try/catch these functions since they seem to only sometimes crash the app? Thanks in advance.

ViewPagerCode

public void onTabChanged(String tag) {
        //TabInfo newTab = this.mapTabInfo.get(tag);
        int pos = this.mTabHost.getCurrentTab();
        mTabHost.getCurrentTabView().invalidate();
        this.mViewPager.setCurrentItem(pos);



    // calculatePoints on TabChange
    if (pos == 1) {
        TabFragment2 fragTrack = (TabFragment2) fragments.get(1);
        fragTrack.calculatePoints();
        fragTrack.createAndFillDatabase();
    }

    else if (pos == 2) {
        TabFragment3 fragFoodList = (TabFragment3) fragments.get(2);
        fragFoodList.createAndFillDatabase("none");
    }

    this.supportInvalidateOptionsMenu();
}

calculatePoints()

public void calculatePoints() {
        int prefDailyPoints, prefPointsUsed, prefPointsRemain, prefBonusPoints, prefBonusUsed, prefBonusPointsRemain;

        // Get points values and fill in respective fields
        appSettings = PreferenceManager.getDefaultSharedPreferences(currentActivity);
        nonDBData = currentActivity.getSharedPreferences(NONDB_DATA, 0);

        prefDailyPoints = Integer.parseInt(appSettings.getString("pointsAllowed", "0"));
        prefPointsUsed = nonDBData.getInt("pointsUsed", 0);
        //prefPointsRemain = nonDBData.getInt("pointsRemain", prefDailyPoints - prefPointsUsed);
        prefPointsRemain = prefDailyPoints - prefPointsUsed;

        textfieldPointsDaily.setText(Integer.toString(prefDailyPoints));
        textfieldPointsUsed.setText(Integer.toString(prefPointsUsed));
        textfieldPointsRemain.setText(Integer.toString(prefPointsRemain));

        if (prefPointsRemain < 0) {
                textfieldPointsRemain.setTextColor(Color.rgb(255, 0, 0));
                textfieldPointsRemain.setTypeface(null, Typeface.BOLD);
        }
        else {
                textfieldPointsRemain.setTextColor(Color.rgb(0, 0, 0));
                textfieldPointsRemain.setTypeface(null, Typeface.NORMAL);
        }
}

Stack Trace

java.lang.NullPointerException 
at android.preference.PreferenceManager.getDefaultSharedPreferencesName(PreferenceManager.java:371)
at android.preference.PreferenceManager.getDefaultSharedPreferences(PreferenceManager.java:366)
at com.mattdonders.android.wppcalculator.TabFragment2.calculatePoints(TabFragment2.java:667)
at com.mattdonders.android.wppcalculator.TabsViewPagerFragmentActivity.onTabChanged(TabsViewPagerFragmentActivity.java:483)
at android.widget.TabHost.invokeOnTabChangeListener(TabHost.java:446)
at android.widget.TabHost.setCurrentTab(TabHost.java:431) 
at com.mattdonders.android.wppcalculator.TabsViewPagerFragmentActivity.onPageSelected(TabsViewPagerFragmentActivity.java:511)
at android.support.v4.view.ViewPager.scrollToItem(ViewPager.java:539)
at android.support.v4.view.ViewPager.setCurrentItemInternal(ViewPager.java:524)
at android.support.v4.view.ViewPager.onTouchEvent(ViewPager.java:1941)
at android.view.View.dispatchTouchEvent(View.java:7239) 
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2168)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1903) 
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2174)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1917) 
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2174)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1917) 
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2174)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1917) 
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2174)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1917) 
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2174)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1917) 
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2174)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1917) 
at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:1953)
at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1405)
at android.app.Activity.dispatchTouchEvent(Activity.java:2410) 
at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:1901)
at android.view.View.dispatchPointerEvent(View.java:7419) 
at android.view.ViewRootImpl.deliverPointerEvent(ViewRootImpl.java:3220)
at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:3165)
at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:4292)
at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:4271)
at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:4363)
at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:179)
at android.os.MessageQueue.nativePollOnce(Native Method) 
at android.os.MessageQueue.next(MessageQueue.java:125) 
at android.os.Looper.loop(Looper.java:124)
at android.app.ActivityThread.main(ActivityThread.java:5039) 
at java.lang.reflect.Method.invokeNative(Native Method) 
at java.lang.reflect.Method.invoke(Method.java:511) 
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560) 
at dalvik.system.NativeStart.main(Native Method)
mango
  • 5,577
  • 4
  • 29
  • 41
mattdonders
  • 1,328
  • 1
  • 19
  • 42
  • 2
    Are you sure currentActivity isn't null? You might be calling your calculatePoints() method before the activity is attached to your new fragment (I dont know the order you are calling things in) – dymmeh Jan 14 '13 at 14:11
  • `calculatePoints()` must be called only after `onActivityCreated()` is called on that Fragment. – S.D. Jan 14 '13 at 14:13
  • My knee-jerk reaction is to suspect that 'currentActivity' you're passing it. – Todd Sjolander Jan 14 '13 at 14:13
  • `currentActivity` is defined in the onCreateView of the Fragment and the Activity always loads with Fragment 0 loaded, so shouldn't it not be null? Is this not correct way to get the Activity that contains Fragments? `currentActivity = TabFragment2.this.getActivity();` – mattdonders Jan 14 '13 at 14:15
  • @dymmeh Do you think that a try/catch might work in this instance since I have had others confirm that the app works after opening it a second time? This should mean the first time it tries to bind to `currentActivity` it will fail, but after its not NULL it should be good or is that not good practice. Even though `currentActivity` should technically be defined I can't get it to be NULL while debugging on my device. – mattdonders Jan 14 '13 at 15:23
  • @mattdonders - relying on a try catch shouldn't really be your solution. You should learn a fragments lifecycle and make sure to code your application so that you cannot run your calculatePoints() code until after you have an activity attached to the fragment. calculatePoints() shouldn't be called by the Tab Activity. It should be called by the fragment itself. – dymmeh Jan 14 '13 at 15:40
  • @dymmeh but this is my confusion. How do I call a function when the Fragment becomes focused. `onResume()` of a fragment is called based on its containing activity being resumed. And `onResumeFragments()` seems to allow code in your host Activity to be called when your Fragment resumes. Is there a function that gets called when the Fragment gets focused itself? Thanks. – mattdonders Jan 14 '13 at 15:57
  • @mattdonders - http://stackoverflow.com/questions/10024739/how-to-determine-when-fragment-becomes-visible-in-viewpager try this out.. – dymmeh Jan 14 '13 at 17:03
  • @dymmeh Wow thank you so much. This means I can move my code out of the Activity hosting the Fragments and into the Fragment itself - this should get rid of all the issues I am facing. Thank you so much - you have been an extreme help. – mattdonders Jan 14 '13 at 17:51

1 Answers1

0

I changed my code to detect userVisibleHint which was fixed mid-2012 by the Android team. This worked 100% and fixed my issues - thanks everyone!

@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);

    if (isVisibleToUser == true) { 
        // TO-DO
    }
    else if (isVisibleToUser == false) {
        // TO-DO
    }

}

Android Support Library (rev 11) finally fixed the user visible hint issue, now if you use support library for fragments, then you can safely use getUserVisibleHint() or override setUserVisibleHint() to capture the changes as described by gorn's answer.

mattdonders
  • 1,328
  • 1
  • 19
  • 42