我最近将ViewPager的适配器从FragmentPagerAdapter切换到FragmentStatePagerAdapter。但是,每当我返回ViewPager时,应用程序就会崩溃。使用FragmentPagerAdapter不会发生这种情况。 Logcat显示:
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Object android.util.SparseArray.get(int)' on a null object reference
我处于那种尴尬的境地,我对所要问的问题了解不足。我所有的搜索都没有用。
Logcat
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Object android.util.SparseArray.get(int)' on a null object reference
at android.support.v4.app.FragmentManagerImpl.getFragment(FragmentManager.java:905)
at android.support.v4.app.FragmentStatePagerAdapter.restoreState(FragmentStatePagerAdapter.java:216)
at android.support.v4.view.ViewPager.onRestoreInstanceState(ViewPager.java:1455)
at android.view.View.dispatchRestoreInstanceState(View.java:17706)
at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:3745)
at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:3751)
at android.view.View.restoreHierarchyState(View.java:17684)
at android.support.v4.app.Fragment.restoreViewState(Fragment.java:415)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1454)
at android.support.v4.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1759)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1827)
at android.support.v4.app.BackStackRecord.executeOps(BackStackRecord.java:797)
at android.support.v4.app.FragmentManagerImpl.executeOps(FragmentManager.java:2596)
at android.support.v4.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2383)
at android.support.v4.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManager.java:2338)
at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:2245)
at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:703)
at android.os.Handler.handleCallback(Handler.java:790)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6494)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
MainActivity.java
public class MainActivity extends AppCompatActivity
implements FragmentQuiz_Selection_Instruments.QuizSelectionInterface,
FragmentQuiz_Started.OnQuizExit,
FragmentQuiz_Selection_Topics.StartQuizInterface {
private DrawerLayout mDrawerLayout;
private Fragment mQuizFragment;
private Fragment mInstrumentsFragment;
private Fragment mReferenceFragment;
private ArrayList<String> mQuizSelection;
private ViewModel_ForegroundView viewModel;
private BottomNavigationView bottomNavigationView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Initialise mQuizSelection
mQuizSelection = new ArrayList<String>();
mQuizSelection.clear();
//Initialise bottomNavigationView
bottomNavigationView = findViewById(R.id.navigation_bottom);
//Set Bottom-Navigation icon
bottomNavigationView.getMenu().getItem(1).setChecked(true);
//Initialise ViewModel_ForegroundView
viewModel = ViewModelProviders.of(this).get(ViewModel_ForegroundView.class);
//Initialise ActionBar
final Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
ActionBar actionBar = getSupportActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setHomeAsUpIndicator(R.drawable.ic_menu);
//Initialise Top-Navigation Drawer
mDrawerLayout = findViewById(R.id.drawer_layout);
NavigationView navigationView = findViewById(R.id.navigation_top);
// Set the onClickListener for the NavigationDrawer
navigationView.setNavigationItemSelectedListener(
new NavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
// set item as selected to persist highlight
item.setChecked(true);
// close drawer when item is tapped
mDrawerLayout.closeDrawers();
// Handle item clicks
int itemId = item.getItemId();
if (itemId == R.id.nav_top_ww) {
Fragment fragment = getSupportFragmentManager().findFragmentByTag("FragmentInstruments_WWind");
if (fragment == null) {
mInstrumentsFragment = FragmentInstruments_WWind.newInstance();
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.add(mInstrumentsFragment, "FragmentInstruments_WWind");
fragmentTransaction.commit();
} else {
mInstrumentsFragment = fragment;
}
} else if (itemId == R.id.nav_top_br) {
Fragment fragment = getSupportFragmentManager().findFragmentByTag("FragmentInstruments_Brass");
if (fragment == null) {
mInstrumentsFragment = FragmentInstruments_Brass.newInstance();
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.add(mInstrumentsFragment, "FragmentInstruments_Brass");
fragmentTransaction.commit();
} else {
mInstrumentsFragment = fragment;
}
} else if (itemId == R.id.nav_top_pp) {
Fragment fragment = getSupportFragmentManager().findFragmentByTag("FragmentInstruments_PercPit");
if (fragment == null) {
mInstrumentsFragment = FragmentInstruments_PercPit.newInstance();
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.add(mInstrumentsFragment, "FragmentInstruments_PercPit");
fragmentTransaction.commit();
} else {
mInstrumentsFragment = fragment;
}
} else if (itemId == R.id.nav_top_pu) {
Fragment fragment = getSupportFragmentManager().findFragmentByTag("FragmentInstruments_PercUnp");
if (fragment == null) {
mInstrumentsFragment = FragmentInstruments_PercUnp.newInstance();
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.add(mInstrumentsFragment, "FragmentInstruments_PercUnp");
fragmentTransaction.commit();
} else {
mInstrumentsFragment = fragment;
}
} else if (itemId == R.id.nav_top_sp) {
Fragment fragment = getSupportFragmentManager().findFragmentByTag("FragmentInstruments_StrPlu");
if (fragment == null) {
mInstrumentsFragment = FragmentInstruments_StrPlu.newInstance();
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.add(mInstrumentsFragment, "FragmentInstruments_StrPlu");
fragmentTransaction.commit();
} else {
mInstrumentsFragment = fragment;
}
} else if (itemId == R.id.nav_top_ky) {
Fragment fragment = getSupportFragmentManager().findFragmentByTag("FragmentInstruments_Keys");
if (fragment == null) {
mInstrumentsFragment = FragmentInstruments_Keys.newInstance();
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.add(mInstrumentsFragment, "FragmentInstruments_Keys");
fragmentTransaction.commit();
} else {
mInstrumentsFragment = fragment;
}
} else if (itemId == R.id.nav_top_sb) {
Fragment fragment = getSupportFragmentManager().findFragmentByTag("FragmentInstruments_StrBow");
if (fragment == null) {
mInstrumentsFragment = FragmentInstruments_StrBow.newInstance();
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.add(mInstrumentsFragment, "FragmentInstruments_StrBow");
fragmentTransaction.commit();
} else {
mInstrumentsFragment = fragment;
}
}
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.frame_layout, mInstrumentsFragment);
transaction.commit();
//Record foreground-fragment change
viewModel.recordForegroundFragment(mInstrumentsFragment);
//Set 'Quiz Exit' button's visibility to 'false,' set Quiz-Ext button.
viewModel.recordQuizBtnStatus(false);
setQuizExtBtn();
return true;
}
});
mDrawerLayout.addDrawerListener(
new DrawerLayout.DrawerListener() {
@Override
public void onDrawerSlide(View drawerView, float slideOffset) {
// Respond when the drawer's position changes
}
@Override
public void onDrawerOpened(View drawerView) {
// Respond when the drawer is opened
drawerView.bringToFront();
}
@Override
public void onDrawerClosed(View drawerView) {
// Respond when the drawer is closed
}
@Override
public void onDrawerStateChanged(int newState) {
// Respond when the drawer motion state changes
}});
// Bottom-Navigation Menu
bottomNavigationView.setOnNavigationItemSelectedListener(
new BottomNavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
int itemId = item.getItemId();
if (itemId == R.id.nav_btm_quiz) {
if (mQuizFragment != null) {
String string = mQuizFragment.toString();
if (string.contains("Started") || string.contains("Topics")) {
viewModel.recordQuizBtnStatus(true);
}
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.frame_layout, mQuizFragment);
fragmentTransaction.commit();
//Record foreground-fragment change
viewModel.recordForegroundFragment(mQuizFragment);
} else {
Fragment fragment = getSupportFragmentManager().findFragmentByTag("FragmentQuiz_Selection_Instruments");
if (fragment == null) {
mQuizFragment = FragmentQuiz_Selection_Instruments.newInstance();
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.frame_layout, mQuizFragment, "FragmentQuiz_Selection_Instruments");
fragmentTransaction.commit();
viewModel.recordForegroundFragment(mQuizFragment);
} else {
mQuizFragment = fragment;
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.frame_layout, mQuizFragment);
fragmentTransaction.commit();
viewModel.recordForegroundFragment(mQuizFragment);
}
}
} else if (itemId == R.id.nav_btm_instruments) {
viewModel.recordQuizBtnStatus(false);
if (mInstrumentsFragment != null) {
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.frame_layout, mInstrumentsFragment);
fragmentTransaction.commit();
viewModel.recordForegroundFragment(mInstrumentsFragment);
} else {
Fragment fragment = getSupportFragmentManager().findFragmentByTag("FragmentInstruments_WWind");
if (fragment == null) {
mQuizFragment = FragmentInstruments_WWind.newInstance();
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.add(R.id.frame_layout, mQuizFragment, "FragmentInstruments_WWind");
fragmentTransaction.commit();
} else {
mQuizFragment = fragment;
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.frame_layout, fragment);
fragmentTransaction.commit();
}
}
} else if (itemId == R.id.nav_btm_reference) {
viewModel.recordQuizBtnStatus(false);
if (mReferenceFragment != null) {
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.frame_layout, mReferenceFragment);
fragmentTransaction.commit();
} else {
mReferenceFragment = FragmentReference.newInstance();
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.frame_layout, mReferenceFragment, "FragmentReference");
fragmentTransaction.commit();
}
}
//Set Quiz-Ext button's visibility.
setQuizExtBtn();
//Call 'invalidateOptionsMenu' to set the Quiz-Exit button's visibility.
invalidateOptionsMenu();
return true;
}
});
}
@Override
protected void onStart() {
super.onStart();
}
@Override
protected void onResume() {
super.onResume();
/**Display FragmentInstruments_WWind when opening the app for the first time.
* If the app is being resumed, use getForegroundFragment.
*/
if (viewModel.getForegroundFragment() == null) {
Fragment fragment = getSupportFragmentManager().findFragmentByTag("FragmentInstruments_WWind");
if (fragment == null) {
mInstrumentsFragment = FragmentInstruments_WWind.newInstance();
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.add(mInstrumentsFragment, "FragmentInstruments_WWind");
fragmentTransaction.commit();
} else {
mInstrumentsFragment = fragment;
}
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.frame_layout, mInstrumentsFragment);
transaction.commit();
//Record foreground-fragment change
viewModel.recordForegroundFragment(mInstrumentsFragment);
//Set Quiz-Exit Status
viewModel.recordQuizBtnStatus(false);
//Set 'Reference' icon as checked
bottomNavigationView.getMenu().getItem(1).setChecked(true);
} else if (viewModel.getForegroundFragment() != null) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
Fragment foregroundFragment = viewModel.getForegroundFragment();
transaction.replace(R.id.frame_layout, foregroundFragment);
transaction.commit();
//Record foreground-fragment change, set bottom-navigation icon
viewModel.recordForegroundFragment(foregroundFragment);
String fragment = foregroundFragment.toString();
if (fragment.contains("Quiz")) {
bottomNavigationView.getMenu().getItem(0).setChecked(true);
} else if (fragment.contains("Reference")) {
bottomNavigationView.getMenu().getItem(1).setChecked(true);
} else if (fragment.contains("Help")) {
bottomNavigationView.getMenu().getItem(2).setChecked(true);
}
}
}
@Override
protected void onPause(){
super.onPause();
//Actions onPause
viewModel.recordInstrumentsFragment(mInstrumentsFragment);
}
//Search function handled here
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the options menu from XML
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.action_bar, menu);
//Set 'Quiz Exit' button's visibility.
boolean status = viewModel.getQuizBtnStatus();
menu.findItem(R.id.ab_quiz_exit).setVisible(status);
return true;
}
//Handle action-bar button clicks
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
mDrawerLayout.openDrawer(GravityCompat.START);
return true;
case R.id.ab_quiz_exit:
onQuizExit();
}
return super.onOptionsItemSelected(item);
}
父片段
public class FragmentInstruments_Brass extends Fragment {
public static FragmentInstruments_Brass newInstance() {
FragmentInstruments_Brass fragment = new FragmentInstruments_Brass();
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Fragment screen orientation normal both portrait and landscape
getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_instruments, container, false);
//Setting ViewPager for each tab
ViewPager viewPager = view.findViewById(R.id.viewPager_instruments);
tabsToViewPager(viewPager);
//Set tabs inside toolbar
TabLayout tabLayout = view.findViewById(R.id.tabLayout_instruments);
tabLayout.setupWithViewPager(viewPager, false);
return view;
}
//Add Fragments to Tabs
private void tabsToViewPager(ViewPager viewPager) {
Adapter adapter = new Adapter(getChildFragmentManager());
//Brass Fragments
adapter.addFragment(new Inst_Br_Frag1(), "Name1");
adapter.addFragment(new Inst_Br_Frag2(), "Name2");
adapter.addFragment(new Inst_Br_Frag3(), "Name3");
adapter.addFragment(new Inst_Br_Frag4(), "Name4");
adapter.addFragment(new Inst_Br_Frag5(), "Name5");
adapter.addFragment(new Inst_Br_Frag6(), "Name6");
viewPager.setAdapter(adapter);
}
static class Adapter extends FragmentStatePagerAdapter {
//mFragmentList stores ChildFragments
private final List<Fragment> mFragmentList = new ArrayList<>();
//mFragmentTitleList stores the displayed name of each ChildFragment
private final List<String> mFragmentTitleList = new ArrayList<>();
Adapter(FragmentManager manager) {
super(manager);
}
// Return the Fragment associated with a specified position
@Override
public Fragment getItem(int position) {
return mFragmentList.get(position);
}
// getCount() returns the number of views available
@Override
public int getCount() {
return mFragmentList.size();
}
void addFragment(Fragment fragment, String title) {
mFragmentList.add(fragment);
mFragmentTitleList.add(title);
}
//This method may be called by the ViewPager to obtain a title string to describe the specified page.
@Override
public CharSequence getPageTitle(int position) {
return mFragmentTitleList.get(position);
}
}
}