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
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:
companies
contains 5 String
s. The exact values are irrelevant.
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.