0

i'm facing an issue i can't seem to resolve and i'd like some help.

My app is composed by an activity containing a fragment. After the user taps on a suggestion, activity's method onSuggestionClicked(String cardId) is called and activity's content is replaced with a new PagerFragment_new.

 @Override
public void onSuggestionClicked(String cardId) {

    Log.d("activity","ID:\t" + cardId);


    PagerFragment_new pagerFragment = PagerFragment_new.getInstance(
            Injection.provideMtgDatabase(getApplicationContext()),
            activityPresenter.getAllCardExpansionIds(cardId),
            this);
    ActivityUtils.replaceFragment(getSupportFragmentManager(), pagerFragment, R.id.MTGRecallActivity_container);
}

PagerFragment_new contains a ViewPager to display CardInfoFragment_new

public class PagerFragment_new extends MtgRecallFragment_new implements PagerFragmentContract.View {

private View fragmentView;
private ViewPager viewPager;
private PagerFragmentContract.Presenter presenter;
private ScreenSlidePageAdapter_new adapter;
private MtgDatabase database;
private String[] printingsIds;
private ScreenSlidePageAdapter_new.ActivePresenterListener listener;

public PagerFragment_new() {
    //Required empty constructor
}

public static PagerFragment_new getInstance(MtgDatabase database, String[] printingsIds, ScreenSlidePageAdapter_new.ActivePresenterListener listener) {
    PagerFragment_new instance = new PagerFragment_new();
    instance.setDatabase(database);
    instance.setPrintingsIds(printingsIds);
    instance.listener = listener;
    return instance;
}

//other stuff

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    setRetainInstance(true);
    super.onCreate(savedInstanceState);
}

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    setHasOptionsMenu(true);
    fragmentView = inflater.inflate(R.layout.fragment_pager, container, false);
    viewPager = (ViewPager) fragmentView.findViewById(R.id.PAGERFRAG_VIEWPAGER);
    adapter = new ScreenSlidePageAdapter_new(getChildFragmentManager(), printingsIds, database, viewPager);
    adapter.setListener(listener);
    viewPager.setAdapter(adapter);
    viewPager.setOffscreenPageLimit(1);
    return fragmentView;
}

@Override
public void setPresenter(PagerFragmentContract.Presenter presenter) {
    this.presenter = presenter;
}
}

The adapter to manage ViewPager's element's is ScreenSlidePageAdapter_new, it is responsible of instantiating CardInfoFragments.

public class ScreenSlidePageAdapter_new extends FragmentStatePagerAdapter {

private String[] printingsIds;
private String firstItemId;
private MtgDatabase database;
public ActivePresenterListener activity;
private ViewPager viewPager;

public ScreenSlidePageAdapter_new(FragmentManager fm, String[] printingsIds, MtgDatabase database, ViewPager viewPager) {
    super(fm);
    this.printingsIds =printingsIds;
    this.database = database;
    this.firstItemId = printingsIds[0];
    this.viewPager = viewPager;
}

@Override
public Fragment getItem(int position) {
    //todo create a bundle with cardId
    Bundle bundle = new Bundle();
    bundle.putString("CardID", printingsIds[position]);
    bundle.putString("FirstItemId", firstItemId);
    CardInfoFragment_new cardInfoFragment_new = CardInfoFragment_new.getInstance(viewPager);
    cardInfoFragment_new.setArguments(bundle);
    CardInfoPresenter cardInfoPresenter = new CardInfoPresenter(cardInfoFragment_new, database);
    activity.setActivePresenter(cardInfoPresenter);
    return cardInfoFragment_new;
}

@Override
public void destroyItem(ViewGroup container, int position, Object object) {
    super.destroyItem(container, position, object);

}

public void setListener(ActivePresenterListener listener) {
    this.activity = listener;
}
@Override
public int getCount() {
    return printingsIds.length;
}

public interface ActivePresenterListener {

    void setActivePresenter(BasePresenter presenter);
}}

Finally, here's the code of CardInfoFragment:

public class CardInfoFragment_new extends MtgRecallFragment_new
    implements CardInfoContract.View,
    CardPrintingsAdapter.OnItemClickListener {

private ViewPager viewPager;

public CardInfoContract.Presenter presenter;
private View fragmentView;
private MTGCard mtgCard;
RecyclerView printingsRecyclerView;

CardPrintingsAdapter cardPrintingsAdapter;


private String firstItemId; //the first id 




public CardInfoFragment_new() {
    //required empty constructor
}

private void setViewPager(ViewPager viewPager) {
    this.viewPager = viewPager;
}

public static CardInfoFragment_new getInstance(ViewPager viewPager) {
    CardInfoFragment_new cardInfoFragment_new = new CardInfoFragment_new();
    cardInfoFragment_new.setViewPager(viewPager);
    return cardInfoFragment_new;
}

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    setRetainInstance(true);
    presenter.start();
    String cardId = getArguments().getString("CardID");
    firstItemId = getArguments().getString("FirstItemId");
    mtgCard = presenter.getCardData(cardId);
    super.onCreate(savedInstanceState);
}

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    fragmentView = inflater.inflate(R.layout.fragment_card_info_new, container, false);
    setUpCardInfoView(fragmentView);
    return fragmentView;
}

public void setUpCardInfoView(final View view){
//others view set-up action omitted



    cardprintingsContainer =  (LinearLayout) view.findViewById(R.id.CARDINFO_printingsContainer);
    printingsRecyclerView = (RecyclerView)fragmentView.findViewById(R.id.CARDINFO_printings_recyclerView);
    final List<String> printings = presenter.getCardPrintings(firstItemId, mtgCard.getName());
    if (printings.size() < 40) {
        setupPrintings(printings,printingsRecyclerView);
    }
    else {
        LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        LinearLayout printingsRow = new LinearLayout(getContext());
        printingsRow = (LinearLayout)inflater.inflate(R.layout.card_info_printings_row,printingsRow,true);
        printingsRow.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                setupPrintings(printings, printingsRecyclerView);
            }
        });
        ImageView printingssetImage = (ImageView)printingsRow.findViewById(R.id.CARDINFO_printingsRow_setImage);

        printingssetImage.setVisibility(View.INVISIBLE);
        TextView printingssetName = (TextView)printingsRow.findViewById(R.id.CARDINFO_printingsRow_setName);

        printingssetName.setText("Click to see all the "+printings.size()+ " versions");
        cardprintingsContainer.addView(printingsRow);
    }
}

public void setupPrintings(List<String> printings, RecyclerView recyclerView) {
    cardPrintingsAdapter =
            new CardPrintingsAdapter(getContext(), printings);
    cardPrintingsAdapter.setOnItemClickListener(this);
    UnscrollableLayoutManager layoutManager = new UnscrollableLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false);
    recyclerView.setAdapter(cardPrintingsAdapter);
    recyclerView.setLayoutManager(layoutManager);
}

@Override
public void onItemClick(View itemView, int position) {
    int i = viewPager.getAdapter().getCount();

    viewPager.setCurrentItem(position);
}



@Override
public void onDestroy() {
    presenter = null;
    mtgCard = null;
    super.onDestroy();
}}

When user click on a RecyclerView item, CardInfoFragment's method onItemClick(View itemView, int position) is called and the viewpager is set to current position. Everything as expected.

THE PROBLEM

When the orientation changes, fragments are able to retain their states, but viewPager.setCurrentItem(position) does nothing, and i'm not able to change displayed fragment.

I already checked:

  • ViewPager instance and adapters instances corresponds to those passed to Fragments
  • onItemClick is fired
  • this questions question1 question2

If i use

android:configChanges="orientation|screenSize"

in manifest it works even after config changes, but i don't want to use this option since is discouraged. Thanks in advance!

Community
  • 1
  • 1
Mick Hardins
  • 25
  • 1
  • 9

1 Answers1

0

By default, when certain key configuration changes happen on Android (a common example is an orientation change), Android fully restarts the running Activity to help it adjust to such changes.

When you define android:configChanges="keyboardHidden|orientation" in your AndroidManifest, you are telling Android: "Please don't do the default reset when the keyboard is pulled out, or the phone is rotated; I want to handle this myself. Yes, I know what I'm doing".

So use configChanges. The use of this is discouraged, IF you don't know how to use it. But for a case like this, I would suggest you use it. IF not, still the activity will be recreated. which just takes time, resources, and I don't see why you would want that to happen.

rosu alin
  • 5,674
  • 11
  • 69
  • 150
  • i see your point: some times is preferable to retain the state and don't waste resources in recreating everything, but in my case, leaving behind resources considerations i can't figure out why things aren't working as expected. – Mick Hardins May 18 '17 at 13:49