keep each fragment selected inner ViewPager? - android

I implement the same fragment of 100 in ViewPager on my application. The fragment rather large display data from the server. When I put the code mViewPager.setOffscreenPageLimit (100), the app feels very heavy. Therefore, I use the way: remove setOffscreenPageLimit and invoke a method to check the data on the server and displays it when the fragment was selected. But when this happens: when Fragment "1" was chosen, then to fragment "2", back to fragment "1", Fragment "1" will repeat the activity. My question is how to keep the activity of each fragment is selected or when returning to the fragment that was selected at the last condition? Sorry for my English.

setOffscreenPageLimit : Set the number of pages that should be
retained to either side of the current page in the view hierarchy in
an idle state. Pages beyond this limit will be recreated from the
adapter when needed.
Don't setOffscreenPageLimit too large, because the view pager will keep the page active so your app will run slowly. And when you remove setOffscreenPageLimit, this setting defaults to 1. It means that pages beyond this limit (1) will be recreated from the adapter when needed.
https://developer.android.com/reference/android/support/v4/view/ViewPager.html#setOffscreenPageLimit(int)

if you remove setOffscreenPageLimit, The way to keep the activity of each fragment is store the state data of fragment in:
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putData("key", fragmentData);
}
when you leave it, when you back again, you update the fragment by the state data you have stored.
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
fragmentData = savedInstanceState.getData("key", defaultData);
}
You should use some fragments in a viewpager, do not use too more. think about use a fragment and display many views, data in it.

Related

Load data to a list fragment tab on the creation of the MainActivity

I am absolutely in love with these new components Android is introducing. So, I am building a standard mobile application with solely one activity using the Navigation components and Architecture components such as a View Model as I am performing a lot of communication with my data that I stored in room.
In one of my bottom navigation tabs, I have a list that is loaded from all my data in room. So far, I have set up my RecyclerView and my adapter in the OnCreateView() (only function used in this fragment) of this list fragment and every thing shows successfully.
The problem is that every time (especially more at first view) the fragment takes a solid 10 seconds to display all the data (which is normal considering there is a lot of it).
My question: Is there a way the adapter and and RecylcerView of this specific fragment could be setup (and load all my data) in the OnCreate() of my sole activity? So that when I view the fragment for the first time, everything pops up right away.
Also, how would I go about using OnPause() of the list fragment so that when I am on another tab, the list fragment doesn't get destroyed and when we go back on it, it displays right away?
Fetch all data from room inside onCreate() method of fragment. The onDestroyView() method calls everytime you moves away from the fragment.
To prevent recreation of views inside fragment store view in a variable.
Example:
class YourFragment extends Fragment{
View rootView;
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
//fetch data from room
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState){
if(rootView == null)
rootView = inflater.inflate(R.layout.your_fragment_layout, container, false);
return rootView;
}
}

How can I gather data from my ViewPager?

I made an activity which is simply a viewpager with a few tabs. Each tab is like a form that the user needs to fill out. When the user is done, the data from the view pager should be collected and sent back as a result. I almost have this working but for some reason the data on my first tab seems to get reset when the user gets to the third tab. I'm guessing this is due to some view recycling in the pager. Anyways, I'm wondering if there is some easy way to gather all the data from the different tabs or do I have to create some kind of tight coupling between the activity and viewpager object?
you have to use SmartFragmentStatePagerAdapter as described here "https://guides.codepath.com/android/ViewPager-with-FragmentPagerAdapter" and than need to
vpPager.setOffscreenPageLimit(3);
Your issue should be resolved. :)
A viewpager will kill off the fragment if it is 2 pages away from the current page. It then recreates it when the pager is on a page that is 1 step away from it.
You should move your form data into your activity/fragment that is holding the viewpager and use fragment listeners to update your data accordingly
For example, you could use a fragment listener like below to pass the data to/from the containing activity
public interface MyFragmentListener{
void saveMyFormData(MyFormData formData);
MyFormData getFormData();
}
private MyFragmentListener mListener;
//initialise fragment listener in onAttach (or elsewhere)
private void initFormView(){
MyFormData data = mListener.getFormData();
//do stuff with data
}
private void saveData(){
mListener.saveMyFormData(myFormDataObject);
}

Fragments: Replacing a fragment causes it to reinstantiate on back pressed

I am using one activity all fragment approach. Now I have a fragment A and when I go to fragment B I replace A in container with B with
.replace(R.id.master_fragment_container_above_toolbar, fragment)
.addToBackStack("")
.commit();
As you can see, I have added fragment to backStack. But now when I press back on device, it re-instantiates the fragment A and thus takes time to go back.
Is there another way to do it? I don't want to use add(), if I add multiple fragments to container, it will take up a lot of memory.
The short answer - there's no silver bullet in your case. You'll have to use replace() and it will re-create fragment's View on going back. That's "by design".
The good news is that there're a few tricks you can do to make it less dramatic for UX.
Cache whatever you can. If you load content from web - write it into the local SQLite db. And fill the screen from Local Storage while refreshing the data from the server.
In onCreateView() avoid re-creating Adapters once they are already exist. If user is getting back to FragmentA from the FragmentB, FragmentA will recreate its View. But it doesn't mean, that local variables are null at this point. So I do it like this:
public class FeedFragment extends Fragment {
private FeedAdapter adapter;
......
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = initialize(inflater, container, R.layout.fragment_with_recyclerview);
....
if (adapter == null) {
adapter = new FeedAdapter();
}
RecyclerView recyclerView = (RecyclerView)rootView.findViewById(R.id.recyclerView)
recyclerView.setAdapter(adapter);
recyclerView.setLayoutManager(new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL));
return rootView;
}
}
It matters, because filling TextViews, etc. are so fast operations, that you don't really care about it, while huge ListView or RecyclerView can be much more expensive;
Use image-caching and good image-loading tool. I'd recommend Picasso from Square. It has automatic memory and disk caching;
Try to logically decouple your app. Let's take a Gmail-style application, as an example:
It has NavigationDrawer, which is switching user through the root fragments (i.e. no need to keep navigation stack). Once you open mail-thread - it replaces the root fragment with MailThread fragment. There you can consume the content.
But once you click on "Compose email" - you are redirecting to a separate Activity - as you move from consuming content to composing content state (I.e. significant change in user's behaviour: new user scenario == new activity).
Many top developers go even further and having Activities for pretty much everything. Twitter (and it's satellite products) as an example. But personally, I prefer to keep it in balance (as opening new activity is an expensive operation from perf. point of view).

How to pre-load a fragment before showing?

In my activity I have several fullscreen fragments, each of them downloads some data from web (using an async task) and shows them to the user. The fragments are showed one at a time.
To be more specific, each of the fragment readings some urls from a sqlite database, and fetch the content before showing them in a list, if that matters. The data loading tasks can be done in the OnCreate() function.
I would like to preload all the fragment (at least starting the downloading), when I show a splash screen. Pretty much like a viewpager preload its fragments.
I am wondering how to achieve this? I tried initialize/create all the fragments in the OnCreate() function of my activity, hoping the OnCreate() of fragments could be called earlier, but the OnCreate() and OnCreateView() function of the fragments are not called until a fragment is about to show to the user.
It sounds like you need to separate your model (the data which is downloaded) from your view (the fragments). One way to do this is to start the downloading AsyncTasks in your activity, rather than starting them in each fragment. Then when the fragments are eventually displayed they can show the data which has been downloaded (or a spinner or some other indication that the download process is still executing).
Fragment's onActivityCreated(Bundle) tells the fragment that its activity has completed its own Activity.onCreate().
So your solution to this problem is initialize or create or do your stuffs which you want to preload before fragments are created, inside your Fragment's onActivityCreated(Bundle)
see documents for fragment's lifecyle
The earliest pace you can start loading is either in a static singleton or in the Application Class
What I end up doing is the following, (1) add all the fragments into the container. So they (and their view) will be created and initialized. (2) hide those not in use and only show the one I would like the user to see. (3) use FragmentTrasaction.show()/FragmentTrasaction.hide() to manipulate the visibility instead of FragmentTrasaction.add() or FragmentTrasaction.replace().
If you following this approach, be warn that all the fragments will be cached in memory. But the benefit is the switch between fragment will be fast and efficient.
I was facing the same problem and then I used this method, suppose we are having an EditText in the fragment, then we can use codes like this
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
//this method allows you to input or instantiate fragments before showing this to an activity conidering id is "editTextEditProfileFirstName"
EditText firstName = (EditText) getActivity().findViewById(R.id.editTextEditProfileFirstName);
firstName.setText("This is my first name", TextView.BufferType.EDITABLE);
super.onViewCreated(view, savedInstanceState);
}

ViewPager with Fragment reload at first and last page

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

Categories

Resources