FragmentStatePagerAdapter Cache usage - android

When using FragmentStatePagerAdapter is an Android version of "This is better for pagination through a collection of objects for the number of pages is indeterminate. Destroy fragments as the user navigates to other pages, minimizing memory usage "
The operation of this widget to make the creation of a page before the actual position, in my case I consume different services each time I scroll over the tabs and obviously the data can be updated, since paging loads a position towards Forward when I return to the previous position does not perform service request because FragmentStatePagerAdapter does not detect this, please someone knows how to resolve this FragmentStatePagerAdapter
The length of my tabs is dynamic, that's why I'm using 2 Fragment, one for the tabs and another for the pager
https://developer.android.com/reference/android/support/v4/app/FragmentStatePagerAdapter.html

I try to understand your problem, let me guess your previous or next Fragment was not destroy and when you swipe the page back to previous page or next page it does trigger Network request.
Yes, if it the case then Fragment does not remove from activity which mean not lifecycle trigger to the fragment. However if you need to trigger the network then in your FragmentStatePagerAdapter override this method setPrimaryItem then send the callback to your Fragment (The object pass in should be your live instance fragment). Set primary will provide the one which being visible to the user which is actually the current item of ViewPager.

Related

Does restarting Fragment also recall FirebaseDatabase

I have 3 fragments and a bottom navigation menu to switch between them.
In every fragment i have a recyclerview to display data gathered from FirebaseDatabase.
My question is: Should i use Replace() fragment? As it would result in restarting the fragment and requesting again Firebase SingleEventValue every time the user navigate between fragments
Or i must use Add Show Hide? Or that would lead in memory leaks?
The methods you use to deal with the fragments are mostly not relevant. The Firebase SDK will cache data previously fetched, so if you make a second request for some data, from any point in your app, you will be seeing cached data, and it will even work offline. There are no "leaks" involved here when using single value events.
Adding a listener to a database location is a different matter. Ideally, listeners should be attached when a fragment becomes visible, then detached when not visible.

Store async data in recycler view

I have a main activity in which i have used a view pager.So i can move between 4 tabs and the view pager handles all of that.One of my tabs scans the contacts on the phone to get their details and display it in the recylerview which is in the same tab,this task takes a long time and i am doing this in an async task.Everything is working fine but the problem is if i move to another tab while this scanning is going on the data does not get applied to the recycler view possible because that fragment is being destroyed.
Is there a workaround for this or should i just prevent the user from shifting tabs while the scanning is going on (if so some sort of code or a link to the code would be really helpfull).
I wouldn't recommend you force a user to stay on a page whilst data loads. This sounds like it would only frustrate people. To that end, I have a couple of ideas that should keep your AsyncTask running whilst your Fragment isn't visible.
First, you could call setOffScreenPageLimit(2) on your ViewPager. As you only have four Fragments, this should mean all of them are stored in memory.
viewPager.setOffScreenPageLimit(2);
Another approach is you may be able to create a UI-less Fragment whose sole function is to conduct your AsyncTask and then, once it reaches onPostExecute(), pass the Cursor result to the Fragment that requires it with either an interface or an EventBus of some sort (i.e. LocalBroadcastManager or one of the other many excellent libraries that exist, such as GreenRobot's EventBus).
Edit If you like information on how to create such a "worker" Fragment, then there is a very good and detailed post on androiddesignpatterns.

3 android fragments in viewpager, how to keep them all alive?

I have a viewpager with at least 3 fragments. If the user inputs data into A, then B, then C and goes back to A that data is lost from A.
I think I read somewhere that this has to do with memory management and since fragments only connect to or store adjacent fragments it's killing A when I get too far away.
However I wish to retain the life of each fragment even were I to have >3.
How can I tell the viewpager to never kill a fragment unless explicitly directed?
use
setOffscreenPageLimit(int limit)
on the ViewPager object. "It sets the number of pages that should be retained to either side of the current page in the view hierarchy in an idle state."

android load data asynchronously in view pager

I need a solution for view pager implementation.
Firstly I am loading huge data from database in single page,so sometimes during swipe it slows down swipe frequency(you need to multiple time swipe on page) as in background it is doing fetching task.
I am not using async task for returning view.
Is there any way to lazy load pages just allow user to go on other page on swipe but data is lazy loaded.
My code sample is as below;
public Object instantiateItem(View container, int position) {
View v;
v = View.inflate(context,R.layout.swipearea, null);
listView = (ListView)v.findViewById(R.id.MyListView);
largeDataCall();
((ViewPager)container).addView(v);
return v;
}
I am calling this in on create method.
pager=(ViewPager) findViewById(R.id.pagerAdapter);
pager.setAdapter(new SimplePager(MyPager.this));
pager.setCurrentItem(364);
Is there any solution?
I would suggest to work with Fragments (and not directly with views).
You need an Interface on your fragments to tell them when they are shown:
public interface IShowedFragment {
public void onShowedFragment();
}
Make all your fragments implement that interface, and in that method call your loaders/asyncTasks/background tasks.
Then put an onPageChangeListener on your ViewPager, and when you detect the user changed the page, call the interface method on your fragment. You have some choices with this listener, with one of the methods you can wait for the viewPager to stop to slide to trigger your interface call.
To be able to get the right fragment to make this call, take the fragment from yourFragmentApadter.instantiateItem(ViewGroup, int) which will return the fragment for that position if it is already loaded.
mPager.setOnPageChangeListener(new OnPageChangeListener() {
#Override
public void onPageSelected(int position) {
Fragment fragment = (Fragment) mAdapter.instantiateItem(mPager, position);
if(fragment instanceof IShowedFragment){
((IShowedFragment) fragment).onShowedFragment();
}
}
(...)
Like that you can prepare your fragments with empty views and when you slide on one, you start to load the data.
I have just completed a very similar task. To get you started on finding the solution to your problem consider the following points in order;
Look at whether you need to be fetching all of that data in the first instance. Feel free to post back with some detail as to what information you are needing to be loaded and what you are doing with it (displaying it as a list on screen?)
Look at using CursorLoaders which perform heavy-lifting tasks such as database fetches asynchronously. This tutorial on the interwebs introduces the ContentProvider Android approach. Best to familiarise yourself with the official Android URI and ContentProvider documentation if those terms don't mean much.
If you are working with Fragments - Look at using the FragmentStatePagerAdapter instead of the traditional FragmentPagerAdapter. I haven't used this adapter but I have read that it only instantiates the currently visible Fragment, i.e. not those Fragments to the right or left of the currently selected tab.
Look at optimising the query you are running against the DB.
instantiateItem is called when the ViewPager is about to swap and needs a view. It doesn't have to actually create everything. I think ultimately, lazy-loading is out. The way I see it, there's two things you'll need to do here.
1:
Cache the data in the background when the user is about to reach your page. Your example claims that 364 pages (good Lord), so I'd say use a listener to handle page changes. When you're at page 363, start loading the data for 364. When you're at 364, start loading the data at 365 and keep the data at 363 in case the user wants to swap back. If the data loads relatively quickly or the user takes a long time to swap, it should be seemless assuming you're using asyncTask or thread to load the data.
2: Have a backup default view that doesn't get populated until the data is retrieved. You'll need to do this with option 1 as well in case the user loads the page before you retrieve the data. Basically, just have a view that says "loading..." or something until you have the data. Either that, or populate the data at real time as you get it. In that case the user will see it build.
Either way, I think you'll need to cache something to make the app look good.
I had a similar problem. A viewpager which was loading heavy data. If you are not going to change the views of the individual pages often, then I would suggest you keep the pages in memory. Use following code to perform this
mViewPager.setOffscreenPageLimit(#pages); to keep #pages in memory. I had 5 pages so my #pages was 4.
If you want to refresh data on the viewpager slides, use
mViewPager.getAdapter().notifyDataSetChanged(); with getItemPosition() returning POSITION_NONE.
And use FragmentStatePagerAdapter.
I do not think there's any way to lazy load data in the synchronous fashion that you describe. AsyncTask is the way to go or perhaps you could use threads directly. I believe AsyncTask was designed specifically for this kind of functionality. It's easier to use then the thread directly. If you need ideas on implementation, have a look at:
http://geekjamboree.wordpress.com/2011/11/22/asynctask-call-web-services-in-android/
Have you looked into android ignition library? according to Sample-applications there is a a component "Endless List" and a http-cache component.
I havent tried it myself and dont know if this is a solution for you-just saw the examples.....

Keeping ListFragments in a FragmentPager in sync

Let's say I have a list of homogenous items which is likely to be changed in the lifetime of my Activity by user interaction or OS events. The Activity contains a FragmentPager which shows a number of ListFragments.
These fragments share the previously mentioned data but display it in different ways. E.g. they differ in sorting order or display only a subset of the data. Currently each fragment keeps a separate list containing the respective part of the data in the respective order.
When the data changes, basicly every fragment has to be updated. This means resorting or adding/removing items from some of the fragments. What is the best practice to keep the data in the different fragments consistent?
Currently I have some sort of an observer object, which is notified when something changes and subsequently notifies the connected fragments. But there are a couple of problems:
When the app just started, some of the fragments haven't been created by the FragmentPager, so notifying them is impossible.
When swiping through the fragments some of them get paused. In this state, they can't update their list. Should they disconnect from the observer in this case? This leads to:
When a change happens, while a fragment is disconnected, it basicly misses it.
And so on...
If I understood your ViewPager shows the same data (or it's portion) but in different views. So, I belive ViewPager shouldn't act in any way when data is changed, it's responsibility of Adapter.
About points below you said:
a) creating of fragments inside ViewPager can be managed by you. Just see javadoc of ViewPager::setOffscreenPageLimit(int limit) method.
b) I think you should do nothing with UI when data changed but fragment is in paused state. If you want to update do it in onResume(). Or better to set some field in DB (if you have) to "updates present" state and check it when Activity(Fragment) appears.
c) As in previous option - if fragment disconnected just ignore updates. Or if you really interested in that update use sticky BroadcastReciver (be carefull sticky BR is expensive thing)
You can keep your data in Application class, update only visible fragments when data has changed, and always ask for the new data in Fragment's onResume(), that'll do it
What I would do is have each ListFragment use a Loader to load its data. Then, instead of having the observer notify the Fragment (which might have been killed) to refresh its data, register an observer for each Loader so that it will know when the data source has changed, and will re-query when one has been detected. (If your data source is an SQLite database and you are using a ContentProvider, the CursorLoader will do all of this for you).
This is the implementation I would recommend because
Each Fragments behavior remains self-contained (i.e. each is a re-usable component that is not tied to any specific ViewPager or Activity).
It avoids the complexities of having to deal with potentially destroyed Fragments within your ViewPager.
If you need a quick fix, you could probably get away with forcing the Fragments to remain in memory using ViewPager#setOffScreenPageLimit(int limit) as Ivan suggests... however, this isn't as clean of a solution in my opinion.

Categories

Resources