Differences between fragmentpageradapter and fragmentstatepageradapter

Source: Internet
Author: User

In an Android app, I use the fragmentpageradapter to process the horizontal sliding of multiple fragment pages. However, I encountered a problem, that is, when the dataset corresponding to fragment changes, I want to be able to call madapter. notifydatasetchanged () is used to trigger the fragment page to use new data adjustment or regenerate its content. However, when I call yydatasetchanged (), I find that nothing has happened.

After searching, I found that not only did I encounter this problem, but there were a variety of solutions, some of which did solve the problem, but I always felt that the problem was not clear. So I decided to understand what the problem was and how it was used correctly. To understand this problem, it is not enough to read the document. You also need to read the implementation of several related classes and understand their design intent. The following is what we can understand through reading the source code.


[Viewpager]

As described in the name, viewpager is a view that is used to flip pages. A viewgroup contains multiple view pages. When the screen is swiped horizontally by the finger, the viewgroup switches the view. To generate these view pages, you need to provide a pageradapter to bind data and generate the final view page.

  • Setadapter ()
    • Viewpager uses setadapter () to establish a connection with pageradapter. This relationship is bidirectional. On the one hand, viewpager will have a pageradapter object, so that you can call the pageradapter method as needed. On the other hand, viewpager will call the registerdatasetobserver () of pageradapter in setadapter () you can call the onchanged () or oninvalidated () method of the observer to register a self-generated pagerobserver object () to send information to viewpager.
  • Datasetchanged ()
    • Called in pagerobserver. onchanged () and pagerobserver. oninvalide. Therefore, when pageradapter. notifydatasetchanged () is triggered, viewpager. datasetchanged () can also be triggered. This function uses the return value of getitemposition () for determination. If it is position_unchanged, nothing is done. If it is position_none, pageradapter is called. destroyitem () to remove this object and set it to be refreshed (needpopulate = true) to trigger pageradapter. instantiateitem () to generate a new object.



[Pageradapter]

Pageadapter is a supporter of viewpager. viewpager calls it to obtain the page to be displayed. pageadapter also notifies viewpager when data changes. This class is also the base class of fragmentpageradapter and fragmentstatepageradapter. If you inherit from this class, you must at least implement instantiateitem (), destroyitem (), getcount (), and isviewfromobject ().


  • Getitemposition ()
    • This function is used to return the location of a given object. The given object is returned by instantiateitem.
    • In viewpager. datasetchanged (), the return value of this function is determined to determine whether to trigger the pageradapter. instantiateitem () function.
    • The implementation in pageradapter is to directly return position_unchanged. If this function is not overloaded, it will always return position_unchanged. As a result, when viewpager. datasetchanged () is called, it is considered that pageradapter. instantiateitem () does not need to be triggered (). Many people call this function because it is not overloaded.
      Nothing happens after pageradapter. notifydatasetchanged.
  • Instantiateitem ()
    • Every time viewpager needs an object to be displayed, this function will be called by viewpager. addnewitem.
  • Notifydatasetchanged ()
    • When the dataset changes, the activity usually calls pageradapter. notifydatasetchanged () to notify pageradapter, while the pageradapter notifies all datasetobserver registered here. One of them is the pageobserver registered in viewpager. setadapter. Pageobserver then calls viewpager. datasetchanged (), so that viewpager starts to update its contained view.



[Fragmentpageradapter]

Fragmentpageradapter inherits from pageradapter. Compared with the general pageradapter, this class focuses more on the situation where every page is fragment. As described in the document,Each generated fragment in this class will be stored in the memory.Therefore, it is suitable for those pages with a relatively small number of static pages. If you need to process many pages, and the data is dynamic and occupies a large amount of memory, fragmentstatepageradapter should be used. The fragmentpageradapter overload implements several required functions. Therefore, we only need to implement the getcount () function from pageradapter. Furthermore, since the implementation of fragmentpageradapter. instantiateitem () calls a new virtual function getitem (), we need to implement at least one getitem (). Therefore, in general, it is more convenient than inheriting from pageradapter.

  • Getitem ()
    • A new virtual function in this class. Function generationNewFragment object. Pay attention to this when you reload this function. If necessary, this function will be called by instantiateitem.
    • If you want to pass relative information to the fragment objectStatic DataWe generally use fragment. setarguments (). This part of code should be put in getitem (). They are executed only once when a new fragment object is generated.
    • If you need to generate the fragment objectSome Dynamic Data in the datasetIf this code is passed to the fragment, it is not suitable for storing it in getitem. Because when the dataset changes, the corresponding fragment is usually generated. If some code passing data is put in getitem (), this Part of code will not be called. This is one reason why many people find that getitem () is not called after calling pageradapter. notifydatasetchanged.
  • Instantiateitem ()
    • The function checks whether the fragment to be generated has been generated. If the fragment is generated, the old one will be used and the old one will be fragment. attach (); if not, call getitem () to generate a new object. add ().
    • Fragmentpageradapter saves all generated fragment objects through fragmentmanager for backup. When this fragment object is required in the future, it will be read from fragmentmanager,Instead of calling the getitem () method again.
    • If you need to pass some data in the dataset to the fragment object after generating the fragment object, this part of code should be placed in the overload of this function. In the subclass we inherit, reload the function and call the fragmentpageradapter. instantiateitem () gets this function and returns the fragment object. Then, we pass the data in the corresponding method of the fragment object, and then return the object.
    • Otherwise, if you place the code for passing data in getitem (), after pageradapter. notifydatasetchanged (), this data setting code will not be called.
  • Destroyitem ()
    • After this function is called, fragmenttransaction. Detach () is performed on fragment (). Here it is not remove (), but detach (), so fragment is still in fragmentmanager management, and the resources occupied by fragment will not be released.


[Fragmentstatepageradapter]


Like the preceding fragmentpageradapter, fragmentstatepageradapter inherits the child pageradapter. However, unlike the fragmentpageradapter, the implementation of this pageradapter retains only the current page, just as the 'state' in its class name indicates, it will be eliminated and its resources will be released. When the page needs to be displayed, a new page will be generated (just like the implementation of listview ). The advantage of this implementation is that when you have a large number of pages, you do not have to use a large amount of memory in the memory.

  • Getitem ()
    • A new virtual function in this class.
    • Function generationNewFragment object.
    • Fragment. setarguments () is a parameter passing code that will only be executed once when the fragment is created, which can be placed here.
    • Because fragmentstatepageradapter. in most cases, instantiateitem () calls getitem () to generate a new object. Therefore, if you place the setter Code related to the dataset in this function, you can basically put it in instantiateitem () executed when called, but this is inconsistent with the design intent. After all, some of them may not call getitem. Therefore, this part of code should be put in instantiateitem.
  • Instantiateitem ()
    • Unless fragmentmanager recovers the corresponding fragment from the savedstate, this function will call the getitem () function to generate a new fragment object. The new object will be fragmenttransaction. Add ().
    • Fragmentstatepageradapter creates a new fragment each time. Instead, it immediately releases its resources to save memory usage.
  • Destroyitem ()
    • Remove fragment, that is, call fragmenttransaction. Remove (), and release its resources.


Discussion

Some solutions have been found before, and some think this is a bug and should be fixed; some suggest switching to fragmentstatepageradapter instead of fragmentpageradapter, and reload getitemposition () and return position_none, to trigger the destruction of objects and recreate objects. From the above analysis, the suggestions provided by the latter can indeed achieve the effect of re-establishing fragment with new parameters after calling yydatasetchanged.

But the problem is, if we can only solve this problem, isn't the fragmentpageradapter useless? The most important thing is that the two correspond to different situations. I still want to save the generated fragment in the memory and call it directly when the page is relatively small, instead of generating or destroying objects, this is more efficient. In this case, selecting the fragmentpageradapter is more suitable, and selecting the fragmentstatepageradapter is not suitable. We cannot discard food for any reason.

Therefore, the solution for fragmentpageradapter is to overload getitem () and instantiateitem () Objects respectively. Getitem () is only used to generate new fragment unrelated to data. The instantiateitem () function first calls instantiateitem () in the parent class to obtain the corresponding fragment object. Then, based on the corresponding data, call the corresponding method of the object to set the data.

Of course, do not forget to reload the getitemposition () function and return position_none, which is required for solutions of both classes. The difference between the two is that the fragmentstatepageradapter will actually release resources in the destroyitem () called because of position_none, and re-create a new fragment; while the fragmentpageradapter will only () the detach fragment in instantiateitem () will use the old fragment and trigger attach, so there is no process of releasing resources and rebuilding.

In this way, when policydatasetchanged () is called, The instantiateitem () will be triggered eventually. No matter whether getitem () is called or not, we are in the overloaded instantiateitem () the function has passed the required data to the corresponding fragment. In the next oncreateview (), onstart (), and onresume () Events of fragment, it can read new data correctly, and fragment is reused successfully.

Note that before fragment is not added to fragmentmanager, we can set parameters through fragment. setarguments () and use getarguments () in fragment to obtain parameters. This is a common parameter transfer method. However, this method is not applicable to the situation we are talking about. This data transfer method can only be used once. After fragment is added to fragmentmanager, once it is used, we call setarguments () Again, which will causeJava. Lang. illegalstateexception: fragment already activeException. Therefore, the parameter transfer method here is to add several setters in the inherited fragment subclass, and then pass the data through these setters. The reverse direction is similar. For more information, see [5]. Oh, do not operate those views in these setters. These views can only be operated after the oncreateview () event.

The solution to fragmentpageradapter is shown in the following code:

@ Override
Public fragment getitem (INT position ){
Myfragment F = new myfragment ();
Return F;
}

@ Override
Public object instantiateitem (viewgroup container, int position ){
Myfragment F = (myfragment) Super. instantiateitem (container, position );
String title = MList. Get (position );
F. settitle (title );
Return F;
}


@ Override
Public int getitemposition (Object object ){
Return pageradapter. position_none;
}

Differences between fragmentpageradapter and fragmentstatepageradapter

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.