android load data asynchronously in view pager - android

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.....

Related

FragmentStatePagerAdapter Cache usage

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.

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.

When (& where) are my fragments created

I'm using the viewpagerindicator library (http://viewpagerindicator.com/) to create some sort of wizard for my android app. It works fine and does exactly what I want.
I would like to "extend" the functionality a bit by having "previous"/"next" buttons in my ActionBar - pretty much as in Android's "Done Bar" tutorial - to step through the wizard. Works like a charm, too.
HOWEVER:
I would like to display information about the "next" & "previous" fragment in the ActionBar's buttons. Information I pass to the fragments that live in the ViewPager at the time of their "creation" (actually at the time of their object instantiation - using the classical "newInstance(...)" approach to create the instance of my fragment, store the parameters in a Bundle and extract them in the fragment's "onCreate" method). The same way the template does it, when you create a new fragment for your project.
So, this information is the thing I actually want to display in my wizards button to know what fragment is next and which was last.
The type of this information is not important for my problem. It could be a String or an icon or an int or ... anything else you want.
However, wherever I've tried to access my fragments data, the fragment has not yet been fully initialized (meaning its "onCreate" method has not been called yet).
I've tried it in the host fragment's "onViewCreated" method, because I thought that's where all its subviews should be initialized already (at least their "onCreate" method should have been called, I thought), but it seems that this is handled differently for ViewPager to retain only the number of fragments in memory that was set by setOffscreenPageLimit.
So, what I'm looking for (and probably just missing) is the correct callback method here. One that is called when the ViewPager's next Fragments have been loaded and initialized. If such a callback exists, I could place my little piece of code there to update the text in my "previous"/"next" buttons within the ActionBar.
Any help, comments, ideas are highly appreciated. If needed, I can also try to attach some code sample to better explain my setup, but I think it should be easy enough to understand what my problem is.
Thanks in advance!
P.S.: I also tried to do this by using EventBus to send "onFragmentInitialized" messages from my fragments within in the ViewPager and the hosting fragment. It actually worked, but it does not seems the proper way to do this.
When a Fragment's onCreate Method is called, its already preparing to be displayed, and practically its past the point where its considered a Next or Previous fragment instead its considered current.
A fragment's onCreateViews method is called after committing a transaction in the FragmentManager. which takes less than 1 sec to bring it in front of the user (depending on the device and runtime environment)
But in your case, your data should be initalized outside the Fragment that uses it, and displayed where ever you want by passing the data itself then displaying whatever you want form it.
decouple your data from android objects (Fragment, Activity ...) and you should be able to load, maintain, access it cleanly and without worrying about their callbacks.
The Fragment's arguments can be read and loaded in its onAttach callback rather than onCreate, the Activity will then (after onAttach is complete) get a onAttachFragment callback with the Fragment as a parameter. However, I doubt onAttachFragment will be called when switching between already loaded pages in the view pager.
If not, you could have the fragment notify the activity (through an interface) that it is now active during its onActivityCreated, onViewCreated or similar method.
But it sounds more like the activity should register as a page changed listener to the ViewPager itself, and update its state depending on the page rather than which fragment is active.
As a side note, ViewPagerIndicator is quite old now (hasn't been updated in 3 years), a more modern approach is the SlidingTabs example from Google, which has been built into a library available here: https://github.com/nispok/slidingtabs

How to get/set data from/to each page of ViewPager in android

Will try to explain what I need to achieve:
My activity is used to display some user settings. Just for users, to make it look nicer, I need to use ViewPager with 3 pages: general settings, another settings, different settings. When activity starts I get all settings using http async task. So i need to fill all my 3 pages with the data from http responce. So user can scroll left/right to view different pages and change settings. On action bar I have button save: when press it, it should take all the data from each page and send http post request in order to save data.
Which type of adapter do I need to use for my ViewPager in order to achieve it? Currently I use "FragmentStatePagerAdapter", but it gives me access to the current/displayed fragment. But I need to be able to get/set data from every fragment, not only current one.
Can someone give me any hint how I can do that. Shoul I use FragmentStatePagerAdapter or just PagerAdapter will be enough? Or maybe there is another way for it)
Any tips will be very helpful. Thanks
Loading the data and displaying it are different tasks. You can of course download all the data that you will need and store it in the adapter itself. Once the adapter gets a call to getItem() you initialize a new fragment with the data for the given page and return it.
Also, use a FragmentPagerAdapter because it is a lot more lightweight. In the api docs you can actually see how a new Fragment is created an returned.

Using Loader inside ActionProvider

Context:
I want an action button that will allow the user to select some stuff form a list.
I'm considering using an ActionProvider for this.
My data is retrieved from a REST service and cached locally in a DB.
Problem:
ActionProvider doesn't seem to support loaders. (or am I mistaken?)
If I just load the data using a query, it will not get updated once/if the new REST result comes in. In fact, the first time around - it will be empty.
Questions:
0) Is there a way to do what I want in an ActionProvider?
1) Should I be using this approach over a plain old Activity?
PS. Could someone add 'actionprovider' as a tag? :-)
10X
How about creating a fragment with no UI, but with setHasOptionsMenu(true) and onCreateOptionsMenu() implementation instead.
The fragment could load the data via loaders, and when ready invalidate the options menu, populating it with the required list.
You can attach such fragment to your activity and it will take care of its life cycle, while having this feature in a separate class.

Categories

Resources