Android Fragment Data Dynamic update problem

Source: Internet
Author: User

In an Android app, I use Fragmentpageradapter to handle cross-slide of multiple Fragment pages. But I ran into the problem that when the Fragment corresponding dataset changed, I wanted to be able to trigger the Fragment page to use the new data to adjust or regenerate its contents by calling Madapter.notifydatasetchanged (), but when I called   Notifydatasetchanged () and found nothing happened. After the search found that not only I have encountered this problem, we have given a variety of solutions, some did solve the problem, but I always feel that the problem is not clear. So I decided to figure out what the problem was and what the correct usage was. To understand this problem, it is not enough to read the document, but also to read the implementation of the relevant methods of several related classes to understand its design intent. Here's what you can read through the source code. "Viewpager"
Viewpager is a View that is responsible for paging, as described in its name. It's exactly a viewgroup that contains multiple view pages, which are responsible for switching the view when the finger is sliding horizontally across the screen. To generate these view pages, you need to provide a pageradapter to do and data binding and to generate the final view page.
    • Setadapter ()
      • Viewpager through Setadapter () to establish a connection with Pageradapter. This connection is bidirectional, on the one hand, Viewpager will have the Pageradapter object, so that you can call Pageradapter method when needed, on the other hand, Viewpager will call Setadapter in Pageradapter (). The Registerdatasetobserver () method registers a Pagerobserver object that is generated by itself so that when pageradapter is needed (such as notifydatasetchanged () or Notifydatasetinvalidated (), you can call Observer's onChanged () or oninvalidated () method to enable Pageradapter to send information in viewpager direction.
    • datasetchanged ()
      • Called in Pagerobserver.onchanged (), and Pagerobserver.oninvalide (). So when pageradapter.notifydatasetchanged () is triggered, viewpager.datasetchanged () can also be triggered. The function will use the return value of GetItemPosition () to determine if it is position_unchanged, and if it is Position_none, call Pageradapter.destroyitem () To remove the object and set it to require a refresh (Needpopulate = True) to trigger Pageradapter.instantiateitem () to generate a new object.
"Pageradapter"

PageAdapter is a supporter of Viewpager, Viewpager will call it to get the page you want to display, and PageAdapter will notify Viewpager when the data changes. This class is also the base class for Fragmentpageradapter and Fragmentstatepageradapter. If inherited from this class, you need to implement at least Instantiateitem (), Destroyitem (), GetCount (), and Isviewfromobject ().

    • getitemposition ()
      • This function returns the position of the given object, which is the return value of Instantiateitem (). The return value of the function is judged by the
      • in viewpager.datasetchanged () to determine whether the Pageradapter.instantiateitem () function will eventually be triggered. The implementation of
      • in Pageradapter is returned directly to  position_unchanged. If the function is not overloaded, it will always return position_unchanged, causing viewpager.datasetchanged () to be called when it is not necessary to trigger Pageradapter.instantiateitem (). Many people do not take place after the call to
         pageradapter.notifydatasetchanged () because the function is not overloaded.
    • instantiateitem ()
      • every time Viewpager needs an Object to display, the function will be Viewpager.addnewitem ()   call.
    • notifydatasetchanged ()
      • When the data set changes, the general Activity invokes the PAGERADAP Ter.notifydatasetchanged () to notify Pageradapter, and Pageradapter will notify all  datasetobserver registered here. One of these is the Pageobserver registered in Viewpager.setadapter (). Pageobserver then calls Viewpager.datasetchanged (), which causes the Viewpager to start triggering updates to its included View operation.
"Fragmentpageradapter"Fragmentpageradapter inherits from Pageradapter. This class is more focused on Fragment per page than the generic Pageradapter. As the documentation describes, each generated Fragment within the class will be stored in memory, so it applies to those pages that are relatively static, the number is less, if you need to deal with a lot of pages, and the data is more dynamic and memory-intensive situations, you should use Fragmentstatepageradapter. Fragmentpageradapter overloads implement several necessary functions, so the function from Pageradapter, we only need to implement GetCount (), can. And, because of the implementation of Fragmentpageradapter.instantiateitem (), a new virtual function GetItem () is called, so we also need to implement at least one GetItem (). Therefore, in general, compared to inheriting from Pageradapter, it is more convenient.
  • GetItem ()
    • A new virtual function in the class. The purpose of the function is to generate new  fragment object. You need to be aware of this when overloading the function. When needed, the function is called by Instantiateitem ().
    • If you need to pass a relative static data , we generally Fragment.setarguments (), this part of the code should be put into GetItem (). They are only executed once when the Fragment object is newly generated.
    • If you need to generate a Fragment object, in the dataset is passed to the Fragment, This part of the code is not suitable to be placed in GetItem (). Because when the data set changes, often the corresponding Fragment has been generated, if the passing data part of the code into the GetItem (), this part of the code will not be called. This is also why many people find that after calling Pageradapter.notifydatasetchanged (), GetItem () is not called for a reason.
  • Instantiateitem ()
    • function to determine whether the generated Fragment has been generated, if generated, use the old, the old will be Fragment.attach (), if not, call GetItem () to generate a new, the new object will be Fragmenttransation.add ().
    • Fragmentpageradapter will save all the generated Fragment objects through Fragmentmanager, and will be read from Fragmentmanager when the Fragment is needed, and will not be called again GetItem () method .
    • If you need to pass some data from the dataset to the Fragment after generating the Fragment object, this part of the code should be placed in the overload of the function. In our inherited subclass, overload the function and call Fragmentpageradapter.instantiateitem () to get the function to return the Fragment object, and then we Fragment the corresponding method in the object to pass the data past, The object is then returned.
    • Otherwise, if you put this part of the data passing code into GetItem (), after pageradapter.notifydatasetchanged (), this part of the data set code will not be called.
  • Destroyitem ()
    • After the function is called, the Fragment is Fragmenttransaction.detach (). This is not remove (), only detach (), so Fragment is still in Fragmentmanager management, and the resources that Fragment occupies are not released.
"Fragmentstatepageradapter"Fragmentstatepageradapter, like the previous Fragmentpageradapter, is the successor Pageradapter. However, unlike Fragmentpageradapter, as the "state" in its class name implies, the implementation of the Pageradapter will only retain the current page, and when the page leaves the line of sight, it will be eliminated, releasing its resources, and when the page needs to be displayed, Generate a new page (just like the implementation of a ListView). The benefit of this implementation is that when you have a large number of pages, you do not have to consume large amounts of memory in memory.
    • GetItem ()
      • A new virtual function in the class.
      • The purpose of the function is to generate a new Fragment object.
      • Fragment.setarguments () is a parameter passing code that executes only once when a new Fragment is created, and can be placed here.
      • Because Fragmentstatepageradapter.instantiateitem () will call GetItem () in most cases to generate a new object, if you place the setter code associated with the dataset in the function, you can basically Instantiateitem () is invoked when executed, but this is inconsistent with the design intent. After all, there may be parts that don't call GetItem (). So this part of the code should be put into Instantiateitem ().
    • Instantiateitem ()
      • The function will invoke the GetItem () function to generate a new Fragment object unless it encounters fragmentmanager that the corresponding Fragment is restored from the savedstate. The new object will be Fragmenttransaction.add ().
      • In this way, Fragmentstatepageradapter creates a new Fragment every time, and frees up its resources as soon as it is not used, to save the memory footprint.
    • Destroyitem ()
      • Remove Fragment, call Fragmenttransaction.remove (), and release its resources.
discussion   See some solutions before, some think this is a   bug, should be fixed, some are not fragmentpageradapter, but instead of fragmentstatepageradapter, and overloaded GetItemPosition () and returns Position_none to trigger destroying the object and rebuilding the object. From the above analysis, the latter's recommendations do reach the effect of Fragment being re-established with new parameters after calling Notifydatasetchanged ().   But the question is, if we can only solve this problem, wouldn't it be fragmentpageradapter? The most critical is that they correspond to different situations. For a relatively small number of pages, I still want to be able to save the generated Fragment in memory and call it directly when it needs to be displayed, rather than generating additional overhead to generate and destroy objects, which is more efficient. In this case, choosing  fragmentpageradapter is more suitable, without considering the choice of fragmentstatepageradapter is inappropriate. We are not able to unworthy.   Therefore, the solution for Fragmentpageradapter is to overload the GetItem () and Instantiateitem () objects respectively. GetItem () is used only to generate new data-independent Fragment, whereas the Instantiateitem () function invokes the Instantiateitem () in the parent class to obtain the corresponding Fragment object, and then, based on the corresponding data, Call the method that corresponds to the object to set the data.   Of course, don't forget to overload the GetItemPosition () function and return the Position_none, which is required for this two-class solution. The difference is that fragmentstatepageradapter re-establishes a new Fragment in the real release of resources in the Destroyitem () that triggered the call because of Position_none; Fragmentpageradapter will only detach this Fragment in Destroyitem (), use the old Instantiateitem when Fragment (), and trigger Attach, Thus there is no process of releasing resources and rebuilding them.   So, when noTifydatasetchanged () is called and eventually triggers Instantiateitem (), regardless of whether GetItem () is called, we have passed the required data to the appropriate Instantiateitem () function in the overloaded Fragment. In the event of Fragment next Oncreateview (), OnStart () and Onresume (), it can read the new data correctly, and the Fragment is successfully reused.   Here are a few things to note, before Fragment is added to Fragmentmanager, we can set parameters by Fragment.setarguments () and in Fragment, using Getarguments () to get the parameters. This is a common way to pass parameters. But this approach does not apply to the situation we are talking about. Because this data transfer method can only be used once, after Fragment is added to Fragmentmanager, once used, we call Setarguments again () will cause   Java.lang.IllegalStateException:Fragment already activeAbnormal. Therefore, our choice of parameter passing method is that in the inherited Fragment subclass, a few setters are added, and then the data is passed through these setters. The reverse is similar. The relevant information can be found in [5].   Well, these setters should be careful not to manipulate those view, which can only be manipulated after the Oncreateview () event. The workaround for Fragmentpageradapter is as shown in the following code:
@Overridepublic Fragment getItem (int position) {    myfragment f = new myfragment ();    return F;} @Overridepublic Object Instantiateitem (viewgroup container, int position) {    myfragment f = (myfragment) Super.instantiateitem (container, position);    String title = Mlist.get (position);    F.settitle (title);    return F;} @Overridepublic int GetItemPosition (Object object) {    return pageradapter.position_none;}



Reference   Android Document: [1]  http://developer.android.com/reference/android/support/v4/view/PagerAdapter.html [2]   http://developer.android.com/reference/android/support/v4/app/FragmentPagerAdapter.html [3] /http Developer.android.com/reference/android/support/v4/app/fragmentstatepageradapter.html [4] /HTTP developer.android.com/reference/android/support/v4/view/viewpager.html [5]  http://developer.android.com/ Guide/components/fragments.html#communicatingwithactivity   Android Source code: [6]  http://grepcode.com/file/ Repository.grepcode.com/java/ext/com.google.android/android/4.1.1_r1/android/support/v4/view/pageradapter.java #PagerAdapter [7]  Http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/ 4.1.1_r1/android/support/v4/app/fragmentpageradapter.java#fragmentpageradapter [8]  http://grepcode.com/ file/repository.grepcode.com/java/ext/com.google.android/android/4.1.1_r1/android/support/v4/app/ FragmentstatepageradaptEr.java#fragmentstatepageradapter [9]  http://grepcode.com/file/repository.grepcode.com/java/ext/ Com.google.android/android/4.1.1_r1/android/support/v4/view/viewpager.java#viewpager   Android Issue List: [10 ]  http://code.google.com/p/android/issues/detail?id=19001

Problems with Dynamic update of Android Fragment data

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.