Android Combat tips: fragment of those pits

Source: Internet
Author: User

Original address: http://toughcoder.net/blog/2015/04/30/android-fragment-the-bad-parts/?utm_source=tuicool&utm_medium= Referral

Fragment is a UI component of Android that was added to the 3.0 (Homeycomb) version for more flexibility in building a multi-screen interface. For fragment, you can refer to the official tutorials and best practices for basic usage, and choose activity or fragment. But fragment use is far less simple than the tutorial said, also far more complex than the activity, here summed up the solitary in the use of fragment encountered in the pit.

Duplicated ID or tag itch when nesting fragment

This is a small pit, but beginners are very easy to encounter, especially in the fragment with fragment, and the layout of the addition of sub-fragment is more easily encountered.

Phenomenon:

The fragment has another fragment that throws an exception when the second time it enters the parent fragment or the interface created by fragment, roughly meaning that the ID or tag of the child fragment is duplicated. If you add an ID or tag to the child fragment in layout, you are bound to encounter this exception.

Reason:

You can specify an ID or tag for fragment to identify this fragment when adding fragment. Because the fragment attached to each activity is placed in an object pool, fragment is still in the pool during the activity's life cycle, The pool is managed by Fragmentmanager, even if a fragment is detach from the activity (that is, Fragmentmanager pops off). When you want to add fragment with an ID or tag again, Fragmentmanager will retrieve it in the pool, and if it finds an existing fragment object with this ID or tag, it will throw the exception and complain about the duplicate ID. The purpose of this is to reduce the creation of objects and to reuse objects as much as possible.

How to hack:
    1. When writing fragment in the layout, do not add ID or tag;
    2. If you want to add an ID or tag, add fragment in your code, such as using ID or tag, first go to Fragmentmanager to find whether the object exists, and then create it when it does not exist, that is:

        Fragment target = getFragmentManager().findFragmentByTag("tag");  if (target == null) {      targe = new SomeFragment();  }  FragmentTransaction ft = getFragmentManager().beginTransaction();  ft.add(R.id.content, target, "tag");  ft.commit();
Replace the pain phenomenon:

When there are two of the same overall page cascade, want to put the last layout of a fragment to replace, you will find that it put the previous replace, the back of no effect.

Reason:

The ID of the layout is unique within a form (Activity), and fragment's replace uses this unique ID to replace the corresponding layout with fragment. When the same page is stacked, the layout of the same ID appears two times, but the ID is the same. So fragmenttransaction replaced only one at replace. Instead of replacing the last page as expected.

How to hack:

If the same page does not want to cascade, either do not use fragment, or set a different ID for the layout. This is often the case when the layout is reused, such as a two-page long image, so the same overall layout is reused. But the actual logic is not the same page, you can set a different ID for the layout.

The phenomenon of visible pain:

How each fragment can perceive the visibility of a user when multiple fragment are stacked together. For example, the application has three pages, a, B and C, such as a is the overall category list, B is the details of each category, C is a kind of more detailed information about the category, when C is displayed, how can I know that it is actually not visible to the user, so you can not refresh, do not load data and so on. When C is back by the user, how does b feel it becomes visible?

Reason:

The fragment life cycle is the same as the activity, and adding to the activity will go through the oncreate similar callbacks, and then, when the activity onresume/onpause/onstart/onstop, The fragment that it holds also go the corresponding onresume/onpause/onstart/onpause. But fragment is very different from activity, when activity is shown by another activity, the current activity goes onpause/onstop, and fragment is completely unaware. At most can only from Fragmentmanager there know backstackstate change, but is fragment increased, or decreased, and can not know.

How to hack:

This is a very painful problem, the simple page is OK, but it involves data loading or for some events (network) to refresh the problem, the user is not visible to the page does not need to refresh. The feasible solution is:

    1. Monitor the change of Fragmentmanager backstackstate
    2. Define the page path depth and then compare it to the backstack depth to see if it is visible to the user as the previous a is level and whose path is 1,b is 2,c is 3. The current stack depth is 3 o'clock, C is visible, A and B are not visible, and so on.
The click of the pus in the blank area:

A fragment, stacked on top of another fragment or activity, with some white space in the fragment, or an empty area outside the widget, When you click on these blank areas, the fragment below fragment or the Activity view receives the event and responds to the Click event.

Reason:

The essence of fragment is the manager of a view layout, and when fragment attach to the activity, it is actually replacing the view returned by Fragment#oncreateview () (if it is with replace) The view specified in Fragmenttransaction#replace, or added to the viewgroup specified in (if add) Fragmenttransaction#add ().

When we cascade multiple fragment, it's common practice to get a framelayout, and then add fragment to the layout every time. Thus, the activity's page layout tree is actually a framelayout containing several view.

So, when you click on the blank area of the fragment above, if the event is not eaten, it will pass down.

How to hack:

In the fragment root layout plus a clickable=true, this causes the root layout to eat the Click event to prevent the event from continuing, resulting in the above situation.

Activity re-creation of the phenomenon:

There is no general error, there is only a specific error exception associated with the project, or the page is not displayed correctly. And why the tutorial has a sentence like this:

123456        
  @Override oncreate (bundle savedinstance { if  (savedintance == null) { //Create fragment and add it to Activity. Span class= "o" >}}          
Reason:

Activity in addition to the normal start to go to OnCreate, there are other entrances, such as the system configuration information changes, or activity in the depth of the stack, the system will kill the activity, and then re-create it, the problem is to recreate it. Re-creation is different from creating a new activity, which is to restore the previous state as much as possible, because it is transparent to the user, that is, it is not perceived by the user, otherwise the experience is quite poor. The only difference from regular creation is that the parameter passed to OnCreate is savedinstancestate null.

How to hack:

In order to recover the status when the activity is rebuilt, you need:

    1. For activity

      To save some variables at onsaveinstancestate (), then restore them at OnCreate

    2. For fragment

      Tell the system that you want to restore state fragment#setretaininstance (true). The state is then saved in Onsavedinstance () and resumed at OnCreate. That's enough, the system will also create the fragment it holds when it re-creates the activity. So why each fragment subclass needs to define a default constructor. You can refer to this article for more information.

The fragmenttransaction of the asynchronous operation

The fragmenttransaction is asynchronous, and commit () is just the equivalent of adding the operation to the Fragmentmanager queue, and then the Fragmentmanager is executed at some point, not immediately. So, when you really start executing commit (), if the activity's life cycle changes, such as go to OnPause, or go to the onstop, or OnDestroy all gone, then will be reported IllegalStateException.

Another reason for Asynchrony is to manipulate (display) Fragment in async. For example, the first to go to the network to request data, and then according to the data display a fragment, this particularly prone to the situation is the network request back, but the activity is no longer, then if the commit will also report illegalstateexception.

For specific reasons, and how to avoid this article you can refer to Daniel.

The common solution is suggested by the author: 1. Be careful to commit in the life cycle. 2 Try not to commit in an asynchronous callback another solution is

    • Determine if activity is being destroyed in an asynchronous callback, isfinishing, if true, stop doing other things
    • Control asynchronous tasks as much as possible within the life cycle of the activity (onstart->onstop). Terminates the asynchronous task when stop occurs. Starts again when start again.

      But this does not apply to all situations. For example, in the case of home, this process usually does not need to stop the task. Because normally, when you cut back, the application should keep the state of the cut, for example, load a data, press home to cut away, and then come back when it should be loaded complete. This is also a manifestation of the multitasking system. If you stop a task while onstop, you have to do a lot of work to restore the state when you onstart.

    • Using Commitallowstateloss () This is the final solution. This is the only way except to avoid the design.
The disgusting activity rebuilds and restores its fragment

First of all, the very disgusting thing about Android is that in some cases the system kills the activity and then re-creates it and tries to restore its previous state, such as when the screen is rotated, when the system language changes, when the activity in the stack is recycled, to the top of the stack, and so on, it's disgusting, Often cause problems. The method of identifying the rebuild and new is to see if the bundle parameter in OnCreate is null.

For fragmentactivity, even more disgusting, when this scenario is onsaveinstance, it saves the fragment and then re-creates it at OnCreate, calling Framgment's default parameterless construct to create the fragment object. So that's why the document says fragment must have a default constructor, and it's best not to have a constructor with parameters, and to use setarguments to pass parameters. The reason for the default constructor is to rebuild the fragment instance. The setarguments argument is that a bundle will also follow the fragment to save it and restore it when rebuilding fragment. The preservation of the recovered state data here is stored in the system by binder, which also explains why the parameter is not a bundle.

So what happens when you really need a constructor with parameters, or that the system can't help you rebuild fragment (such as fragment to get from a dynamically loaded dex)?

First, we want to simulate this scenario, the most convenient thing is to remove the activity configchanges, and then rotate the screen.

One idea is to stop the system from recovering fragment, and we can load it ourselves, because the rebuild will go to the oncreate of the activity, so we have reason to go through the initialization process again. How to stop it is to remove the fragment from the Fragmentmanager before fragmentactivity save all fragment states.

1234567     
@OverridePublicvoidonsaveinstance (bundle out) Span class= "o" >{ fragmenttransaction ft = getsupportfragmentmanager ().  ft. (frag ft. super. (out               /span>                 

Android Combat tips: Fragment of those pits (go)

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.