preface
Series of articles:
Android Activity to interact with the View of thinking Android Activity life cycle, and to monitor the Android onSaveInstanceState/onRestoreInstanceState originally to be understood What does Android Fragment want you to use?
There have been many excellent articles about Fragment analysis on the Internet. Some people feel that its life cycle is complicated and difficult to control. Some people think it is a “lightweight Activity” that is well packaged and worth introducing in projects. Through this article, you will learn:
1, Why is a Fragment needed? 2, How to add a Fragment? 3, How to connect an Activity to the Fragment life cycle
1、为什么需要Fragment
Fragments defined
Fragment; Fragment; Fragment; Fragment Originally introduced in Android 3.0, it provides a flexible UI component for applications that can be adapted to larger screen devices.
Fragment relationships with Views and Activities
And comparison of the View
1. Have a lifecycle. 2. Encapsulate View(UI) and logic in fragments. 3, Other activities can reuse Fragment(UI + logic).
And comparison of the Activity
We often say that activities are “heavy” and views are “light”. This is easy to understand. Think about it: Starting an Activity is much slower than displaying a View. Why is that? Because an Activity is controlled by AMS, its life cycle is notified to the App process by AMS across processes, which obviously takes a lot of time. Plus there are many things initialized when the Activity starts, such as Windows, DecorView, and so on, so it takes a while for the Activity to be fully displayed. And View is different, just need to new an object, and set some properties, and finally add to the upper ViewGroup for display, are in this process operation, very fast. Like a View, when you add a Fragment to an Activity, you actually do two things:
1. Add it to Fragment stack for easy management. 2. Add the View held by the Fragment to a node in the ViewTree.
As you can see, the above two steps don’t involve interprocess communication and don’t initialize many components, so starting a Fragment is much faster than starting an Activity.
The three relations
Illustrate the connection between the three:
Fragment is not an Activity subclass or a View/ViewGroup parent or subclass.
2. Method of adding fragments
Static add mode
Now that you know the Fragment feature, see how you can use it. Similar to views, views can be loaded statically in XML or dynamically in code. Let’s start with static loading. Write a static layout file: activity_static_fragment.xml:
<? The XML version = "1.0" encoding = "utf-8"? > <com.example.androiddemo.fragment.MyFrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent"> <fragment android:id="@+id/static_fragment" android:name="com.example.androiddemo.fragment.MyFragment" android:layout_width="match_parent" android:layout_height="100dp" tools:ignore="Instantiatable"> </fragment> </com.example.androiddemo.fragment.MyFrameLayout>Copy the code
Android :name Specifies the fully qualified class name of the Fragment. MyFragment is a custom Fragment. Then load the layout file in the Activity onCreate:
setContentView(R.layout.activity_static_fragment);
Copy the code
Adding a View statically is similar to adding a View statically.
Principle of static addition
As mentioned in the previous section, the Fragment manages the layout file and adds it to the ViewTree. To declare a custom Fragment, override the onCreateView(xx) method:
@Override public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) { TextView textView = new TextView(getContext()); If (textutils. isEmpty(desc)) desc = "Static fragment"; textView.setText(desc); textView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); return textView; }Copy the code
This method can be interpreted as a Fragment specifying the layout it hosts, where a TextView object is constructed and returned.
The string static loading process is as follows:
1. Activities load layout files using LayoutInflater. 2. LayoutInflater looks for “fragment” tags. 3. Find the “Fragment” tag and reflect the fully qualified name of the fragment class specified by “Android :name” to instantiate it. 4. After retrieving the Fragment instance, call onCreateView(xx) to associate the View object with the Fragment. 5. View objects are added to the parent layout of the “fragment” tag. In this case, MyFrameLayout. 6. The View associated with the Fragment has been added to the ViewTree.
Fragment is not a subclass of Activity/View,
Add a View to a ViewTree
#FragmentManagerImpl.java void ensureInflatedFragmentView(Fragment f) { if (f.mFromLayout && ! F. PerformedCreateView) {// Finally execute to fragment.oncreateView () // assign the returned View object to f.view f.performCreateView(f.performGetLayoutInflater( f.mSavedFragmentState), null, f.mSavedFragmentState); if (f.mView ! = null) { ... OnViewCreated (xx).onViewCreated(f.view, f.savedFragmentState); } else { f.mInnerView = null; }}}Copy the code
Fragment stores the associated View in the F.View. LayoutInflater adds the F.View to the upper ViewGroup when loading. Finally, the F.View is attached to the ViewTree.
Dynamic add mode
private void addFragment(Fragment fragment) { // list.add(fragment); / / get fragments managed object FragmentManager FragmentManager = getSupportFragmentManager (); FragmentTransaction transaction = fragmentManager.beginTransaction(); // Start a fragment transaction // Add (R.i container, fragment); // Submit the action transaction.com MIT (); }Copy the code
Encapsulate an addFragment(xx) method and pass in the constructed Fragment. This method is then called in the Activity’s onCreate(xx)
@Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_fragment); AddFragment (new MyFragment("fragment1")); }Copy the code
Principle of Dynamic addition
1, obtain fragments controller look getSupportFragmentManager () :
#FragmentActivity.java
public FragmentManager getSupportFragmentManager() {
return mFragments.getSupportFragmentManager();
}
Copy the code
And mFragments are member variables of FragmentActivity.java:
#FragmentActivity.java
final FragmentController mFragments = FragmentController.createController(new HostCallbacks());
Copy the code
The final return is the FragmentManagerImpl instance. As you can see from this, every class that directly or indirectly inherits from FragmentActivity.java will have a FragmentController member variable, from which obtaining an instance of FragmentManagerImpl controls all Fragment activities.
2, Fragment associated View
transaction.add(R.id.container, fragment);
Copy the code
The first parameter indicates the ViewGroup to which the Fragment is to be attached. The second parameter indicates the Fragment object to be attached. When fragment.onCreateView (xx) is called, the returned View will be added to the ViewGroup represented by R.I.C.ontainer. R.i. D.c. Ontainer is the ID of a layout in the Activity layout file. At this point:
The View associated with the Fragment is added to the ViewTree.
Add View to ViewTree
#FragmentManagerImpl.java void moveToState(Fragment f, int newState, int transit, int transitionStyle, boolean keepActive) { ... // Execute fragment.onCreateView (xx) // assign the returned View to f.view, F Fragment object f.p erformCreateView (f.p erformGetLayoutInflater (f. may SavedFragmentState), container, f.mSavedFragmentState); if (f.mView ! = null) { f.mInnerView = f.mView; f.mView.setSaveFromParentEnabled(false); // Container is an instantiation of R.D.C. tainer in the ViewGroup //transaction.replace(R.D.C. tainer, fragment) method. = null) {// Add the Fragment. OnCreateView (xx) View to the container, i.e. add the View to the ViewTree. container.addView(f.mView); }... } else { f.mInnerView = null; }... }Copy the code
Note that in onCreateView(xx) we are creating views on the fly and loading layout files using LayoutInflater:
@Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {// View View = infler.inflate (r.layout. fragment_layout, container,false); return view; }Copy the code
So the last parameter must be false, the meaning is not the generated View and add into the container, because in FragmentManagerImpl. MoveToState also can perform the container (xx). The addView (View), If the final argument is true, a repeat addition error is reported.
3. Linkage between Activity and Fragment life cycles
By analyzing static and dynamic addition, we have figured out how views associated with fragments are added to a ViewTree. We then analyze the flow of the Fragment life cycle between static and dynamic additions.
The origin of the Fragment lifecycle
Fragment depends on Activity, so we take it for granted that its lifecycle depends on Activity. What is the truth? To find the truth, start with the source code. Take activity.onresume () as an example to explore the relationship with fragment.onresume (). When activity.performResume (xx) is called, the following source code is available:
#Activity.java final void performResume(boolean followedByPause, String reason) { ... onPostResume(); . } #FragmentActivity.java protected void onPostResume() { super.onPostResume(); onResumeFragments(); } #FragmentActivity.java protected void onResumeFragments() { mFragmentLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME); / / mFragments eventually controlling the Fragment lifecycle mFragments dispatchResume (); }Copy the code
As you can see, since custom activities inherit directly/indirectly from FragmentActivity, and FragmentActivity overrides many Activity methods, Therefore, whenever the activity.xx () method is called, the corresponding method of the FragmentActivity override is called, and that override method ultimately controls the Fragment lifecycle callback methods through mFragments(FragmentController controller). To sum up:
The Fragment life cycle depends on the Activity life cycle. 2, change the Activity lifecycle callback methods onCreate/onStart/onResume/onPause, onStop/onDestroy, fragments, fragments is more than the Activity callback methods, So onAttach, onCreateView, etc.
Add the Fragment life cycle statically
As illustrated:
As can be seen from the figure:
The Fragment method is called when the Activity life cycle changes, so the Fragment also has an indirect life cycle.
Obviously, the Fragment life cycle involves more methods than activities. Briefly explain the usefulness of each method involved:
1, onAttach
Fragment binds the Context for the first time. When using fragment.getContext ()/ fragment.getActivity () returns the bound >FragmentActivity.
2, the onCreate
Similar to Activity onCreate.
3, onCreateView
Associate the Fragment with the UI. The display effect of the Fragment is displayed through the UI.
4, onViewCreated
The View created in step 3 has been added to the ViewTree.
5, onActivityCreated
Indicates that the Activity and Fragment are fully bound.
OnDestroyView, onDetach, and so on are the reverse operations without going into detail.
Dynamically add the Fragment life cycle
In theory, the lifecycle is the same for static or dynamic additions, so why distinguish? As we mentioned before, there is a method that focuses on dynamic addition:
transaction.commit();
Copy the code
This method has a twin:
transaction.commitNow()
Copy the code
As the name implies, transaction.commitNow() means add now, with the same lifecycle as static add. While transaction.com MIT () is queued and delayed, the lifecycle is as follows:
Because of the delay, some column operations such as fragment.onattach () are not performed at activity.oncreate (xx), but after activity.onstart (). Except for that difference, everything else is the same.
4. Common methods for controlling fragments
It relies primarily on FragmentTransaction to control fragments. 1, FragmentTransaction. Hide (xx)
View. SetVisibility (GONE) Hide the View associated with the Fragment.
Methods in the Fragment life cycle are not called back.
2, FragmentTransaction. Show (xx)
View. SetVisibility (VISIBLE) Display a Fragment, essentially displaying the View associated with the Fragment: view.setvisibility (VISIBLE)
Methods in the Fragment life cycle are not called back.
3, FragmentTransaction. Detach (xx)
Removing a Fragment from an Activity removes the View associated with the Fragment from the ViewTree. Fragment is still on the stack.
The lifecycle changes are as follows:
4, FragmentTransaction. Remove (xx)
In addition to removing the Fragment from the Activity, remove the Fragment from the rollback stack.
The lifecycle changes are as follows:
5, FragmentTransaction. Replace (xx)
Same effect as remove + add.
The current display fragment1, through FragmentTransaction. Replace (fragment2), life cycle changes are as follows:
An Activity passes data to a Fragment, essentially passing the Bundle. Fragments. SetArguments (Bundle). Get this in Fragment: fragment.getarguments (). Of course, Jetpack was introduced to share data through the ViewModel.
Finally, the Demo renderings are attached
Fragment Adds/removes/replaces/hides test code
This article is based on Android 10.0
If you like, please like, pay attention to your encouragement is my motivation to move forward
Continue to update, with me step by step system, in-depth study of Android
4, View Measure/Layout/Draw 5, Android events distribution of full service 6, Android invalidate postInvalidate/requestLayout thoroughly clarify 7, how do you determine the Android Window size/onMeasure () to be executed multiple times Android event driver Handler-message-Looper 9, Android keyboard in one move 10, Android coordinates completely clear 11, Android Activity/Window/View background Android IPC series 14, Android Storage series 15, Java concurrent series no longer confusion 16, Java thread pool series 17, Android Jetpack Practice and Principle series