Explanation and usage of fragment in Android _android

Source: Internet
Author: User
Tags rollback

Objective

The Android fragment lifecycle is similar to activity, and may actually involve data transfer, Onsaveinstancestate State preservation, Fragmentmanager management and transaction, Toggle the animation.

Let's start with a brief introduction to the life cycle of fragment.

In general, you can tell by name what each life cycle is.

Appcompatactivity is a subclass of fragmentactivity, and if you want to use fragment, you want to inherit fragmentactivity because of compatibility issues, We want to use Getsupportfragmentmanager, and this method is declared in Fragmentactivity.

There is also a similar approach in activity, Getfragmentmanager, where two methods return Fragmentmanager, but one is the V4 packet.

As for how Android really is for the low version of compatibility fragment This problem, this is not studied, because the source code involved is expected to be a lot, and may be very deep.

How does fragment bind his life cycle and activity together?

Here's a very critical class: Fragmentcontroller.

In the fragmentactivity lifecycle, the Fragmentcontroller corresponding methods are called, and these methods call the corresponding methods of the Fragmentmanager.

Let's look at the OnCreate method of fragmentactivity.

Mfragments.attachhost (null/*parent*/);
Super.oncreate (savedinstancestate);

The Attachhost method is called here, and the Attachhost method calls the Fragmentmanager Attachcontroller method.

Attachcontroller This method, in fact, is the fragmenthostcallback,fragmentcontainer and fragment that need to be passed in.

Fragmenthostcallback is a subclass of Fragmentcontainer, in fact, it is the activity that fragment to attach, it holds the instance of the activity, the context and the handler.

Fragmentcontainer and Fragmenthostcallback are the same example, the activity to be attached.

and fragment passed in is null, the parameter name is parent, here is the activity, so no parent fragment is very normal.

When we use Fragmentmanager, if we want to add fragment, we need to write this:

Fragmentmanager manager = ((fragmentactivity) context). Getsupportfragmentmanager ();
Fragmenttransaction transaction = Manager.begintransaction ();
Transaction.add (fragment, Context.getclass (). Getsimplename ());
Transaction.commit ();

Here comes the new class: Fragmenttransaction.

Fragmenttransaction is used to handle fragment stack operations, the specific subclass is Backstackrecord, and it is also a runnable.

When we call Fragmenttransaction's add, we actually call Backstackrecord's Addop method, OP is a custom data structure:

Static Final class Op {
  op next;
  Op prev;
  int cmd;
  Fragment Fragment;
  int Enteranim;
  int Exitanim;
  int Popenteranim;
  int Popexitanim;
  Arraylist<fragment> removed;
 }

That is, the data structure of the nodes inside the fragment stack.

When we commit, we call the Fragmentmanager Allocbackstackindex, which uses objects internally to ensure the normal write order of the fragment, in fact, Internally, a Backstackrecord ArrayList is used to save the incoming Backstackrecord.

After performing fragment writes, the key step is to call Fragmentmanager's enqueueaction and add our actions to the operations queue.

When you execute this method, you will first check whether you have saved the state, that is, whether you are in the OnStop lifecycle, and if so, you will report the exception information. So we can't do anything about fragment in the onstop of the activity.

Object locks are also used to ensure that the operation is sequential.

The key is to run the Fragmentmanager mexeccommit this runnable, which is mainly to each active fragment as a parameter to movetostate this method, to determine the status of fragment.

The logic here is more complex, comparing the state of the fragment with the mcurstate. The state of every fagment at the beginning of a commit is initializing.

Divided into 2 kinds of situations:

1.mCurState > State

Description fragment start creating.

OnCreate finally invokes the dispatchcreate of Fragmentcontroller and Fragmentmanager, changing the mcurstate status to created, which is also called the Movetostate method, Each fragment state is initializing, it begins to read the saved state and calls fragment Onattach,oncreate,oncreateview and Onviewcreate, respectively.

If the setarguments is not passed before the commit, the invocation of the commit is unreadable. Because the bundle passed over by Setarguments is assigned to fragment marguments when the fragment is initialized, The initialization action of the fragment is performed in the Oncreateview of Fragmentmanager. When we use fragment, we commit them in the oncreate of fragmentactivity, so fragment actually starts initializing at the time of the commit, If placed behind a commit setarguments, there is no chance to pass to fragment.

Here we should note that the above is done in the oncreate of Fragmentactivity, that is, the activity is not created at all, so the resources on the activity are not available here.

2.mCurState < State

Description fragment has been created.

So, fragment real and activity bindings are at the time of the commit call.

It is officially recommended that we pass setarguments to the parameters required by the construction fragment, and it is not recommended to pass the parameters directly through the construction method, because when the screen is switched, it is recreating the new activity, which is recreating the new fragment, The original data will all be lost, but the Setarguments pass bundle will be preserved.

As long as we look at the fragmentactivity OnCreate method, it will determine whether the previous configuration and savedinstancestate are NOT NULL, and Savedinstancestate will save the fragment data, The data is saved as a parcelable, the data is fragmentmanagerstate, and if not NULL, the data is reloaded.

In fact, the graph of the life cycle above is problematic, onactivitycreated is actually called in Fragmentactivity's OnStart, when Mcurstate becomes activity_created, And the fragment state becomes created, then if fragment is not declared in the layout file, using the way of dynamic addition, then fragment is here to invoke Oncreateview and onviewcreated, and add the fragment to the fragmentactivity layout.

First of all, we must be clear, onstart, although the activity is visible, but has not been shown to the foreground, so this time to deal with dynamic add fragment is reasonable, if we put the dynamic add fragment logic in the OnCreate, At that time the activity itself layout has not yet been created, how can you find container load fragment?

This also reminds us not to deal with time-consuming logic in fragment Oncreateview and onviewcreated, otherwise it will affect the time that fragmentactivity is shown to the foreground.

When the fragmentactivity into the Onresume, has been shown to the foreground, this time to send a message to handler, notify Fragmentmanager,mcurstate into resumed, At this point, fragment will begin to set up the listening event.

When the fragmentactivity into the OnPause, will first check whether the fragment has not set up the listening event, if not, let it set up, and then modify mcurstate for started, then belong to the previous second case, Fragment into the OnPause.

When fragmentactivity into the OnStop, first notice Fragmentmanager modify mcurstate for stopped, then will notify fragment into OnStop, then is handler received message, Notify Fragmentmanager will change Mcurstate to activity_created, notify fragment call Performreallystop, which is the real end.

When Fragmentactivity enters the OnDestroy, it confirms that the reallystop is true and then notifies Fragmentmanager to modify mcurstate for created, When the fragment state is activity_created, the view data is saved, the Ondestroyview is invoked, and the parent layout begins to remove the fragment.

Take a closer look at this logic, you will find that, regardless of whether there is a set fragment need to be retained, will enter the Ondetach, indicating that the fragment and fragmentactivity are no longer associated.

Let's take a look at Onretainnonconfigurationinstance this method, which sets fragment mretaining to True, so that fragment does not enter OnDestroy, Even if you recreate the new fragmentactivity, just clear the fragment Mhost,mparentfragment,mfragmentmanager and Mchildfragmentmanager, The previous data is saved and the fragment is not destroyed, which leads to the problem that the recreated fragmentactivity itself creates a new fragment, so there will be fragment overlap, Because then fragment state is stopped, will enter OnStart and Onresume respectively, that is, the process of showing back to the foreground.

In the actual test, we will find that in the case of no processing, the Fragmentmanager in the fragment is more and more, so in fact, consider this situation: application in the background if killed, restart the application, The previous fragment may overlap the interface.

This situation is more troublesome when handling tab, because the tab is several fragment at the same time, if the activity is killed, recreated, enter the first fragment, but if this time is under another fragment was killed, Can cause these two fragment to overlap.

Therefore, you can determine whether to re-create the activity in OnCreate, as long as you determine whether savedinstancestate is NULL, or NULL, if the activity has not been rebuilt, you can add fragment, Even the above tab can be handled as long as the first fragment is not added.

If this is based on such a judgment to solve this problem, we can also add fragment, specify an ID or tag, determine the corresponding ID in Fragmentmanager or whether the tag fragment exists to determine whether to add.

Of course, if the project is really not needed, we can force the vertical screen.

If you are only switching against the screen, there is another solution, set in the corresponding Activity tab in Androidmanifest, android:configChanges="orientation|keyboardHidden" but this attribute is not valid on Android 4.0, it must be written in this way: android:configChanges="orientation|keyboardHidden|screenSize" . In this way in the screen switch, will not walk onretainnonconfigurationinstance, go is onconfigurationchanged, switch will not destroy the current fragmentactivity, Natural fragment can also be maintained.

If we want to add a cut to the fragment, there are two ways to V4 and not V4.

1. For V4, the use of view Animation, animation resources in the Res\anim\ directory.

2. For V4, the use of property animation, animation resources in the Res\animator\ directory.

Generally we are using V4 fragment, and for the Transition animation, view animation is enough to meet our requirements.

Let's take a look at the Fragmenttransaction Addtobackstack method.

If we want to achieve this effect: Click the Return key and return to the previous fragment. Then you have to call Addtobackstack this method. This method requires passing in a string parameter, in fact we just pass in null on the line, if we don't want to specify the name of the stack (although the stack is actually just a ArrayList and does not implement the stack's structure).

Looking carefully at the source, we will find that if you do not call this method, in the press the return key, directly finish the current fragmentactivity.

There is a big difference between fragment's fallback and activity's fallback, and we know that fragment's operation is Fragmenttransaction, and Backstackrecord is really the specific subclass of these operations.

This is the problem: if we are two times Fragmenttransactiont add fragment, first add a, second add B and C, we return not fragment, is Backstackrecord op, The OP records the fragment of each operation, and when we roll back the second time, it is the second addition of both B and C out.

If we only have a fragment, and do not want to implement the fragment back stack, do not call addtobackstate, otherwise, when the activity presses the return key, will not immediately quit the activity, but return a blank, Because even null is added to the ArrayList of Backstackrecord, because this parameter is labeled Backstackrecord as Mname, it is not important in actual processing whether it is null or not.

Of course, we can also call the Fragmentmanager Popbackstack method to do the rollback stack operation, if we want to execute immediately, we will call the Popbackstackimmediate method, in fact, the default call is this method.

If we add fragment, and do not set any tag, but in the pop-up stack, the request to pop up the latest fragment, add new fragment.

The fragment stack is not as complex as the activity stack, providing a variety of startup modes, and if you look at the source, you'll find that there is actually only one thing: Pop up all the fragment in the nearest Backstackrecord.

If we call Popbackstack, do not specify flag as pop_back_stack_inclusive, the implementation of the source code although the If-else is divided into two kinds of judgments, but the actual processing is similar, but not specified, It will deal with more trouble, if possible, we still specify.

Back to the question above us, how do we do it?

Replace does not affect the fallback stack, if we really want to replace a fragment with replace, and want to implement the rollback stack, we need to addtobackstack, but if we want to replace a fragment, The records in the rollback stack are not replaced, that is, when we opt for a fallback, we return to the fragment we replaced, so we have to pop this fragment before we replace it.

Fragmentmanager provides a Getbackstackentrycount method that tells us the number of fallback stacks, as well as the Getbackstackentryat method to obtain the corresponding Backstackrecord, Then we can do the following to implement the pop-up:

if (Manager.getbackstackentrycount () >0) { 
 int n = manager.getbackstackentrycount ();
 Manager.popbackstack (Manager.getbackstackentryat (n-1). GetName (), fragmentmanager.pop_back_stack_inclusive);

Then we can use the Replace.

We must note that Add,remove and replace affect the display of fragment on the interface, they have nothing to do with the fallback stack, in fact, if we do not call Addtobackstack, there is no fallback stack, And the fallback stack is added one after each invocation of the method, regardless of whether it is duplicated, and it does not make any judgments, so if a fragmenttransaction commits multiple fragment, but only one addtobackstack is invoked, Although there are multiple fragment on the interface, there is only one record in the fallback stack.

Fragment said to the end, in the source view, just and activity lifecycle synchronization of the view, it is impossible to do with the activities of the same complex function, any of its logical business code, actually belongs to the activity, but moved to another class, of course, If you want to, even if it is a lightweight viewcontroller is also possible, after all, it is responsible for their own view of all business functions.

Fragmenttransaction provides fragment with add,remove,hide,show and replace operations, and we need to be aware of the difference between add and replace.

Replace is actually a combination of remove + add, and with replace, each switch will cause fragment to be recreated because it will remove the replaced fragment from the view so that when the replacement comes back, it will be recreated.

This frequent switching can have a severe impact on performance and traffic.

So, officially, replace() This approach is simply a simple way to use when the last fragment is no longer needed.

The correct way to switch is add() to switch to another fragment when you switch hide() add() again, just the current one, and the hide() show() other.

Of course, before we hide, we need to use Isadd to determine whether we have added it.

If we switch between hide and show, we don't need to save the data because the fragment is not destroyed, and if it's replace, we're going to save the data, for example, if there's a edittext in the interface, If we want to save the input before edittext, we need to save this value, otherwise we will remove the entire view if we use Replace.

Fragment also involves communication with activity and other fragment.

The best way is to just let the activity and the fragment communicate, and if fragment wants to communicate with other fragment, it has to go through the activity.

We can use callback fragment to communicate, of course, we can also declare the interface in fragment, as long as the activity to implement these interfaces, can achieve activity and fragment communication.

Think of setarguments is the form of bundle to save data, then we can use this, to do a little article on the reference?

In software design, in order to reduce reliance, it is proposed to use a high-level abstraction to take charge of communication between components, so that each component does not need to rely on each other, that is, the so-called dependency inversion principle.

So, can we also use this principle to do something about it?

The expression of dependency inversion in many frameworks is in the form of annotations, and we can consider the annotations to solve this problem.

If only the parameters that are transmitted for the purpose of constructing the fragment, the problem is relatively simple, as long as the reflection is reasonable, we can get to the Fragment field and assign the value.

Similar representations are as follows:

Class Fragmenta extends fragment{
  @Arg
  private int age;
  public void OnCreate () {
   fragmentinject.inject (this);
  }
}
Class Activitya extends activity{public
  
  voi onCreate () {
   Fragmenta a = new Fragmenta ();
   Bundle Bundle = new Bundle ();
   Bundle.putstring ("text", "Hello");
   A.setarguments (bundle);
   Fragmentmanager manager = Getsupportfragmentmanager ();
   Fragmenttransaction transaction = Manager.begintransaction ();
   Transaction.add (R.id.container, a);
   Transaction.commit ();
  }

In fact, this is nothing more than a change in the way the code is organized, because we can get bundle in fragment's OnCreate, we can do the same thing, and there will be less total code, but if it's purely from fragment, We only need to call the Fragmentinject.inject method and declaration arg annotation, other things do not have to consider, the relevant parsing bundle and field assignment are placed in the Fragmentinject abstract, we do not have to write the same code for each fragment, as long as the FRA Gmentinject on the line.

Of course, the above is just a simple implementation, really is to achieve a mature thing is to consider a lot of aspects, we put this simple project on the GitHub: Https://github.com/wenjiang/FragmentArgs.git, if there are new ideas, welcome to add.

Summarize

The above is the entire content of this article, I hope the content of this article for everyone's study or work can bring certain help, if you have questions you can message exchange.

Related Article

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.