Android - Save/restore state with FragmentStatePageAdapter - java

I made this class:
public class My_ViewPagerAdapter extends FragmentStatePagerAdapter {
private ArrayList<My_Fragment> fragments=new ArrayList<>();
private ArrayList<String> tabTitles=new ArrayList<>();
public My_ViewPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
return fragments.get(position);
}
#Override
public int getItemPosition(Object object) {
for (int i=0;i<fragments.size();i++){
Class<? extends My_Fragment> clazz= fragments.get(i).getClass();
if (clazz.isInstance(object)){
return i;
}
}
return POSITION_NONE;
}
#Override
public int getCount() {
return fragments.size();
}
public void addFragment(My_Fragment fragment, String tabTitle){
fragments.add(fragment);
tabTitles.add(tabTitle);
notifyDataSetChanged();
}
public void removeFragment(int position){
fragments.remove(position);
tabTitles.remove(position);
notifyDataSetChanged();
}
public My_Fragment getFragmentAtTab(int position){
return fragments.get(position);
}
#Override
public CharSequence getPageTitle(int position) {
return tabTitles.get(position);
}
}
I'm adding/removing fragments/tabs dynamically, and i want to save their state through configuration changes.
I implemented onSaveInstanceState():
int tabs=tabLayout.getTabCount();
for (int i=0;i<tabs;i++){
outState.putInt("TabsCount",tabs);
outState.putString("Tab_"+i,getTabTitle(i));
outState.putString("FragmentClassAtTab_"+i,my_viewPagerAdapter.getFragmentAtTab(i).getClass().getName());
}
and i implemented onRestoreInstanceState():
for (int i=0;i<tabs;i++){
try {
My_Fragment fragment= (My_Fragment) Class.forName(savedInstanceState.getString("FragmentClassAtTab_"+i)).newInstance();
addTab(fragment ,savedInstanceState.getString("Tab_"+i));
}
catch (ClassNotFoundException e) {
e.printStackTrace();
}
catch (InstantiationException e) {
e.printStackTrace();
}
catch (IllegalAccessException e) {
e.printStackTrace();
}
}
addTab method is:
public void addTab(My_Fragment fragment, String title){
if (fragment!=null) my_viewPagerAdapter.addFragment(fragment,title);
tabLayout.addTab(tabLayout.newTab().setText(title));
}
THE PROBLEM:
Every fragment i add gets recreated "automatically" when configuration change occurs, so its constructor gets called everytime. onCreateView gets called on these instances and not on the ones recreated by my code.
I need onCreateView to get called on fragments instantiated in my tabs in order to set their listviews.
Fragments created "automatically" get replaced by new fragment instances through my onRestoreInstanceState method, but no onCreateView method gets called on these new instances.
I think i'm doing it wrong and maybe there is a better way to save tabs and fragments throught configuration changes... Any help is appreciated.

I once created something similar, which in my case looked like this:
public class DisplayPagerAdapter extends FragmentStatePagerAdapter {
private static final String TAG = "DisplayPagerAdapter";
SparseArray<DisplayFragment> registeredFragments = new SparseArray<DisplayFragment>();
private final Context context;
private final DisplayCoreModule display;
private final FragmentManager fm;
private boolean isAddOrRemoving;
public DisplayPagerAdapter(Context context, FragmentManager fm,
DisplayCoreModule display) {
super(fm);
this.context = context;
this.display = display;
this.fm = fm;
Log.d(TAG, "pages " + display.getPagesCount());
}
public void notifySizeChangingDataSetChange() {
isAddOrRemoving = true;
notifyDataSetChanged();
isAddOrRemoving = false;
}
#Override
public int getCount() {
int count = (display != null && display.getPagesCount() > 0) ? display
.getPagesCount() : 1;
return count;
}
#Override
public int getItemPosition(Object object) {
DisplayFragment frag = (DisplayFragment) object;
if (!display.containsPageId(frag.getPageId())) {
// this will update the 'no information' page with id -1
return POSITION_NONE;
}
if (isAddOrRemoving) {
// recreate all for simplicity
return POSITION_NONE;
}
return POSITION_UNCHANGED;
}
#Override
public Fragment getItem(int position) {
Log.d(TAG, "getItem " + position);
return DisplayFragment.newInstance(position);
}
#Override
public CharSequence getPageTitle(int position) {
if (display != null && display.getPagesCount() > 0) {
return context.getString(R.string.page) + " " + (position + 1);
} else {
return super.getPageTitle(position);
}
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
Log.d(TAG, "instantiateItem " + position);
DisplayFragment fragment = (DisplayFragment) super.instantiateItem(
container, position);
registeredFragments.put(position, fragment);
return fragment;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
Log.d(TAG, "destroyItem " + position);
registeredFragments.remove(position);
super.destroyItem(container, position, object);
}
public Fragment getRegisteredFragment(int position) {
return registeredFragments.get(position);
}
public SparseArray<DisplayFragment> getRegisteredFragments() {
return registeredFragments;
}
}
It has been a long time since I wrote this, so are not able to go into great detail.
However, the key thing to note (I would think), is that I have an external 'bookkeeper' (the DisplayCoreModule). Whenever the amount of fragments would change in DisplayCoreModule, I simply invoked notifySizeChangingDataSetChange() to make the FragmentStatePagerAdapter refresh content.
Regaring some of your problems, FragmentStatePagerAdapter will not invoke onCreateView of your fragments until they are displayed. Usually this means only three fragments: the one you currently look at and one from either side of that fragment.
Perhaps, come to think of it, the root of your problem is missing getItemPosition() with POSITION_NONE. Seem to recall that it was neccesarry for dynamic content to be updated. To make notifyDataSetChanged have a proper effect.

HACKY SOLUTION:
I simply modified my addTab method:
public void addTab(My_Fragment fragment, String title){
boolean createFragment=true;
if (getTabCount()>0){
//all tabs must have different names
for (int i=0;i<getTabCount();i++){
if (getTabTitle(i).equals(title)==true){
createFragment=false;
break;
}
}
}
if (createFragment && fragment!=null){
//this ensures that if a fragment of the same type already exists, that should be the one to be added, tabs are made of fragments of different classes, so there will be no problem while checking this.
for (Fragment f: my_activity.getSupportFragmentManager().getFragments()){
if (fragment.getClass().isInstance(f)){
my_viewPagerAdapter.addFragment((My_Fragment)f,title);
tabLayout.addTab(tabLayout.newTab().setText(title));
return;
}
}
my_viewPagerAdapter.addFragment(fragment,title);
tabLayout.addTab(tabLayout.newTab().setText(title));
}
}

Related

How to hide fragment from activity - Android Studio

I have two fragment in one activity, and I need to know how to just hide the second fragment and leave the firs one
So, i want to hide PerfilDatosFragmen();, but i also need to keep "2" in return statement. how can i do that?
public class ViewPagerAdapter extends FragmentStatePagerAdapter {
public ViewPagerAdapter(FragmentManager fragmentManager) {
super(fragmentManager);
}
String[] encabezado = {"Tarjeta", "Datos"};
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return new PerfilTarjetaFragment();
case 1:
return new PerfilDatosFragmen();
}
return null;
}
#Override
public int getCount() {
System.out.println(vacio);
// int vacio = getIntent().getExtras().getInt("AcompaƱante");
/* if(vacio.equals("1")){
a= 1;
}else{
a= 2;
}*/
return 2;
}
It's very simple. PagerAdapter.getCount() is defined the count of your fragments. You always return 2. The best solution is:
public class ViewPagerAdapter extends FragmentStatePagerAdapter {
private final List<Fragment> fragments = new ArrayList<>();
public ViewPagerAdapter(FragmentManager fragmentManager) {
super(fragmentManager);
fragments.add(new PerfilTarjetaFragment());
fragments.add(new PerfilDatosFragmen());
}
String[] encabezado = {"Tarjeta", "Datos"};
#Override
public Fragment getItem(int position) {
return fragments.get(position);
}
#Override
public int getCount() {
return fragments.size();
}

Stopping Exoplayer onSwipe of ViewPager

I am using a ViewPager with single fragment instance in which I am showing Media files like Images, Videos, Audio.
I have implemented ExoPlayer for handling Video & Audio files. And Glide for images.
To avoid the memory leaks I am releasing the ExoPlayer object like this in ItemViewerFragment.java :
private void releasePlayer() {
if (player != null) {
player.release();
player = null;
trackSelector = null;
simpleExoPlayerView.setPlayer(null);
}
}
#Override
public void onStart() {
super.onStart();
if (player == null && currentGalleryModel != null) {
initializePlayer();
}
}
#Override
public void onResume() {
super.onResume();
if (player == null && currentGalleryModel != null) {
initializePlayer();
}
}
#Override
public void onPause() {
super.onPause();
releasePlayer();
}
#Override
public void onStop() {
super.onStop();
releasePlayer();
}
And in onViewCreated() I am initializing view like this :
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
if (currentGalleryModel.isVideo() || currentGalleryModel.isAudio()) {
simpleExoPlayerView.setVisibility(View.VISIBLE);
imageView.setVisibility(View.GONE);
initializePlayer();
} else if (currentGalleryModel.isImage() || currentGalleryModel.isGif()) {
simpleExoPlayerView.setVisibility(View.GONE);
imageView.setVisibility(View.VISIBLE);
Glide.with(this)
.load(currentGalleryModel.getFilePath())
.placeholder(android.R.color.black)
.fitCenter()
.diskCacheStrategy(DiskCacheStrategy.NONE)
.into(imageView);
}
}
I am using FragmentStatePagerAdapeter. This is the getItem method :
#Override
public Fragment getItem(int position) {
return ItemViewerFragment.newInstance(mItems.get(position));
}
I am not able to detect the onPause of the fragment on first swipe of Viewpager. On second swipe video/audio files are stopped playing.
In activity I have tried adding .addOnPageChangeListener :
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
try {
((ItemViewerFragment)mAdapter.getItem(mPreviousPos)).imHiddenNow();
} catch (Exception e) {
e.printStackTrace();
}
mPreviousPos = position;
}
And in ItemViewerFragment.java :
public void imHiddenNow(){
releasePlayer();
}
Still video/audio keeps on playing.
Here is a Video Link to the Screencast.
Demo project GitHub link.
I followed an approach of maintaining HashMap of fragment objects inside PagerAdapter
Declare an interface :
interface FragmentLifecycle {
void onPauseFragment()
}
Implement an interface in Fragment.
public void onPauseFragment() {
if (simpleExoPlayer != null){
simpleExoPlayer.setPlayWhenReady(false);
}
}
Store all the fragment objects in a HashMap<Integer,Fragment> with there respective positions as a key. Declare hashmap inside PagerAdapter. Also declare one getter method for accessing fragment objects from hashmap. e.g.
#Override
public Fragment getItem(int position) {
ItemViewerFragment fragment = ItemViewerFragment.newInstance(mItems.get(position));
mFragments.put(position,fragment);
return fragment;
}
public ItemViewerFragment getMapItem(int position) {
return mFragments.get(position);
}
In activity where you have declared viewPager keep one variable currentPosition and implement ViewPager.OnPageChangeListener.
Inside onPageSelected method,
#Override
public void onPageSelected(int position) {
if(mAdapter.getMapItem(currentPosition) != null) (mAdapter.getMapItem(currentPosition)).onPauseFragment();
currentPosition = position;
}
Edit from the future: you should never hold a reference to Fragment instances directly inside a FragmentPagerAdapter, because it can cause crashes after process death.
Here is the code for the pager adapter:
class ViewPagerAdapter extends FragmentPagerAdapter {
private final List<Fragment> mFragmentList = new ArrayList<>();
private final List<String> mFragmentTitleList = new ArrayList<>();
public ViewPagerAdapter(FragmentManager manager) {
super(manager);
}
#Override
public Fragment getItem(int position) {
return mFragmentList.get(position);
}
#Override
public int getCount() {
return mFragmentList.size();
}
public void addFragment(Fragment fragment, String title) {
mFragmentList.add(fragment);
mFragmentTitleList.add(title);
}
#Override
public CharSequence getPageTitle(int position) {
return mFragmentTitleList.get(position);
}
}
Here is the scroll Listener:
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
//Stop media here.
}
#Override
public void onPageSelected(int position) {
//Save your previous position here.
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
For the media you can use a for Loop and add all the fragments to the list at once and then use this for efficiency :
viewPager.setOffscreenPageLimit(3);
This will make sure only 3 instances of your fragment are available which is enough.
For using single fragment i would suggest you to do it like this:
public MyFragment() {
}
//This is to send a file to the fragment if you need it.
public static MyFragment newInstance(File file) {
MyFragment fragment = new MyFragment();
Bundle bundle = new Bundle();
bundle.putSerializable("file", file);
fragment.setArguments(bundle);
return fragment;
}
Then in the onCreate of Fragment you can retrieve your file like this:
File file;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
file = getArguments().getSerializable("file");
}
Now add your fragments to pager like this:
for (int i = 0; i < totalFiles; i++) {
viewPagerAdapter.addFragment(MyFragment.newInstance(fileList.get(i));
}
Hope this helps.
It's been more then a year since I used Exoplayer & I kinda tackled a similar problem. Please note that the APIs have changed a little bit so take the following code just to get an idea on how to implement a potential solution. Please let me know if it doesn't work, I'll look into the APIs further and get back to you.
Coming to the solution:
private int mPlayerCurrentPosition;
private int getCurrentPlayerPosition() {
return mExoPlayer.getCurrentPosition();
}
// call this from onPause
private void releaseExoplayer() {
mPlayerCurrentPosition = getPlayerCurrentPosition();
mExoPlayer.setPlayWhenReady(false);
mExoPlayer.release(); // this will make the player object eligible for GC
}
private void resumePlaybackFromPreviousPosition(int prevPosition) {
mExoPlayer.seekTo(mPlayerCurrentPosition );
}
The problem is that onPause and onResume are not called when the fragment visibility changed in ViewPager.
The solution is to add 2 visibility events: losingVisibility and gainVisibility.
Why is it a great solution?
Because you keep the framework managing Fragment cache and lifecycle.
We just add the callbacks needed to pause and resume our media in our fragment.
Step-by-step:
The below code is just an explanation for my code. Check Step*.java classes to see full implementation.
Create losingVisibility and gainVisibility methods in YourFragment.java:
public class YourFragment extends Fragment {
/**
* This method is only used by viewpager because the viewpager doesn't call onPause after
* changing the fragment
*/
public void losingVisibility() {
// IMPLEMENT YOUR PAUSE CODE HERE
savePlayerState();
releasePlayer();
}
/**
* This method is only used by viewpager because the viewpager doesn't call onPause after
* changing the fragment
*/
public void gainVisibility() {
// IMPLEMENT YOUR RESUME CODE HERE
loadVideo();
}
}
Call losingVisibility and gainVisibility every time a new page is selected (onPageSelected) in YourActivity.java:
mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
YourFragment cachedFragmentLeaving = mYourPagerAdapter.getCachedItem(mCurrentItem);
if (cachedFragmentLeaving != null) {
cachedFragmentLeaving.losingVisibility();
}
mCurrentItem = position;
YourFragment cachedFragmentEntering = mYourPagerAdapter.getCachedItem(mCurrentItem);
if (cachedFragmentEntering != null) {
cachedFragmentEntering.gainVisibility();
}
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
Add getCachedItem to YourPagerAdapter.java:
The 3rd step is adding a method to retrieve cached fragments. To do it we must cache a reference to a fragment created (overriding instantiateItem) and release the same reference (overriding destroyItem).
public class YourPagerAdapter extends FragmentStatePagerAdapter {
private SparseArray<YourFragment> mFragmentsHolded = new SparseArray<>();
#NonNull
#Override
public Object instantiateItem(ViewGroup container, int position) {
Object fragment = super.instantiateItem(container, position);
if(fragment instanceof StepFragment) {
mFragmentsHolded.append(position, (StepFragment) fragment);
}
return fragment;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
mFragmentsHolded.delete(position);
super.destroyItem(container, position, object);
}
public YourFragment getCachedItem(int position) {
return mFragmentsHolded.get(position, null);
}
}
i know its so late but i hope it helps anyone ...
viewPager keeps offscreen fragment started ..
so you have:
prev offscreen fragment (start) --> visible fragment (working)--> next offscreen fragment (start)
solution is you can override Fragment.setUserVisibleHint() and handle play/pause video..

Java.lang.IllegalStateException: The application PagerAdapter changed the adapter's contents without calling PagerAdapter#notifyDataSetChanged android

I am trying to use a static class to pass value to a view instead of using intent as I have to pass a large amount of data. Sometimes I get this error and couldn't find out what is the main reason
Error :-
java.lang.IllegalStateException: The application's PagerAdapter changed the adapter's contents without calling PagerAdapter#notifyDataSetChanged! Expected adapter item count: 101, found: 200
My Pager class
public class MemeDetailActivity extends AppCompatActivity implements OnDialogClickListner<Void> {
private ViewPager mPager;
private List<Datum> mList;
private ScreenSlidePagerAdapter pagerAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_meme_detail);
mList = DataResult.getInstance().getData();
DataResult.getInstance().resetData();
if (mList != null)
startPager(selected_position);
else
Toast.makeText(this, "Error loading data", Toast.LENGTH_SHORT).show();
// ATTENTION: This was auto-generated to implement the App Indexing API.
// See https://g.co/AppIndexing/AndroidStudio for more information.
client = new GoogleApiClient.Builder(this).addApi(AppIndex.API).build();
}
private void startPager(int position) {
pagerAdapter = new ScreenSlidePagerAdapter(getSupportFragmentManager());
mPager.setAdapter(pagerAdapter);
pagerAdapter.notifyDataSetChanged();
mPager.setOffscreenPageLimit(0);
mPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
new Interactors(MemeDetailActivity.this).updateView(Util.getAccessToken(), mList.get(position).getId(), new OnFinishListner<ViewsRM>() {
#Override
public void onFinished(ViewsRM result) {
}
#Override
public void onFailed(String msg) {
}
});
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
mPager.setCurrentItem(position);
}
public class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter {
SparseArray<Fragment> registeredFragments = new SparseArray<Fragment>();
public ScreenSlidePagerAdapter(FragmentManager fm) {
super(fm);
}
//todo entry point 3 : showing the image in the viewpager
#Override
public Fragment getItem(int position) {
Fragment fragment = new fragment_mypager_new();
Bundle bundle = new Bundle();
if (frmMyMemes)
bundle.putParcelable("MY_DATA", myList);
bundle.putSerializable("DATA", mList.get(position));
fragment.setArguments(bundle);
return fragment;
}
#Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
#Override
public int getCount() {
return mList.size();
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment fragment = (Fragment) super.instantiateItem(container, position);
registeredFragments.put(position, fragment);
return fragment;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
registeredFragments.remove(position);
super.destroyItem(container, position, object);
}
public Fragment getRegisteredFragment(int position) {
return registeredFragments.get(position);
}
}
}
My static class
public class DataResult<T> {
private static DataResult instance;
private List<T> data = null;
protected DataResult() {
}
public static synchronized DataResult getInstance() {
if (instance == null) {
instance = new DataResult();
}
return instance;
}
public List<T> getData() {
return data;
}
public void setData(List<T> data) {
this.data = data;
}
public void resetData() {
data = null;
}
}
How I call the activity
Intent intent = new Intent(getActivity(), MemeDetailActivity.class);
DataResult.getInstance().setData(mListA);
look at your code:
#Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
this code is use to refresh view when view change. it is also called notifyDataSetChanged()
its optional ovverride method so you can remove it.
Take a look at this answer: ViewPager PagerAdapter not updating the View
or else you can Change the FragmentStatePagerAdapter to FragmentPagerAdapter
Sometimes this error occurs.
Here is my suggestion:
In your DataResult->getData()
return a copy of the data.
DataResult is a singleton and holds the data. When your view gets the data, the view gets the data reference witch the DataResult is holding. Then setData() would change the data reference. Here comes the IllegalStateException.
Hope it would work :)
I think your DataResult class is not necessary.
According to your comment you are getting the error while you are updating the data set. I think you are getting data from some REST API or another web service. Then assign the data you gets from the API to a temporary Array List and update that temporary array list while you are getting new data. Don't touch the mListA variable until you finish receiving data. After complete getting data from the API assign the temporary array list you used to mListA directly in one line.
mListA = tmpList;
Then again call
mList = mListA;
pagerAdapter.notifyDataSetChanged();
This should solve your error.
try using the following way:
mList=new ArrayList<Datum>();
mList.addAll(DataResult.getInstance().getData());
DataResult.getInstance().resetData();
It may because you first setAdapter() and notifyDataSetChanged in method initUI();
Then, you instantiate the List<?> data in method initData(), the two methods in different lifetime of fragment.
It's the problem about fragment's lifecycle
#Override
public void restoreState(Parcelable state, ClassLoader loader) {}
#Override
public Parcelable saveState() {return null;}
#Add in your adapter after getCount();

Endless ViewPager (not looped)

I want to create ViewPager and each page will contain unique data (for example simple textview with integers from 1 to 1000000) and I want to make user see first page with number 500000 (so he will be in the middle of viewpager). I tryed using FragmentStatePagerAdapter with overrided method
getCount() {
return 500000
} and
getItem(int position) {
return MyCustomFragment.newInstance(position)
}
and then set my viewpager.setCurrentItem(50000, false) but when I start app it crashes with OutOfMemory exception. But if I remove viewpager.setCurrentItem(50000, false) then everything works nice, but user starts with first page, not with 50000. As I understand OutOfMemory is thrown because when I set current item to 50000 fragmentadapter tryes to load every fragment from 1 to 50000 and keeps them in memory. So how can I avoid such problem? Probably I should find another solution, but I don't know how to solve my problem with some other way
UPD: here is code that doesnt work:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_one_day_schedule);
mViewPager = (ViewPager) findViewById(R.id.day_page);
mViewPager.setAdapter(new SchedulePagerAdapter(getSupportFragmentManager()));
// Puts user in the middle of viewpager
mViewPager.setCurrentItem(Integer.MAX_VALUE/2, false);
}
public static class SchedulePagerAdapter extends FragmentStatePagerAdapter {
public SchedulePagerAdapter(FragmentManager fm) {
super(fm);
}
// This doesnt work even with empty fragment
#Override
public Fragment getItem(int position) {
return new Fragment()
}
#Override
public int getCount() {
// Makes viewpager almost infinite
return Integer.MAX_VALUE;
}
}
Try to override these methods:
#Override
public int getCount() {
return Integer.MAX_VALUE;
}
#Override
public CharSequence getPageTitle(int position) {
String title = mTitleList.get(position % mActualTitleListSize);
return title;
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
int virtualPosition = position % mActualTitleListSize;
return super.instantiateItem(container, virtualPosition);
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
int virtualPosition = position % mActualTitleListSize;
super.destroyItem(container, virtualPosition, object);
}

ViewPager: Fire event before page change

I'm using Android Studio 1.2.1.1 and I've implemented a ViewPager with a fair few fragments. I'm trying to get the data from each of the fragments into a public class via an interface. The classa nd interface are not the issue though, I want to export the data from the current page before a new page is selected, unfortunately it appears these are the only options and none really suit my needs:
_mViewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrollStateChanged(int position) {
}
#Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
}
#Override
public void onPageSelected(int position) {
}
});
I would be able to invoke the call to export the data easily on checkboxes etc, but my fragments include imageviews (exported as base64) and edittexts. Has anyone else come across this in the past? Is it an easy one or is it going to be changing my code entirely?
Any help would be greatly appreciated
Can you not just keep a reference to what page you're currently on and set that index every time onPageSelected is called. You can then see what the index was before changing it and update the old Fragment with that?
Example:
int oldPosition = -1;
#Override
public void onPageSelected(int position) {
if (oldPosition != -1) {
extractInformationFromFragment(oldPosition);
}
oldPosition = position;
}
private void extractInformationFromFragment(int position) {
switch (position) {
case 0:
fragment1.getInformation();
break;
case 1:
fragment2.getInformation();
break;
case 2:
fragment3.getInformation();
}
}
I'm handling it this way :
private int mCurrentSelectedPage = 0;
mViewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(mTabLayout) {
#Override
public void onPageSelected(int position) {
super.onPageSelected(position);
// Get data from last selected fragment
EditFragment oldFragment = getFragment(mCurrentSelectedPage);
if (oldFragment != null) {
oldFragment.getData();
}
// Set data to the new fragment
EditFragment newFragment = getFragment(position);
if (newFragment != null) {
newFragment.setData();
}
mCurrentSelectedPage = position;
}
});
public EditFragment getFragment(int position) {
String fragmentTag = "android:switcher:" + mViewPager.getId() + ":" + position;
return (EditFragment) getSupportFragmentManager().findFragmentByTag(fragmentTag);
}

Categories

Resources