我有一个由ViewPager组成的Activity。
此ViewPager显示由Grid of Tiles组成的Fragment。由于要显示的片段数量未知,我使用的是FragmentStatePagerAdapter。
问题是这样的:
首次启动时,会正常创建活动,并且所有必需的碎片都会在viewpager中正确显示。
但是当我关闭活动并尝试再次启动它时,我得到了 以下错误:
引起:java.lang.IllegalStateException:Fragment EventGridFragment {162f70f8}当前不在FragmentManager中 在android.app.FragmentManagerImpl.saveFragmentInstanceState(FragmentManager.java:595)
然后应用程序崩溃了。 当我再次启动它时,应用程序正常启动并重复上述循环。
我在博客文章,自我分析和Stack-Overflow中的调查结果表明:
FragmentStatePAgerAdapter中存在错误。
我需要从头开始启动活动/使用启动模式的一些标志
如果有人有这方面的解决方案,请帮助我。 请记住我是这个领域的新手:) 以下是活动代码:
//Lighter Home View and heavy lifting done by presenters
public class HomeActivity extends AppCompatActivity implements HomeView, View.OnClickListener, PlayServicesView {
private static final String TAG = "Home Activity";
private static final String MYEVENTSTAG = "MY";
private static final String TOPEVENTS = "TOP";
private static final String FEATUREDEVENTS = "FEATURED";
private static final String LATESTEVENTS = "LATEST";
private static final String LOCALEVENTS = "LOCAL";
private HomeAdapter mHomeAdapter;
private HomePresenter mHomePresenter;
private static final int REQUEST_ACHIEVEMENTS = 1001;
private static final int REQUEST_LEADERBOARD = 1002;
@InjectView(R.id.activity_home_toolbar)
Toolbar mToolbar;
@InjectView(R.id.activity_events_progress)
ProgressBar mProgressBar;
@InjectView(R.id.activity_home_viewPager)
ViewPager mViewPager;
@InjectView(R.id.pager_header)
PagerSlidingTabStrip mPagerTabStrip;
@InjectView(R.id.drawer_layout)
DrawerLayout mDrawerLayout;
private User mUser;
private PlayServicesPresenter mPlayServicesPresenter;
@InjectView(R.id.imgUserCover)
ImageView mImgUserCover;
@InjectView(R.id.imgUserProfile)
ImageView mImgUserProfilePic;
@InjectView(R.id.txtUserName)
TextView mTxtUserName;
@InjectView(R.id.txtUserEmail)
TextView mTextUserEmail;
@InjectView(R.id.navigation_view)
NavigationView mNavigationView;
GoogleApiClient mGoogleApiClient;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
ButterKnife.inject(this);
setSupportActionBar(mToolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeButtonEnabled(true);
getSupportActionBar().setIcon(R.mipmap.ic_launcher);
getSupportActionBar().setHomeAsUpIndicator(
R.drawable.ic_menu_white_24dp);
mPlayServicesPresenter = new PlayServicesPresenter(this, true);
mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mDrawerLayout.openDrawer(GravityCompat.START);
}
});
if (savedInstanceState == null) {
mHomePresenter = new HomePresenter(this);
} else {
EventCategoriesWrapper eventCategoriesWrapper = (EventCategoriesWrapper) savedInstanceState
.getSerializable("event_categories_wrapper");
mHomePresenter = new HomePresenter(this, eventCategoriesWrapper);
}
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Override
public void onActivityReenter(int resultCode, Intent data) {
super.onActivityReenter(resultCode, data);
Log.d("[DEBUG]", "Home Activity onActivityReenter - Re-enter");
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_home, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
switch (id) {
case R.id.action_settings:
this.startActivity(new Intent(HomeActivity.this, AppSettings.class));
break;
case R.id.action_socialLogin:
this.startActivity(new Intent(HomeActivity.this, SocialLoginActivity.class));
break;
case R.id.action_signout:
if(mGoogleApiClient!=null){
if (mGoogleApiClient.isConnected()) {
Plus.AccountApi.clearDefaultAccount(mGoogleApiClient);
mGoogleApiClient.disconnect();
startActivity(new Intent(HomeActivity.this,Splash.class));
finish();
}
}
break;
}
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
Intent i = new Intent(HomeActivity.this, AppSettings.class);
this.startActivity(i);
}
return super.onOptionsItemSelected(item);
}
@Override
protected void onResume() {
super.onResume();
// Logs 'install' and 'app activate' App Events.
AppEventsLogger.activateApp(this);
}
@Override
protected void onStart() {
super.onStart();
mPlayServicesPresenter.start();
}
@Override
protected void onStop() {
super.onStop();
//Call for login
mHomePresenter.stop();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if (mHomeAdapter != null) {
outState.putSerializable("event_categories_wrapper",
new EventCategoriesWrapper(mHomeAdapter.getEventCategoriesList()));
}
}
@Override
public void showEventCategories(List<EventCategory> eventCategoryList) {
mHomeAdapter = new HomeAdapter(getFragmentManager(), eventCategoryList);
mHomeAdapter.notifyDataSetChanged();
mViewPager.setAdapter(mHomeAdapter);
mPagerTabStrip.setViewPager(mViewPager);
mPagerTabStrip.setIndicatorColor(Color.parseColor(eventCategoryList.get(0).getCatColor()));
mPagerTabStrip.setTextColor(Color.BLACK);
mPagerTabStrip.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int i, float v, int i1) {
}
@Override
public void onPageSelected(int i) {
mPagerTabStrip.setIndicatorColor(Color.parseColor(mHomeAdapter.getEventCategoriesList().get(i).getCatColor()));
mPagerTabStrip.setTextColor(Color.BLACK);
}
@Override
public void onPageScrollStateChanged(int i) {
}
});
}
@Override
public boolean isTheListEmpty() {
return (mHomeAdapter == null) || mHomeAdapter.getEventCategoriesList().isEmpty();
}
@Override
public void appendCategories(List<EventCategory> eventCategoryList) {
}
/**
* Call this method from the presenter when login is complete
*/
@Override
public void onGoogleAuthenticationSuccess(GoogleApiClient googleApiClient) {
//lets load an interstitial
this.mGoogleApiClient = googleApiClient;
mUser = BaseCore.getInstance().getUser();
setupNavDrawer();
loadInterStitialAd();
mHomePresenter.start();
}
private void setupNavDrawer() {
if (mUser != null) {
try {
mTxtUserName.setText(mUser.getUsrName());
if (mUser.getUsrCoverImgURL() != null && !mUser.getUsrCoverImgURL().isEmpty()) {
Picasso.with(getContext()).load(mUser.getUsrCoverImgURL()).fit().into(mImgUserCover);
}
if (mUser.getUsrImgURL() != null && !mUser.getUsrImgURL().isEmpty()) {
Picasso.with(getContext()).load(mUser.getUsrImgURL()).fit().into(mImgUserProfilePic);
}
mTextUserEmail.setText(mUser.getUsrEmail());
} catch (Exception e) {
Log.e(TAG, "Error in setting up nav drawer " + e.getMessage());
}
}
mNavigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(MenuItem menuItem) {
switch (menuItem.getItemId()) {
case R.id.nav_coins:
mDrawerLayout.closeDrawers();
startActivity(new Intent(getContext(), CoinsActivity.class));
break;
case R.id.nav_friends:
mDrawerLayout.closeDrawers();
startActivityForResult(Games.Leaderboards.getLeaderboardIntent(mGoogleApiClient,
getResources()
.getString(R.string.leaderboard_1)), REQUEST_LEADERBOARD);
break;
case R.id.nav_achievements:
mDrawerLayout.closeDrawers();
//startActivity(new Intent(this.getActivity(), AchievementsActivity.class));
startActivityForResult(Games.Achievements.getAchievementsIntent(mGoogleApiClient), REQUEST_ACHIEVEMENTS);
break;
case R.id.nav_notifications:
mDrawerLayout.closeDrawers();
startActivity(new Intent(getContext(), NotificationsActivity.class));
break;
case R.id.nav_localEvents:
mDrawerLayout.closeDrawers();
Intent intentL = new Intent(getContext(), FilterEventsActivity.class);
intentL.putExtra("tag", LOCALEVENTS);
startActivity(intentL);
// finish();
break;
case R.id.nav_topEvents:
mDrawerLayout.closeDrawers();
Intent intentT = new Intent(getContext(), FilterEventsActivity.class);
intentT.putExtra("tag", TOPEVENTS);
startActivity(intentT);
// finish();
break;
case R.id.nav_myEvents:
mDrawerLayout.closeDrawers();
Intent intentM = new Intent(getContext(), FilterEventsActivity.class);
intentM.putExtra("tag", MYEVENTSTAG);
startActivity(intentM);
// finish();
break;
case R.id.nav_latestEvents:
mDrawerLayout.closeDrawers();
Intent intentLA = new Intent(getContext(), FilterEventsActivity.class);
intentLA.putExtra("tag", LATESTEVENTS);
startActivity(intentLA);
// finish();
break;
case R.id.nav_featuredEvents:
mDrawerLayout.closeDrawers();
Intent intentF = new Intent(getContext(), FilterEventsActivity.class);
intentF.putExtra("tag", FEATUREDEVENTS);
startActivity(intentF);
// finish();
break;
default:
return true;
}
return true;
}
});
}
public void loadInterStitialAd() {
/*if(!GameCore.getInstance().isInterstitialLoaded()){
GameCore.getInstance().setYoutubevideoId("cEurW7CBzZE");
startActivity(new Intent(HomeActivity.this, YoutubeIntersitial.class));
}else{
GameCore.getInstance().setInterstitialLoaded(false);
}*/
}
/**
* Call this method from the presenter when login fails
*/
@Override
public void onGoogleAuthenticationFailure() {
}
@Override
public Context getContext() {
return this;
}
@Override
public void loadYouTubeAd(String videoId) {
}
/**
* Called when a view has been clicked.
*
* @param v The view that was clicked.
*/
@Override
public void onClick(View v) {
}
@Override
protected void onPause() {
super.onPause();
// Logs 'app deactivate' App Event.
AppEventsLogger.deactivateApp(this);
BaseCore.getInstance().persistInDb();
}
@Override
protected void onActivityResult(int requestCode, int responseCode, Intent intent) {
super.onActivityResult(requestCode, responseCode, intent);
if (requestCode == mPlayServicesPresenter.getRcSignIn()) {
Log.d(TAG, "onActivityResult with requestCode == RC_SIGN_IN, responseCode="
+ responseCode + ", intent=" + intent);
mPlayServicesPresenter.setmSignInClicked(false);
mPlayServicesPresenter.setmResolvingConnectionFailure(false);
if (responseCode == RESULT_OK) {
mPlayServicesPresenter.start();
} else {
BaseGameUtils.showActivityResultError(this, requestCode, responseCode, R.string.signin_other_error);
}
}
}
}
'showEventCategories'方法为活动设置适配器和viewpager。
以下是适配器的代码:
import android.app.Fragment;
import android.app.FragmentManager;
import android.os.Bundle;
import android.support.v13.app.FragmentStatePagerAdapter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.steigensoft.android.bt_client.R;
import com.steigensoft.android.bt_client.views.fragments.EventGridFragment;
import com.steigensoft.android.model.entities.EventCategory;
import java.util.List;
/**
* Created by rajiv on 07-04-2015.
*/
public class HomeAdapter extends FragmentStatePagerAdapter {
private List<EventCategory> mEventCategoryList;
public HomeAdapter(FragmentManager fm) {
super(fm);
}
public HomeAdapter(FragmentManager fm, List<EventCategory> eventCategoryList) {
super(fm);
this.mEventCategoryList = eventCategoryList;
}
/**
* Return the Fragment associated with a specified position.
*
* @param position
*/
@Override
public Fragment getItem(int position) {
return EventGridFragment.newInstance(mEventCategoryList.get(position).getCatId(),mEventCategoryList.get(position).getCatColor());
}
@Override
public CharSequence getPageTitle(int position) {
return mEventCategoryList.get(position).getCatName();
//return Titles[position];
}
/**
* Return the number of views available.
*/
@Override
public int getCount() {
//Log.i("GETTING COUNT ", String.valueOf(mEventCategoryList.size()));
if(mEventCategoryList!=null){
return mEventCategoryList.size();
}else return 0;
}
public List<EventCategory> getEventCategoriesList() {
return mEventCategoryList;
}
}
以下是Fragment的代码:
import android.app.Fragment;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.ProgressBar;
import com.steigensoft.android.bt_client.R;
import com.steigensoft.android.bt_client.mvp.presenters.EventGridPresenter;
import com.steigensoft.android.bt_client.mvp.views.EventGridView;
import com.steigensoft.android.bt_client.utils.RecyclerInsetsDecoration;
import com.steigensoft.android.bt_client.utils.RecyclerViewClickListener;
import com.steigensoft.android.bt_client.views.activities.EventDetailsActivity;
import com.steigensoft.android.bt_client.views.adapters.EventGridAdapter;
import com.steigensoft.android.model.entities.Event;
import com.steigensoft.android.model.entities.EventsWrapper;
import java.util.List;
import butterknife.ButterKnife;
import butterknife.InjectView;
/**
* A simple {@link Fragment} subclass.
* Activities that contain this fragment must implement the
* {@link EventGridFragment.OnFragmentInteractionListener} interface
* to handle interaction events.
* Use the {@link EventGridFragment#newInstance} factory method to
* create an instance of this fragment.
*/
public class EventGridFragment extends Fragment implements EventGridView, RecyclerViewClickListener,View.OnClickListener {
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_CAT_ID = "catId";
private static final String ARG_CAT_COLOR = "catColor";
private Long mCatId;
private String mCatColor;
private EventGridAdapter mEventGridAdapter;
private EventGridPresenter mEventPresenter;
private GridLayoutManager mGridLayoutManager;
public float mBackgroundTranslation;
int pastVisiblesItems, visibleItemCount, totalItemCount;
@InjectView(R.id.fragment_event_grid_progress)
ProgressBar mProgressBar;
@InjectView(R.id.fragment_event_grid_recycler)
RecyclerView mRecyclerView;
private ImageView mCoverImage;
private OnFragmentInteractionListener mListener;
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* @param catId Parameter 1
* @return A new instance of fragment EventGrid.
*/
// TODO: Rename and change types and number of parameters
public static EventGridFragment newInstance(Long catId,String catColor) {
EventGridFragment fragment = new EventGridFragment();
Bundle args = new Bundle();
args.putLong(ARG_CAT_ID, catId);
args.putString(ARG_CAT_COLOR,catColor);
fragment.setArguments(args);
return fragment;
}
public EventGridFragment() {
// Required empty public constructor
}
@Override
public void onCreate(Bundle savedInstanceState) {
//Todo investigate more on lifecycle of a fragment, whether onCreate is better or OnCreateView
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View fragmentEvent = inflater.inflate(R.layout.fragment_event_grid, container, false);
ButterKnife.inject(this, fragmentEvent);
// mRecyclerView.setLayoutManager(new GridLayoutManager(fragmentEvent.getContext(),));
mRecyclerView.addItemDecoration(new RecyclerInsetsDecoration(this.getContext()));
//mRecyclerView.setOnScrollListener(recyclerScrollListener);
if (getArguments() != null) {
mCatId = getArguments().getLong(ARG_CAT_ID);
mCatColor = getArguments().getString(ARG_CAT_COLOR);
}
if (savedInstanceState == null) {
mEventPresenter = new EventGridPresenter(this);
} else {
EventsWrapper eventsWrapper = (EventsWrapper) savedInstanceState.getSerializable("events_wrapper" + mCatId);
mEventPresenter = new EventGridPresenter(this,eventsWrapper);
}
return fragmentEvent;
}
/* //Todo : Need to take a deeper look into Attach/Detach events
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mListener = (OnFragmentInteractionListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement OnFragmentInteractionListener");
}
}
@Override
public void onDetach() {
super.onDetach();
mListener = null;
}*/
@Override
public void onStart(){
super.onStart();
mEventPresenter.start(mCatId);
}
@Override
public void onStop(){
super.onStop();
mEventPresenter.stop();
}
@Override
public void showEvents(List<Event> eventList) {
mEventGridAdapter = new EventGridAdapter(eventList);
mEventGridAdapter.setRecyclerListListener(this);
mRecyclerView.setAdapter(mEventGridAdapter);
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if (mEventGridAdapter != null) {
outState.putSerializable("events_wrapper" + mCatId,
new EventsWrapper(mEventGridAdapter.getEventList()));
}
}
@Override
public void showLoading() {
mProgressBar.setVisibility(View.VISIBLE);
}
@Override
public void hideLoading() {
mProgressBar.setVisibility(View.GONE);
}
@Override
public void showError(String error) {
//TODO
}
@Override
public void hideError() {
}
@Override
public void showLoadingLabel() {
}
@Override
public void hideActionLabel() {
}
@Override
public boolean isTheListEmpty() {
return (mEventGridAdapter == null) || mEventGridAdapter.getEventList().isEmpty();
}
@Override
public void appendEvents(List<Event> eventList) {
//TODO when we will be invoking paging system
}
@Override
public Context getContext() {
return this.getActivity();
}
@Override
public void loadYouTubeAd(String videoId) {
}
@Override
public void onClick(View v, int position, float x, float y) {
Intent eventDetailActivityIntent = new Intent (
getContext(), EventDetailsActivity.class);
//TODO : Put some nice transition effects here later
eventDetailActivityIntent.putExtra("event_obj", mEventGridAdapter.getEventList().get(position));
eventDetailActivityIntent.putExtra("event_color",mCatColor );
startActivity(eventDetailActivityIntent);
}
@Override
public void onClick(View v) {
}
/**
* This interface must be implemented by activities that contain this
* fragment to allow an interaction in this fragment to be communicated
* to the activity and potentially other fragments contained in that
* activity.
* <p>
* See the Android Training lesson <a href=
* "http://developer.android.com/training/basics/fragments/communicating.html"
* >Communicating with Other Fragments</a> for more information.
*/
public interface OnFragmentInteractionListener {
// TODO: Update argument type and name
public void onFragmentInteraction(Uri uri);
}
}
错误:
Caused by: java.lang.IllegalStateException: Fragment EventGridFragment{2fbf162b} is not currently in the FragmentManager
at android.app.FragmentManagerImpl.saveFragmentInstanceState(FragmentManager.java:595)
at android.support.v13.app.FragmentStatePagerAdapter.destroyItem(FragmentStatePagerAdapter.java:140)
at android.support.v4.view.ViewPager.setAdapter(ViewPager.java:417)
at com.steigensoft.android.bt_client.views.activities.HomeActivity.showEventCategories(HomeActivity.java:214)
at com.steigensoft.android.bt_client.mvp.presenters.HomePresenter.onAllEventsReceived(HomePresenter.java:61)