3

i am having an issue with an app i am making, everything seemed to be working ok until i started getting an error seemingly out of no where i dont believe i changed any thing from when it was working but every time i open the activity it give me a NullPointerException, heres the logcat from it.

09-13 18:29:54.951: E/AndroidRuntime(4407): FATAL EXCEPTION: main
09-13 18:29:54.951: E/AndroidRuntime(4407): Process: renseew.knowyourtime, PID: 4407
09-13 18:29:54.951: E/AndroidRuntime(4407): java.lang.NullPointerException
09-13 18:29:54.951: E/AndroidRuntime(4407):     at android.support.v13.app.FragmentCompatICS.setMenuVisibility(FragmentCompatICS.java:23)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at android.support.v13.app.FragmentCompat$ICSFragmentCompatImpl.setMenuVisibility(FragmentCompat.java:41)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at android.support.v13.app.FragmentCompat.setMenuVisibility(FragmentCompat.java:68)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at android.support.v13.app.FragmentStatePagerAdapter.instantiateItem(FragmentStatePagerAdapter.java:120)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at android.support.v4.view.ViewPager.addNewItem(ViewPager.java:837)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at android.support.v4.view.ViewPager.populate(ViewPager.java:987)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at android.support.v4.view.ViewPager.populate(ViewPager.java:919)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at android.support.v4.view.ViewPager.onMeasure(ViewPager.java:1441)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at android.view.View.measure(View.java:16497)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at android.support.v4.widget.DrawerLayout.onMeasure(DrawerLayout.java:762)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at android.view.View.measure(View.java:16497)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5125)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at android.widget.FrameLayout.onMeasure(FrameLayout.java:310)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at android.view.View.measure(View.java:16497)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5125)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at com.android.internal.widget.ActionBarOverlayLayout.onMeasure(ActionBarOverlayLayout.java:327)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at android.view.View.measure(View.java:16497)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5125)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at android.widget.FrameLayout.onMeasure(FrameLayout.java:310)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at com.android.internal.policy.impl.PhoneWindow$DecorView.onMeasure(PhoneWindow.java:2291)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at android.view.View.measure(View.java:16497)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:1916)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:1113)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1295)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1000)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5670)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at android.view.Choreographer$CallbackRecord.run(Choreographer.java:761)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at android.view.Choreographer.doCallbacks(Choreographer.java:574)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at android.view.Choreographer.doFrame(Choreographer.java:544)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:747)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at android.os.Handler.handleCallback(Handler.java:733)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at android.os.Handler.dispatchMessage(Handler.java:95)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at android.os.Looper.loop(Looper.java:136)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at android.app.ActivityThread.main(ActivityThread.java:5017)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at java.lang.reflect.Method.invokeNative(Native Method)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at java.lang.reflect.Method.invoke(Method.java:515)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at dalvik.system.NativeStart.main(Native Method)

the activity uses a FragmentStatePagerAdapter to dynamically add tabs from a fragment to to activity, ive also tried changing if(position < companies.size() -1) to if(position < companies.size()) no change(the first one worked before i started getting the error) heres the activity code.

public class UserDetails extends BaseActivity implements ActionBar.TabListener {

    CompanyPagerAdapter companyPagerAdapter;
    ViewPager viewPager;
    Cursor cursor;

    SettingsDBAdapter settingsDBAdapter;
    String companyName;
    private List<String> companies = new ArrayList<String>();
    ActionBar ab;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_user_details);
        updateActionBarNavigation();
        initialize();
        setupTabs();
        getCompanies();
        getTabs();
    }

    private void initialize() {
        if(ab != null)
            ab.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

        viewPager = (ViewPager) findViewById(R.id.UDviewpager);

        ContentResolver settingsContent = this.getContentResolver();
        cursor = settingsContent.query(KnowYourTimeContentProvider.CONTENT_URI_SETTINGS, null, null, null, null);
        settingsDBAdapter = new SettingsDBAdapter(getApplicationContext());

        if (cursor.getCount() == 0) {
            settingsDBAdapter.settingsDBOpen();
            settingsDBAdapter.setDefaultSettings();
        }
    }

    private void setupTabs() {
        companyPagerAdapter = new CompanyPagerAdapter(getFragmentManager());

        viewPager.setAdapter(companyPagerAdapter);
        viewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
                    @Override
                    public void onPageSelected(int position) {
                        if (ab != null) {
                            ab.setSelectedNavigationItem(position);
                        }
                    }
                });
    }

    private void getTabs() {
        for (int i = 0; i < companyPagerAdapter.getCount(); i++) {
            if (ab != null) {
                ab.addTab(ab.newTab()
                        .setText(companyPagerAdapter.getPageTitle(i))
                        .setTabListener(this));
            }
        }
    }

    private void getCompanies() {
        cursor = settingsDBAdapter.getCompanies();
        if (companies.size() != 0) {
            for (int i = 0; i < companies.size(); i++) {
                companyName = companies.get(i);
                companies.add(companyName);
            }
        } else if (cursor.getCount() != 0) {
            while (cursor.moveToNext()) {
                companyName = cursor.getString(cursor.getColumnIndex("company"));
                companies.add(companyName);
            }
        } else {
            companyName = getString(R.string.company);
            companies.add(companyName);
        }
        companyPagerAdapter.notifyDataSetChanged();
    }

    @Override
    protected void onNavDrawerStateChanged(boolean isOpen, boolean isAnimating) {
        super.onNavDrawerStateChanged(isOpen, isAnimating);
        updateActionBarNavigation();
    }

    @Override
    protected void onActionBarAutoShowOrHide(boolean shown) {
        super.onActionBarAutoShowOrHide(shown);
    }

    private void updateActionBarNavigation() {
        boolean show = !isNavDrawerOpen();

        ab = getActionBar();
        if (show && ab != null) {
            ab.setDisplayShowCustomEnabled(true);
            ab.setDisplayShowTitleEnabled(true);
            ab.setDisplayUseLogoEnabled(false);
            ab.setTitle(getString(R.string.title_user_details));
        } else if (ab != null) {
            ab.setDisplayShowCustomEnabled(false);
            ab.setDisplayShowTitleEnabled(false);
            ab.setDisplayUseLogoEnabled(true);
        }
    }

    @Override
    protected int getSelfNavDrawerItem() {
        return NAVDRAWER_ITEM_USERDETAILS;
    }

    @Override
    public void onTabSelected(ActionBar.Tab tab,
                              FragmentTransaction fragmentTransaction) {
        viewPager.setCurrentItem(tab.getPosition());

        companies.get(tab.getPosition());
    }

    @Override
    public void onTabUnselected(ActionBar.Tab tab,
                                FragmentTransaction fragmentTransaction) {
    }

    @Override
    public void onTabReselected(ActionBar.Tab tab,
                                FragmentTransaction fragmentTransaction) {
    }

    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.usersettings_menu, menu);
        return true;
    }

    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        menu.clear();
        menu.add(Menu.NONE, R.id.addCompany, Menu.NONE, getString(R.string.add) + " " + getString(R.string.company));
        menu.add(Menu.NONE, R.id.removeCompany, Menu.NONE, getString(R.string.subtract) + " " + getString(R.string.company));
        return super.onPrepareOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem menuItem) {
        switch (menuItem.getItemId()) {
            case R.id.addCompany:
                companies.clear();
                companyName = getString(R.string.company);
                companies.add(companyName);
                companyPagerAdapter.notifyDataSetChanged();
                getTabs();
                return true;
            case R.id.removeCompany:
                return true;
            default:
                return super.onOptionsItemSelected(menuItem);
        }
    }

    public class CompanyPagerAdapter extends FragmentStatePagerAdapter {

        public CompanyPagerAdapter(FragmentManager fm) {
            super(fm);
        }

        @Override
        public Fragment getItem(int position) {
            while (position < companies.size() - 1) {
                if (position < companies.size() - 1) {
                    position++;
                    return FragmentUserDetails.newInstance(companies.get(position));
                }
            }
            return null;
        }

        @Override
        public int getCount() {
            return companies.size();
        }

        @Override
        public CharSequence getPageTitle(int position) {
            while (position < companies.size() - 1) {
                if (position < companies.size() - 1) {
                    position++;
                    return companies.get(position);
                }
            }
            return "";
        }
    }
}

and here is the code for the fragment that the activity opens.

public class FragmentUserDetails extends Fragment implements AdapterView.OnItemClickListener, View.OnClickListener {

    private BaseAdapter listAdapter;
    private Cursor settingsCursor, companyCursor;

    private String payrate, payperiod, weekstart, allowances, maritalstatus;
    private String companyname;
    private Switch cbMaritalStatus;
    public EditText etCompanyName, etPayrate;
    private Spinner sPayPeriod, sPeriodStart, sAllowances;
    SettingsDBAdapter settingsDBAdapter;

    static FragmentUserDetails newInstance(String title) {
        FragmentUserDetails fragmentUserDetails = new FragmentUserDetails();
        Bundle args = new Bundle();
        args.putString("title", title);
        fragmentUserDetails.setArguments(args);
        return fragmentUserDetails;
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_user_details, container, false);
        initialization(view);
        return view;
    }

    private void initialization(View view) {
        etCompanyName = (EditText) view.findViewById(R.id.UDedittextCompany);
        etPayrate = (EditText) view.findViewById(R.id.UDedittextPayrate);
        sPayPeriod = (Spinner) view.findViewById(R.id.UDspinnerPayPeriod);
        sPeriodStart = (Spinner) view.findViewById(R.id.UDspinnerPeriodStart);
        sAllowances = (Spinner) view.findViewById(R.id.UDspinnerAllowances);
        cbMaritalStatus = (Switch) view.findViewById(R.id.UDswitchMaritalStatus);
        Button save = (Button) view.findViewById(R.id.UDbuttonSaveSettings);

        save.setOnClickListener(this);

        ContentResolver settingsContent = getActivity().getContentResolver();
        settingsCursor = settingsContent.query(KnowYourTimeContentProvider.CONTENT_URI_SETTINGS, null, null, null, null);
        settingsDBAdapter = new SettingsDBAdapter(getActivity().getApplicationContext());

        companyname = getArguments().getString("title");

        if (settingsCursor.getCount() != 0) {
            while (settingsCursor.moveToNext()) {
                companyCursor = settingsDBAdapter.fetchCompanyInfo(companyname);
            }

            if (companyCursor.getCount() != 0) {
                while (companyCursor.moveToNext()) {
                    payrate = companyCursor.getString(companyCursor.getColumnIndex("payrate"));
                    payperiod = companyCursor.getString(companyCursor.getColumnIndex("payperiod"));
                    weekstart = companyCursor.getString(companyCursor.getColumnIndex("weekstart"));
                    allowances = companyCursor.getString(companyCursor.getColumnIndex("allowances"));
                    maritalstatus = companyCursor.getString(companyCursor.getColumnIndex("maritalstatus"));
                }
            } else {
                payrate = "";
                payperiod = getString(R.string.weekly);
                weekstart = getString(R.string.sunday);
                allowances = "0";
                maritalstatus = getString(R.string.no);
            }
        } else {
            companyname = getString(R.string.company);
        }

        etCompanyName.setText(companyname);
        etPayrate.setText(payrate);
        sPayPeriod.setSelection(getIndex(sPayPeriod, payperiod));
        sPeriodStart.setSelection(getIndex(sPeriodStart, weekstart));
        sAllowances.setSelection(getIndex(sAllowances, allowances));

        if (maritalstatus.equals(getString(R.string.yes))) {
            cbMaritalStatus.setChecked(true);
        } else {
            cbMaritalStatus.setChecked(false);
        }
    } 
}

sorry to put so much code im just unsure what is causing the issue. thanks in advance for any help

Update: so the error does seem to be coming from getItem() using the debugger. it runs through once just fine(which makes sense because there is 1 row initially) but the second time around is when it causes the crash. i also changed the code within it to this

public Fragment getItem(int position) {
    FragmentUserDetails fragment = null;
        if (position < companies.size() - 1) {
            fragment = FragmentUserDetails.newInstance(companies.get(position));
        }
    return fragment;
}

to make it simpler as suggested. still getting the same error. thanks again for any help

Adam Weesner
  • 33
  • 1
  • 5
  • If you have posted the full stack trace (double check this), it is one of the very rare occasions where it is entirely unhelpful because it doesn't indicate where in your own code the problem is. You need to fire up a debugger and determine where the `NullPointerException` occurs. – Code-Apprentice Sep 14 '14 at 00:03
  • p.s. Your implementation of `getItem()` looks very suspicious. You should not increment the value of the `position` parameter that is sent to this method. – Code-Apprentice Sep 14 '14 at 00:06
  • yea that is the full stack trace ive been looking at it for several hours trying different things to get it to work. and as far as the getitem() i was unsure how to get it to work dynamically and tried it and it worked at least until i started getting the error. ill try using the debugger and report back. – Adam Weesner Sep 14 '14 at 00:12
  • `getItem()` should most likely be a simple `return` statement. You might want to use an `if` statement for bounds checking, but a `while` loop is certainly incorrect. The one thing to be careful about is to check if `position` is 1-based. The documentation is silent on this detail. Since you store the titles in a `List`, your own indices are 0-based. Adjusting for the difference here is as simple as adding or subtracting 1 as appropriate. – Code-Apprentice Sep 14 '14 at 00:22
  • from what ive seen position is 1 based at least i assume so because not decrementing companies.size() would throw an exception. and the reason i used the while loop is because i wanted it to iterate through the list using just the if statement would only give me the last item in the list, not sure how else to do it, i was pretty sure it was a hacked together workaround when i did it but couldnt think of another way to iterate through and give me all of the list items and create a tab based on the items retrieved. – Adam Weesner Sep 14 '14 at 00:31
  • "using just the if statement would only give me the last item in the list" How did you come to this conclusion? – Code-Apprentice Sep 14 '14 at 01:23
  • @Code-Apprentice ive updated the code, as you suggested the error does seem to be coming from `getItem()`, alsp `position` is 1-based as an fyi, even with the updated code it still throws the same error any more suggestions? – Adam Weesner Sep 14 '14 at 01:24
  • i used `Log`s the `if` statement would cycle through all of the info in the `List` but would only display the last item across all tabs. – Adam Weesner Sep 14 '14 at 01:27

1 Answers1

2

Your implementation of getItem() looks incredibly suspicious. This may or may not be related to your current error. Let's analyze your current code:

    public Fragment getItem(int position) {
        while (position < companies.size() - 1) {
            if (position < companies.size() - 1) {
                position++;
                return FragmentUserDetails.newInstance(companies.get(position));
            }
        }
        return null;
    }

In order to proceed with this analysis, we need to define the preconditions:

  1. companies contains 5 Strings. The exact values are irrelevant.

  2. position is 0-based with a value of 2.

In this particular situation, both the while and if conditions evaluate to true, so position is incremented and we immediately return the value of newInstance().

This shows something very important: as long as the while condition is true, the if condition is also true and we will immediately return a value. This complete negates the need for a while loop at all.

Now that we see that this implementation is incorrect, let's back up and examine what we want to accomplish. The main idea is that we want to return a Fragment for the "company" at index position. A simplistic implementation is very simple:

    public Fragment getItem(int position) {
        return FragmentUserDetails.newInstance(companies.get(position));
    }

In theory, position should never be outside the range, but if you want to be safe, you can add an if statement for error checking:

    public Fragment getItem(int position) {
        if (0 <= position && position < companies.size()) {
            return FragmentUserDetails.newInstance(companies.get(position));
        }
    }

Now if you are still not getting the expected behavior, the error is somewhere else and we will need to analyze other sections of your code.

Code-Apprentice
  • 81,660
  • 23
  • 145
  • 268
  • ok so your code worked the second option anyway but i guess `position` is zero based and read maybe an empty item and then the item it displayed? because with the `-1` it caused an `IndexOutOfBounds` error i believe it was, it took it out and it worked. thank you! – Adam Weesner Sep 14 '14 at 02:13
  • @AdamWeesner So you don't need to subtract 1 after all. I will edit my answer to reflect this. – Code-Apprentice Sep 14 '14 at 02:44