This article is a series of articles, I am in the long-distance development of Android a little thoughts and records, I will try to follow the first easy after the difficult sequence to write the series. The series cited the "Android Development art exploration" and "in-depth understanding of Android volume Ⅰ,ⅱ,ⅲ" in the relevant knowledge, in addition to learn from other high-quality blog, here to the great God to thank you, worship!!!
Objective
The previous article detailed analysis of fragment related knowledge, then as "small activity", what can fragment do, how to use fragment to get the best practice. Fragment's design may have been designed primarily for the needs of large-screen tablet devices, but now fragment is widely used in our regular mobile devices. is a feature that we can find in almost every major app.
Friends who are familiar with Android will know, very simple, use tabhost is OK! But as everyone knows, tabhost is not so simple, its extensibility is very poor, can not arbitrarily customize the contents of the tab display, but also depends on the operation of Activitygroup. Activitygroup was originally used primarily to manage a single activity for each of the Tabhost's children, but it is now obsolete. Why is it? Of course, it's because of fragment's appearance!
Well, the following I will come to realize the effect, but before you start, you must already understand the use of fragment, if you are more unfamiliar with fragment, suggest first read my previous article on Android development long-distance xii--fragment detailed
Create the host activity first
New bestfragmentactivity
public class Bestfragmentactivity extends appcompatactivity {@Override protected void onCreate (Bundle savedinstance State) {super.oncreate (savedinstancestate); Setcontentview (r.layout.activity_best_fragment); The following is the use of luseenbottomnavigation bottomnavigationview Bottomnavigationview = (bottomnavigationview) findViewById ( R.id.bottomnavigation); Bottomnavigationitem Bottomnavigationitem = new Bottomnavigationitem ("Home", Contextcompat.getcolor (this, R.colo R.firstcolor), R.MIPMAP.IC_ACCOUNT_BALANCE_WHITE_48DP); Bottomnavigationitem bottomNavigationItem1 = new Bottomnavigationitem ("Classification", Contextcompat.getcolor (this, r.col Or.secondcolor), R.MIPMAP.IC_LIST_WHITE_48DP); Bottomnavigationitem bottomNavigationItem2 = new Bottomnavigationitem ("task", Contextcompat.getcolor (this, r.col Or.firstcolor), R.MIPMAP.IC_ADD_CIRCLE_OUTLINE_WHITE_48DP); Bottomnavigationitem bottomNavigationItem3 = new Bottomnavigationitem ("Shopping Cart", Contextcompat.getcolor (this, r.color.thirdcolor), R.MIPMAP.IC_ADD_SHOPPING_CART_WHITE_48DP); Bottomnavigationitem bottomNavigationItem4 = new Bottomnavigationitem ("My", Contextcompat.getcolor (this, r.col or.coloraccent), R.MIPMAP.IC_ACCOUNT_BOX_WHITE_48DP); Bottomnavigationview.addtab (Bottomnavigationitem); Bottomnavigationview.addtab (BOTTOMNAVIGATIONITEM1); Bottomnavigationview.addtab (BOTTOMNAVIGATIONITEM2); Bottomnavigationview.addtab (BOTTOMNAVIGATIONITEM3); Bottomnavigationview.addtab (BOTTOMNAVIGATIONITEM4); }}
The corresponding layout file activity_best_fragment
<?xml version= "1.0" encoding= "Utf-8"? ><relativelayout xmlns:android= "http://schemas.android.com/apk/res/ Android "xmlns:app=" Http://schemas.android.com/apk/res-auto "android:layout_width=" Match_parent "Android:layout_h eight= "Match_parent" android:id= "@+id/main_content" android:fitssystemwindows= "true" > <!--fragment after the dynamic In the layout file--<framelayout android:id= "@+id/frame_content" android:layout_width= "Match_parent" android:layout_height= "Match_parent" android:scrollbars= "None" android:layout_above= "@+id/bottomnavigation "/> <!--about the underlying layout I used the open source project on GitHub--<com.luseen.luseenbottomnavigation.bottomnavigation.bottomna Vigationview android:id= "@+id/bottomnavigation" android:layout_width= "Match_parent" android:layout_he ight= "Wrap_content" android:layout_alignparentbottom= "true" app:bnv_colored_background= "false" app:bn V_with_text= "true" app:Bnv_shadow= "false" app:bnv_tablet= "false" App:bnv_viewpager_slide= "true" app:bnv_active_color= "@color /colorprimary "app:bnv_active_text_size=" @dimen/bottom_navigation_text_size_active "App:bnv_inactive_text_si Ze= "@dimen/bottom_navigation_text_size_inactive"/></relativelayout>
About the underlying layout I used the open source project Luseenbottomnavigation on GitHub, the project address is Https://github.com/armcha/LuseenBottomNavigation readers can see for themselves
Then create the Fragment
Currently fragment as a demonstration to use, you can see the layout of the contents are very simple, I here only give one of the fragment of the creation process and source code, the project complete source code visible at the end of the source address.
We'll take the first goodsfragment example
public class Goodsfragment extends Fragment {private static String tag= GoodsFragment.class.getSimpleName (); @Override public void Onattach (context context) {Super.onattach (context); LOG.D (TAG, "Onattach"); } @Nullable @Override public View oncreateview (layoutinflater inflater, ViewGroup container, Bundle savedinstance State) {LOG.D (TAG, "Oncreateview"); View view = Inflater.inflate (r.layout.fragment_goods, NULL); return view; } @Override public void onviewcreated (view view, @Nullable Bundle savedinstancestate) {super.onviewcreated (v Iew, savedinstancestate); LOG.D (TAG, "onviewcreated"); } @Override public void onactivitycreated (@Nullable Bundle savedinstancestate) {super.onactivitycreated (save Dinstancestate); LOG.D (TAG, "onactivitycreated"); } @Override public void OnCreate (@Nullable Bundle savedinstancestate) {super.oncreate (savedinstancestate); LOG.D (TAG, "oncrEate "); } @Override public void OnStart () {Super.onstart (); LOG.D (TAG, "OnStart"); } @Override public void Onresume () {super.onresume (); LOG.D (TAG, "Onresume"); } @Override public void OnPause () {super.onpause (); LOG.D (TAG, "onPause"); } @Override public void OnStop () {super.onstop (); LOG.D (TAG, "onStop"); } @Override public void Ondestroyview () {Super.ondestroyview (); LOG.D (TAG, "Ondestroyview"); } @Override public void OnDestroy () {Super.ondestroy (); LOG.D (TAG, "OnDestroy"); } @Override public void Ondetach () {Super.ondetach (); LOG.D (TAG, "Ondetach"); }}
The source code is very simple, loading the layout file in Oncreateview, the layout file is very simple, just define a frame layout, in the frame layout contains a TextView
<?xml version="1.0" encoding="utf-8"?><FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Goods" android:textStyle="bold" android:textSize="30sp" android:layout_gravity="center"/></FrameLayout>
According to the above process we established the required fragment, and then change the bestfragmentactivity code, the source of the change is as follows
public class Bestfragmentactivity extends appcompatactivity{@Override protected void onCreate (Bundle savedinstances Tate) {super.oncreate (savedinstancestate); Setcontentview (r.layout.activity_best_fragment); Bottom navigation layout bottomnavigationview Bottomnavigationview = (bottomnavigationview) Findviewbyid (r.id.bottomnavigation); Bottomnavigationitem Bottomnavigationitem = new Bottomnavigationitem ("Home", Contextcompat.getcolor (th is, R.color.firstcolor), R.MIPMAP.IC_ACCOUNT_BALANCE_WHITE_48DP); Bottomnavigationitem bottomNavigationItem1 = new Bottomnavigationitem ("Classification", Contextcompat.getcolor (this, R . Color.secondcolor), R.MIPMAP.IC_LIST_WHITE_48DP); Bottomnavigationitem bottomNavigationItem2 = new Bottomnavigationitem ("task", Contextcompat.getcolor (this, R . Color.firstcolor), R.MIPMAP.IC_ADD_CIRCLE_OUTLINE_WHITE_48DP); Bottomnavigationitem bottomNavigationItem3 = new Bottomnavigationitem ("Shopping Cart", Contextcompat.getcolor (this, r.color.thirdcolor), R.MIPMAP.IC_ADD_SHOPPING_CART_WHITE_48DP); Bottomnavigationitem bottomNavigationItem4 = new Bottomnavigationitem ("My", Contextcompat.getcolor (this, R . color.coloraccent), R.MIPMAP.IC_ACCOUNT_BOX_WHITE_48DP); Bottomnavigationview.addtab (Bottomnavigationitem); Bottomnavigationview.addtab (BOTTOMNAVIGATIONITEM1); Bottomnavigationview.addtab (BOTTOMNAVIGATIONITEM2); Bottomnavigationview.addtab (BOTTOMNAVIGATIONITEM3); Bottomnavigationview.addtab (BOTTOMNAVIGATIONITEM4); Set the Click event Bottomnavigationview.setonbottomnavigationitemclicklistener for the bottom navigation layout (new Onbottomnavigationitemclicklistener () {@Override public void Onnavigationitemclick (int i) { switch (i) {case 0:switchtohome (); Break Case 1:switchtocategory (); Break Case 2:switchtotask (); Break Case 3:switchtogoodcar (); Break Case 4:switchtoabout (); Break } } }); Initial load first page, namely Goodsfragment switchtohome (); } private void Switchtoabout () {Getsupportfragmentmanager (). BeginTransaction (). Replace (r.id.frame_content,n EW aboutfragment (), AboutFragment.class.getName ()). commit (); } private void Switchtocategory () {Getsupportfragmentmanager (). BeginTransaction (). Replace (R.id.frame_content,ne W categoryfragment (), CategoryFragment.class.getName ()). commit (); } private void SwitchToTask () {Getsupportfragmentmanager (). BeginTransaction (). replace (R.id.frame_content,new Ta Skfragment (), TaskFragment.class.getName ()). commit (); } private void SwitchtOgoodcar () {Getsupportfragmentmanager (). BeginTransaction (). Replace (R.id.frame_content,new goodcarfragment (), GoodCarFragment.class.getName ()). commit (); } private void Switchtohome () {Getsupportfragmentmanager (). BeginTransaction (). replace (R.id.frame_content,new Go Odsfragment (), GoodsFragment.class.getName ()). commit (); }}
The above code can be based on the previous article is easier to write out, and normal operation, but in the actual development process we have to consider the performance of the code. In fact, the above code has a performance problem, especially in the bottom navigation in this scenario, fragment between the back and forth, the Replace method used here. The problem with this method and how to optimize it are explained in detail in the next section.
Fragment Performance Optimization Problem fragmenttransaction
When talking about the performance optimization problem of fragment, we have to study and explore Fragmenttransaction, which uses Getsupportfragmentmanager (). BeginTransaction () The Fragmenttransaction object is obtained, and the Replace method and the commit method are called in turn.
- replace (int containerviewid, Fragment Fragment), replace (int containerviewid, Fragment Fragment, String tag)
The function of this method is similar to remove all fragment of the view container first, add the fragment in the method parameter, and set tag tag for the fragment.
getSupportFragmentManager().beginTransaction().add(R.id.frame_content,new AboutFragment(),AboutFragment.class.getName()).commit(); getSupportFragmentManager().beginTransaction().add(R.id.frame_content,new CategoryFragment(),CategoryFragment.class.getName()).commit(); getSupportFragmentManager().beginTransaction().add(R.id.frame_content,new TaskFragment(),TaskFragment.class.getName()).commit(); getSupportFragmentManager().beginTransaction().replace(R.id.frame_content,new GoodsFragment(),GoodsFragment.class.getName()).commit();
As shown in the code block above, we first made 3 additions, then the replace operation moves out of the previously added fragment and adds the frament specified in the method parameter.
Add (int containerviewid, Fragment Fragment, String tag), remove (Fragment Fragment)
The Add () operation of the fragmenttransaction is maintained in a queue, in which the order in which the add goes in is formed into a linked list, and the actions above us in the form of this listing change as shown:
Remove (Fragment Fragment): Removes an already existing Fragment.
Show (Fragment Fragment): shows a Fragment that was previously hidden
Hide (Fragment Fragment): Hides an existing Fragment
Note:①fragment is hide/show, just hide/show fragment view, there will be no life cycle method calls.
② override the Onhiddenchanged method in fragment to listen for the Hide and show states of fragment.
There are some other ways not listed here, with the method listed above, we can have a very good optimization of the fragment.
Analysis of fragment performance problem and analysis of solving fragment performance problem
We use replace to switch pages, then each time you switch, fragment will be re-instantiated, reloading the data, which consumes performance and user data traffic. This is because the replace operation, each time the existing fragment instance in the container is emptied, and then add the specified fragment, it will cause the switch to the previous fragment, the instance will be re-fragment.
Fragment Performance Problem Solving
The
knows the root of the problem, and the solution is in the way. We can not use replace to make the page switch, then the method can be used as if only add, we may at the time of loading to determine whether fragment has been added to the queue, if added, we will show (show) The fragment, hide the other, If it has not been added, add it. This allows multiple fragment to be toggled without re-instantiation. This is exactly what it is in the code
public class Bestfragmentactivity extends appcompatactivity{//current Fragment private Fragment mcurfragment = new F Ragment (); Initialize the other fragment private goodsfragment mgoodsfragment = new Goodsfragment (); Private Goodcarfragment mgoodcarfragment = new Goodcarfragment (); Private Taskfragment mtaskfragment = new Taskfragment (); Private Aboutfragment maboutfragment = new Aboutfragment (); Private Categoryfragment mcategoryfragment = new Categoryfragment (); @Override protected void OnCreate (Bundle savedinstancestate) {super.oncreate (savedinstancestate); Setcontentview (r.layout.activity_best_fragment); Bottomnavigationview Bottomnavigationview = (bottomnavigationview) Findviewbyid (r.id.bottomnavigation); Bottomnavigationitem Bottomnavigationitem = new Bottomnavigationitem ("Home", Contextcompat.getcolor (this, R. Color.firstcolor), R.MIPMAP.IC_ACCOUNT_BALANCE_WHITE_48DP); Bottomnavigationitem bottomNavigationItem1= new Bottomnavigationitem ("Classification", Contextcompat.getcolor (this, r.color.secondcolor), R.mipmap.ic_list_white _48DP); Bottomnavigationitem bottomNavigationItem2 = new Bottomnavigationitem ("task", Contextcompat.getcolor (this, R . Color.firstcolor), R.MIPMAP.IC_ADD_CIRCLE_OUTLINE_WHITE_48DP); Bottomnavigationitem bottomNavigationItem3 = new Bottomnavigationitem ("Shopping Cart", contextcompat.getcolor (this, R.color.thirdcolor), R.MIPMAP.IC_ADD_SHOPPING_CART_WHITE_48DP); Bottomnavigationitem bottomNavigationItem4 = new Bottomnavigationitem ("My", Contextcompat.getcolor (this, R . color.coloraccent), R.MIPMAP.IC_ACCOUNT_BOX_WHITE_48DP); Bottomnavigationview.addtab (Bottomnavigationitem); Bottomnavigationview.addtab (BOTTOMNAVIGATIONITEM1); Bottomnavigationview.addtab (BOTTOMNAVIGATIONITEM2); Bottomnavigationview.addtab (BOTTOMNAVIGATIONITEM3); Bottomnavigationview.addtab (BOTTOMNAVIGATIONITEM4); Bottomnavigationview.setonbottomnavigationitemclicklistener (New Onbottomnavigationitemclicklistener () {@Ov Erride public void Onnavigationitemclick (int. i) {switch (i) {case 0: Switchtohome (); Break Case 1:switchtocategory (); Break Case 2:switchtotask (); Break Case 3:switchtogoodcar (); Break Case 4:switchtoabout (); Break } } }); Switchtohome (); } private void Switchfragment (Fragment targetfragment) {fragmenttransaction transaction = Getsupportfragmentmanag ER (). BeginTransaction (); if (!targetfragment.isadded ()) {//If the targetfragment to be displayed has not been added Transaction Hide (mcurfragment)//hides the current fragment. Add (R.id.frame_content, TARGETF Ragment,targetfragment.getclass (). GetName ())//Add targetfragment. Commit (); } else {//if the targetfragment you want to display has been added transaction//hides the current fragment. Hide (Mcurfragment) . Show (Targetfragment)//Display targetfragment. commit (); }//update current fragment to targetfragment mcurfragment = targetfragment; } private void Switchtoabout () {switchfragment (maboutfragment); } private void Switchtocategory () {switchfragment (mcategoryfragment); } private void SwitchToTask () {switchfragment (mtaskfragment); } private void Switchtogoodcar () {switchfragment (mgoodcarfragment); } private void Switchtohome () {switchfragment (mgoodsfragment); }}
That's what we're doing, and we're going back and forth, fragment only one instance at a time, less of the performance cost of destruction and re-creation, and when we want to update the data in fragment, We can override its Onhiddenchanged method in custom fragment
@Overridepublic void onHiddenChanged(boolean hidden) { super.onHiddenChanged(hidden); if (hidden){ //Fragment隐藏时调用 }else { //Fragment显示时调用 }}
Source Address: Source Portal This chapter summary
We give a fragment best practice in this blog, we can see the effect of top and bottom navigation in many mainstream apps, and on this basis we discuss the performance problems and optimizations of using fragment improperly.
Next trailer
The next article is going to add something to the fragment, ListView.
Sincerely, salute.
Android Development long distance xiii--fragment best practices