I have added a ViewPager in RecyclerView. The issue is that, if i press Home Button, or set activity to pause state, and resume activity again, it does not load fragments inside the view pager.
ViewPager tabs are there, but fragments loads blank.
When i debugged, i find out that, onCreateView does not get called in viewPager's fragment, when onResume() is called for activity,
Following is my code in RecyclerAdapter.
private fun bindTabViewHolder(viewHolder: HomeRecyclerAdapter.TabViewHolder, position: Int) {
viewHolder.tabLayout.setupWithViewPager(viewHolder.viewPager)
//Creating View Pager Adapter Instance
viewPagerAdapter = BaseViewPagerAdapter(fragmentManager)
viewPagerAdapter?.addFragment(homeFragment, dataList?.get(position)?.teamName) // this line can crash
viewPagerAdapter?.addFragment(awayFragment, dataList?.get(1)?.teamName) // this line can crash
viewHolder.viewPager.adapter = viewPagerAdapter
}
I think if it starts calling onCreateView() for fragments, issue will be resolved, Also if i try to get fresh data from the feed, by pull to refresh, if does not load fragments inside viewPager.
You should generally never put a ViewPager that hosts Fragments inside a RecyclerView, as the IDs / tags in the FragmentManager will get confused.
You will need to use a ViewPager in the RecyclerView that hosts Views (by subclassing PagerAdapter, instead of FragmentPagerAdapter) instead.
Related
I have three fragments
MainFragment // Fragment with ViewPager2
ItemFragment // Fragment of the item of the adapter ViewPager2 that contains the RecyclerView
PreviewFragment // Fragment to which I navigate after clicking on any RecyclerView item in the ItemFragment
When I go MainFragment -> PreviewFragment (exactly like that, not from ItemFragment) then on return back the ItemFragment is re-created from scratch. It is understandable because in OnCreateView I do this:
viewPager.adapter = MyAdapter(this)
// Add items
Tried saving MyAdapter like this:
private val adapter: MyAdapter by lazy {
MyAdapter(this)
}
But it leads to a crash, all the solutions described there did not help me.
I also tried to save fragments anywhere, in any repository and cache them there and then add them, but this leads to a bunch of leaks in the LeakCanary of ViewPager2.
In general, I would like to hear how this problem is solved, namely, you need to somehow save the state of the ViewPager2 items, perhaps they really need to be cached somewhere
P.S The main reason why the re-creation of fragments bothers me is that the scroll position of the RecyclerView gets lost
i have activity with viewpager where in 4 fragment inside first fragment viewpager too have, if i open third> fragment inside activity, first fragment where viewpager was deleting and dastroy his children fragment doesnt destroy this my problem in gif
Code creating viewpager
private fun initViewPagerFragment() {
val adapter = ViewPagerAdapter((activity as AppCompatActivity).supportFragmentManager)
adapter.addFragment(BasicInformationFragment(), "Основна інформація")
adapter.addFragment(ContactPersonsFragment(), "Контактні особи")
view_pager_fragment.adapter = adapter
tabs_fragment.setupWithViewPager(view_pager_fragment)
}
how to delete children or doesnt destroy first fragment?
set viewPager.offscreenPageLimit(4) for keeping 4 pages in memory. Otherwise, refresh the list or request for a list item from onVisible of a fragment.
I want my fragment to load only when the tab is clicked. That is I am calling a webservice on each fragment, so I want that webservice to be called only when user clicks the specific tab; loads the fragment.
My Fragments are attached to the view pager.
I have override the following method in my fragments: setUserVisibleHint
override fun setUserVisibleHint(isFragmentVisible: Boolean) {
super.setUserVisibleHint(true)
if (this.isVisible) {
// we check that the fragment is becoming visible
if (isFragmentVisible && !isLoadOnce) {
callAPI(param)
isLoadOnce = true
}
}
}
the variable is set as: private var isLoadOnce = false in the fragment class.
I have 3 fragments in number the problem is when my activity popsup, the first fragment is visible and if I click the last tab that is the third tab to load the third fragment, nothing happens that is the web service won't call at all.
But when I click the second fragment and then the third fragment, and yes the webservice then only calls
So I want to call the web service whenver the user clicks each fragment (number 2 fragment or number 3 fragment)!
Can somebody please figure out what I am doing wrong?
I think there are at least 2 solutions to your problem:
Call "callApi(param)" on onResume() of the fragment;
Override onPageSelected(int) and call "callApi(param) in it.
Let me know if this worked for you!
viewpager generally loads the side views to provide smooth swipe experience.
you can restrict the viewpager to load the view using
viewpager.setOffScreenLimit(0)
When viewpager displays one fragment, it will automatically load the fragment pages around it for performance reasons.
In my fragments, i have recycleviews with a popup menu to delete one item in the list.
I am facing a problem of deleting one item from one fragment, but that item still exists in the other preloaded fragments after I scroll to them.
It works only if I force the viewpager to reload the contents of its fragments by manually scrolling back and forth the fragments.
Is there a way to force reload the preloaded fragments by viewpager?
Your problem can be solved by using Interface. Google suggest using callbacks\listeners that are managed by your main Activity for communicating between fragments.You can use Interface which tells the other fragment to refresh its listview when you delete an item in current fragment.
For an overview http://developer.android.com/training/basics/fragments/communicating.html
Also a good question about this How to pass data between fragments
First create an interface to detect changes in your RecyclerView:
public interface MyRecyclerViewChangeListener(){
void onRecyclerViewDataChanged(int id);
}
Create a static variable in your Fragment or Activity which contains your viewpager:
public static List<MyRecyclerViewChangeListener> mListeners = new ArrayList();
Implement your interface to your ViewPagerFragments and do what you want in method you implemented.
In your fragment's onResume register your listener to mListeners like blow to detect changes:
MyFragmentOrActivity.mListeners.add(this);
And in your fragment's onPause unregister your listener:
MyFragmentOrActivity.mListeners.remove(this);
Finally notify your listeners when your recyclerview data changed:
for(MyRecyclerViewChangeListener listener : mListeners){
listener.onRecyclerViewDataChanged(id);
}
Edit : If you are changing your recyclerview's data after an async task result such as a web api call, you can register your listener in fragment's onCreateView method and un register in onDestroyView method. So you can catch changes in your fragments.
I am not sure if i'm getting your question right but i think this should do it.
YourViewpager.setOffscreenPageLimit(0);
Now the fragment should be destroyed if it is not active and will be recreated if you open it again.So the data change should be recognized.
Hope I could help
Try setting mViewPager.setOffscreenPageLimit(1) such that it will not pre-cache any fragment or you could use FragmentStatePagerAdapter inside viewPager to achieve what you want.
Edit 1:
So Conclusion is :
1) Use local broadcast mechanism to update the fragments present in ViewPager adapter
2) Use handler mechanism to refresh these fragments
3) if you want to blindly update these fragments once they are visible to users then do it inside onPageChangeListener of view pager method.
The answers helped me find the solution.
For future reference, I used a callback every time I used deleteItem(), and took a list of the loaded frags by using the method [FragmentHostingViewPager].getChildFragmentManager().getFragments()
Then I iterated through each fragment as long as each fragment was not null, and called a refresh() method on them.
I'm trying to create a ViewPager with six fragments but only 2nd fragment to 5th fragment contain data that I want to show and the first fragment and the last fragment I want to be used to reload the data and set the position to the 2nd fragment again. The overall flow is like this :
1st (reload and go back to 2nd) <- 2nd fragment <-> 5th fragment -> 6th fragment (same with 1st)
what I've tried is I create a callback from the 1st fragment and 6th fragment like this
public static class callbackFragmentLoading implements callbackFragmentLoad {
#Override
public void onLoading() {
mPager.setAdapter(mAdapter);
mPager.setCurrentItem(2,false);
}
}
and I passed the callback to the fragment constructor so I can called the onLoading function in the onActivityCreated. But I everytime I do it the application will be force closed and the logcat shows
recursive entry to executependingtransactions
is there any way to do this? or my method for doing it is wrong?
Thank You
is there any way to do this? or my method for doing it is wrong?
Messing with callbacks between Fragments of a ViewPager isn't probably such a good idea. Instead I would do it like this:
Don't load any data(like with a Loader) in the Fragments from the ViewPager, instead let the FragmentActivity do it(and the Fragments will get it through methods from the Activity).
Your two loading fragments(position 0 and 5) will call in their onResume method a reload action on the parent Activity(like a Loader restart)
At this moment the Activity will load/reload the data and when that finishes it will set the ViewPager to the correct items(either 1 or 4)
in the onResume method of the data fragments you'll refresh the fragment's data(here you may need to use some sort of signaling system because you'll need to duplicate the refresh code in the onCreateView(some fragments may have their view destroyed if they are far apart from the current visible position)).
As I don't know many things about the inner data fragment I've written a basic skeleton sample(without the data loading in the activity).