Reprint please indicate source: http://blog.csdn.net/lmj623565791/article/details/37992017
The previous blog has introduced the Fragment cause, as well as some basic usage and various APIs, if you do not understand, see:Android Fragment Real full Parse (on).
This article describes how to manage fragment fallback stacks, fragment how to interact with activities, fragment best practices for interacting with activities, no fragment of views, use fragment to create dialog boxes, How to integrate with Actionbar,menuitem, etc. ~ ~
1, management fragment fallback stack
Similar to the Android system to maintain a task stack for activity, we can also maintain a fallback stack through activity to save the changes that occur with each fragment transaction. If you add the fragment task to the fallback stack, when the user taps the Back button, they will see the last saved fragment. Once the fragment is completely ejected from the back stack, the user clicks the Back button again, exiting the current activity.
Look at this one:
Click the first button, switch to the second screen, click the second button, switch to the third interface, then click the Back button to rewind. This is not like a beginner Android when the activity jumps, of course, here is certainly not, otherwise I will kneel. Here is the implementation of fragment, the user click Back, is actually the fragment fallback stack constantly.
How to add a fragment transaction to the fallback stack:
Fragmenttransaction.addtobackstack (String)
Here's the code: Obviously there are 3 fragment and one activity.
First look at the activity's layout file:
<relativelayout 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 " > <framelayout android:id= "@+id/id_content" android:layout_width= "Fill_parent" android: layout_height= "Fill_parent" > </FrameLayout></RelativeLayout>
Different fragment are shown in this framelayout.
Mainactivity.java
Package Com.zhy.zhy_fragments;import Android.app.activity;import Android.app.fragmentmanager;import Android.app.fragmenttransaction;import Android.os.bundle;import Android.view.window;public class MainActivity Extends activity{@Overrideprotected void OnCreate (Bundle savedinstancestate) {super.oncreate (savedinstancestate); Requestwindowfeature (Window.feature_no_title); Setcontentview (R.layout.activity_main); Fragmentmanager fm = Getfragmentmanager (); Fragmenttransaction tx = Fm.begintransaction (); Tx.add (R.id.id_content, New Fragmentone (), "one"); Tx.commit ();}}
Very simply, add fragmentone directly to the framelayout in the layout file, note that there is no call to Fragmenttransaction.addtobackstack (String), because I don't like the current display, Click the Back button to appear on the whiteboard. Instead, the correct back key, which exits our activity.
Here's fragmentone.
Package Com.zhy.zhy_fragments;import Android.app.fragment;import Android.app.fragmentmanager;import Android.app.fragmenttransaction;import Android.os.bundle;import Android.view.layoutinflater;import Android.view.view;import Android.view.view.onclicklistener;import Android.view.viewgroup;import Android.widget.button;public class Fragmentone extends Fragment implements Onclicklistener{private Button mbtn;@ Overridepublic View Oncreateview (Layoutinflater inflater, ViewGroup container,bundle savedinstancestate) {View view = Inflater.inflate (R.layout.fragment_one, container, false); mBtn = (Button) View.findviewbyid (r.id.id_fragment_one_ BTN); Mbtn.setonclicklistener (this); return view;} @Overridepublic void OnClick (View v) {fragmenttwo ftwo = new Fragmenttwo (); Fragmentmanager fm = Getfragmentmanager (); Fragmenttransaction tx = Fm.begintransaction (); Tx.replace (R.id.id_content, Ftwo, "a"); Tx.addtobackstack (null); Tx.commit ();}}
When we clicked on the button in Fragmentone, we used the Replace method, if you read the previous blog, you must remember that replace is a combination of remove and add, and if you do not add a transaction to the fallback stack, the previous fragment instance is destroyed. Obviously, we call Tx.addtobackstack (NULL) and add the current transaction to the fallback stack, so the Fragmentone instance will not be destroyed, but the view level will still be destroyed. Will call Ondestoryview and Oncreateview, the evidence is: look at the above, we before the jump in the text box input content, the user back to get the first interface is missing.
Next Fragmenttwo
Package Com.zhy.zhy_fragments;import Android.app.fragment;import Android.app.fragmentmanager;import Android.app.fragmenttransaction;import Android.os.bundle;import Android.view.layoutinflater;import Android.view.view;import Android.view.view.onclicklistener;import Android.view.viewgroup;import Android.widget.button;public class Fragmenttwo extends Fragment implements Onclicklistener{private Button MBtn; Overridepublic View Oncreateview (Layoutinflater inflater, ViewGroup container,bundle savedinstancestate) {View view = Inflater.inflate (R.layout.fragment_two, container, false); mBtn = (Button) View.findviewbyid (r.id.id_fragment_two_ BTN); Mbtn.setonclicklistener (this); return view; } @Overridepublic void OnClick (View v) {fragmentthree fthree = new Fragmentthree (); Fragmentmanager fm = Getfragmentmanager (); Fragmenttransaction tx = Fm.begintransaction (); Tx.hide (this); Tx.add (R.id.id_content, Fthree, "three");//tx.replace ( R.id.id_content, Fthree, "three"); Tx.addtobackstack (null); Tx.commit ();}}
When clicked here, instead of using replace, we first hide the current fragment, then add the Fragmentthree instance and finally add the transaction to the fallback stack. The purpose of this is to provide a solution: If you do not want the view to redraw what to do, please look carefully again, we fragmenttwo in the EditText fill in the content, the user back, the data is still in ~ ~ ~
The last Fragmentthree is a simple toast:
Package Com.zhy.zhy_fragments;import Android.app.fragment;import Android.os.bundle;import Android.view.layoutinflater;import Android.view.view;import Android.view.view.onclicklistener;import Android.view.viewgroup;import Android.widget.button;import Android.widget.toast;public class FragmentThree extends Fragment implements Onclicklistener{private Button mBtn; @Overridepublic View Oncreateview (Layoutinflater inflater, ViewGroup Container,bundle savedinstancestate) {View view = Inflater.inflate (R.layout.fragment_three, container, False ); mBtn = (Button) View.findviewbyid (R.ID.ID_FRAGMENT_THREE_BTN); Mbtn.setonclicklistener (this); return view;} @Overridepublic void OnClick (View v) {toast.maketext (getactivity (), "I am a btn in Fragment three", Toast.length_short). Sh ow ();}}
Well, after the above introduction, you should already know what the fragment fallback stack is all about, as well as the hide,replace of their respective application scenarios.
It is extremely important to note here: The overall code above does not have any reference value, purely to show the fallback stack, after explaining the fragment and activity communication, will refactor the above code!
2, fragment and activity communication
Because all fragment are dependent on activity, communication is not complicated, presumably summed up as:
A, if your activity contains references to the fragment you manage, you can access all of the fragment public methods directly by referencing
b, if the activity does not save any fragment references, then it does not matter, each fragment has a unique tag or ID, can be Getfragmentmanager.findfragmentbytag () or Findfragmentbyid () obtains any fragment instances and then operates.
C, in fragment, you can get an instance of the currently bound activity by getactivity, and then do the operation.
Note: If a context is required in fragment, you can call Getactivity () and use getactivity () if the context needs to exist after the activity is destroyed. Getapplicationcontext ().
3. Best practices for fragment and activity communication
Because it is necessary to consider the reuse of fragment, the coupling between fragment and activity must be reduced, and fragment should not operate the other fragment directly, after all, the fragment operation should be determined by its manager activity.
Here I have two different ways of refactoring, Fragmentone and fragmenttwo Click events, and the activity's response to a click event:
First Look at Fragmentone
Package Com.zhy.zhy_fragments;import Android.app.fragment;import Android.os.bundle;import Android.view.layoutinflater;import Android.view.view;import Android.view.view.onclicklistener;import Android.view.viewgroup;import Android.widget.button;public class Fragmentone extends Fragment implements Onclicklistener{private button mbtn;/** * Set buttons click on Callback * @author Zhy * */public interface fonebtnclicklistener{void ONFONEBTN Click ();} @Overridepublic View Oncreateview (Layoutinflater inflater, ViewGroup container,bundle savedinstancestate) {View view = Inflater.inflate (R.layout.fragment_one, container, false); mBtn = (Button) View.findviewbyid (r.id.id_fragment_one_ BTN); Mbtn.setonclicklistener (this); return view;} /** * gives the host activity to handle if it wishes to process */@Overridepublic void OnClick (View v) {if (getactivity () instanceof Fonebtnclicklistener) { ((Fonebtnclicklistener) getactivity ()). Onfonebtnclick ();}}
You can see that the current fragmentone is not coupled with any activity, any activity can be used, and we declare an interface to turn its click events back and forth, to manage the activity of its click events to implement this interface. You can see that in the onclick we first judged whether the current bound activity implemented the interface and called if it was implemented.
Look at Fragmenttwo again.
Package Com.zhy.zhy_fragments;import Android.app.fragment;import Android.os.bundle;import Android.view.layoutinflater;import Android.view.view;import Android.view.view.onclicklistener;import Android.view.viewgroup;import Android.widget.button;public class Fragmenttwo extends Fragment implements Onclicklistener{private Button mBtn;p rivate ftwobtnclicklistener ftwobtnclicklistener;p ublic interface Ftwobtnclicklistener{void Onftwobtnclick ();} Set callback interface public void Setftwobtnclicklistener (Ftwobtnclicklistener ftwobtnclicklistener) {This.ftwobtnclicklistener = Ftwobtnclicklistener;} @Overridepublic View Oncreateview (Layoutinflater inflater, ViewGroup container,bundle savedinstancestate) {View view = Inflater.inflate (R.layout.fragment_two, container, false); mBtn = (Button) View.findviewbyid (r.id.id_fragment_two_ BTN); Mbtn.setonclicklistener (this); return view; } @Overridepublic void OnClick (View v) {if (Ftwobtnclicklistener! = null) {Ftwobtnclicklistener.onftwobtnclick ();}}}
Very similar to Fragmentone, but we provide a method such as Setlistener, which means that the activity needs not only to implement the interface, but also to display the call Mftwo.setftwobtnclicklistener (this).
Last seen activity:
Package Com.zhy.zhy_fragments;import Android.app.activity;import Android.app.fragmentmanager;import Android.app.fragmenttransaction;import android.os.bundle;import android.view.window;import com.zhy.zhy_fragments. Fragmentone.fonebtnclicklistener;import com.zhy.zhy_fragments. Fragmenttwo.ftwobtnclicklistener;public class Mainactivity extends Activity implements Fonebtnclicklistener, Ftwobtnclicklistener{private fragmentone mfone;private fragmenttwo mftwo;private FragmentThree mFThree;@ overrideprotected void OnCreate (Bundle savedinstancestate) {super.oncreate (savedinstancestate); Requestwindowfeature (Window.feature_no_title); Setcontentview (r.layout.activity_main); mFOne = new FragmentOne (); Fragmentmanager fm = Getfragmentmanager (); Fragmenttransaction tx = Fm.begintransaction (); Tx.add (R.id.id_content, Mfone, "one"); Tx.commit ();} /** * Fragmentone button click Callback */@Overridepublic void Onfonebtnclick () {if (mftwo = = null) {mftwo = new fragmenttwo (); mftwo.setf Twobtnclicklistener (this);} Fragmentmanager FM= Getfragmentmanager (); Fragmenttransaction tx = Fm.begintransaction (); Tx.replace (R.id.id_content, Mftwo, "a"); Tx.addtobackstack (null); Tx.commit ();} /** * Fragmenttwo button click Callback */@Overridepublic void Onftwobtnclick () {if (Mfthree = = null) {Mfthree = new Fragmentthree ();} Fragmentmanager fm = Getfragmentmanager (); Fragmenttransaction tx = Fm.begintransaction (); Tx.hide (mftwo); Tx.add (R.id.id_content, Mfthree, "THREE");// Tx.replace (R.id.id_content, Fthree, "three"); Tx.addtobackstack (null); Tx.commit ();}}
The code refactoring ends exactly the same as the starting effect. The above two means of communication are worth recommending, choose one of their own favorite. Here again: Although fragment and activity can do anything with getactivity and Findfragmentbytag or Findfragmentbyid, Even in the fragment inside the operation of another fragment, but there is no special reason is absolutely not advocated. Activity serves as a bus-like role between fragment and should be determined by it fragment how to operate. In addition, although fragment cannot respond to intent open, but activity can, activity can receive intent, and then according to the parameters to determine which fragment to show.
4. How to handle runtime configuration changes
Runtime configuration changes, the most common is the screen rotation, if you do not know how to handle screen changes can refer to:Android screen rotation processing asynctask and progressdialog the best solution
Here's a note: A lot of people feel compelled to set the direction of the screen, but one thing, when your app is in the background (for example, the user clicked Home), for a long time no return, your app will be restarted. For example: If you take the example above you as the Fragmentthree interface, and then in the background state, after a long time you will find that when you open again through the home, the above Fragmentthree and fragmentone superimposed together, This is because your activity restarts, and a fragmentone is drawn on the original fragmentthree.
OK, here's a snippet of code:
Activity:
Package Com.zhy.zhy_fragments;import Android.app.activity;import Android.app.fragmentmanager;import Android.app.fragmenttransaction;import Android.os.bundle;import Android.view.window;public class MainActivity Extends Activity{private fragmentone mfone; @Overrideprotected void OnCreate (Bundle savedinstancestate) { Super.oncreate (savedinstancestate); Requestwindowfeature (Window.feature_no_title); SetContentView ( R.layout.activity_main); mfone = new Fragmentone (); Fragmentmanager fm = Getfragmentmanager (); Fragmenttransaction tx = Fm.begintransaction (); Tx.add (R.id.id_content, Mfone, "one"); Tx.commit ();}}
Fragment
Package Com.zhy.zhy_fragments;import Android.app.fragment;import Android.os.bundle;import android.util.Log;import Android.view.layoutinflater;import Android.view.view;import Android.view.viewgroup;public class FragmentOne extends Fragment{private static final String TAG = "Fragmentone"; @Overridepublic View Oncreateview (Layoutinflater inflater, ViewGroup container,bundle savedinstancestate) {log.e (TAG, "Oncreateview"); View view = Inflater.inflate (R.layout.fragment_one, container, false); return view;} @Overridepublic void OnCreate (Bundle savedinstancestate) {//TODO auto-generated method Stubsuper.oncreate ( Savedinstancestate); LOG.E (TAG, "onCreate");} @Overridepublic void Ondestroyview () {//TODO auto-generated method Stubsuper.ondestroyview (); LOG.E (TAG, "Ondestroyview");} @Overridepublic void OnDestroy () {//TODO auto-generated method Stubsuper.ondestroy (); LOG.E (TAG, "OnDestroy");}}
Very simple code, when you run, and constantly rotate the screen, you will find that every time you rotate the screen, there is a fragmentone instance on the screen, and the background log will print out many sets of life cycle callbacks.
Similar:
07-20 08:18:46.651:e/fragmentone (1633): oncreate07-20 08:18:46.651:e/fragmentone (1633): onCreate07-20 08:18:46.651: E/fragmentone (1633): oncreate07-20 08:18:46.681:e/fragmentone (1633): oncreateview07-20 08:18:46.831:e/fragmentone ( 1633): oncreateview07-20 08:18:46.891:e/fragmentone (1633): Oncreateview
That's why, because when the screen spins and the activity restarts, the fragment in the default activity is re-created with the activity, which causes the fragment of itself to restart when the rotation occurs, Then when the activity's oncreate is executed, a new fragment is instantiated again, which is the reason for the occurrence.
So how to fix it:
In fact, by checking the OnCreate parameter bundle Savedinstancestate can determine whether the current activity is re-created:
The default Savedinstancestate stores some data, including an instance of fragment: by printing, you can see:
07-20 08:23:12.952:e/fragmentone (1782): Bundle[{android:[email protected], android:viewhierarchystate=bundle[{ android:focusedviewid=2131230721, Android:[email Protected]}]}
So, let's simply change the code to create a fragment instance only when Savedinstancestate==null:
Package Com.zhy.zhy_fragments;import Android.app.activity;import Android.app.fragmentmanager;import Android.app.fragmenttransaction;import Android.os.bundle;import Android.util.log;import Android.view.Window; public class Mainactivity extends activity{private static final String TAG = "Fragmentone";p rivate fragmentone mfone; @Over rideprotected void OnCreate (Bundle savedinstancestate) {super.oncreate (savedinstancestate); Requestwindowfeature ( Window.feature_no_title); Setcontentview (R.layout.activity_main); LOG.E (TAG, savedinstancestate+ ""); if (savedinstancestate = = null) {Mfone = new Fragmentone (); Fragmentmanager fm = Getfragmentmanager (); Fragmenttransaction tx = Fm.begintransaction (); Tx.add (R.id.id_content, Mfone, "one"); Tx.commit ();}}}
Now there is only one fragment instance in the activity, regardless of how many rotations are performed.
Now there is still a problem, that is, when redrawing, fragment reconstruction, the original data how to maintain?
In fact, similar to activity, fragment also has a Onsaveinstancestate method, in which to save the data, and then in OnCreate or Oncreateview or onactivitycreated to recover can be.
The test code is not posted for space reasons.
5. Fragmeny integration with Actionbar and MenuItem
Fragment can add your own MenuItem to the activity's Actionbar or optional menu.
A, call Sethasoptionsmenu (True) in the oncreate of fragment;
b, then implement Oncreateoptionsmenu in the fragment subclass
C, if you want to handle MenuItem in fragment, you can also implement onoptionsitemselected, of course, the activity can also directly handle the MenuItem click event.
Code:
Fragment
Package Com.zhy.zhy_fragments;import Android.app.fragment;import Android.os.bundle;import Android.view.layoutinflater;import Android.view.menu;import Android.view.menuinflater;import Android.view.menuitem;import Android.view.view;import Android.view.viewgroup;import Android.widget.Toast;public Class Fragmentone extends fragment{@Overridepublic void OnCreate (Bundle savedinstancestate) {super.oncreate ( Savedinstancestate); Sethasoptionsmenu (true);} @Overridepublic View Oncreateview (Layoutinflater inflater, ViewGroup container,bundle savedinstancestate) {View view = Inflater.inflate (R.layout.fragment_one, container, false); return view;} @Overridepublic void Oncreateoptionsmenu (Menu menu, Menuinflater inflater) {inflater.inflate (R.menu.fragment_menu, menu);} @Overridepublic boolean onoptionsitemselected (MenuItem item) {switch (Item.getitemid ()) {case R.id.id_menu_fra_test: Toast.maketext (Getactivity (), "FragmentMenuItem1", Toast.length_short). Show (); break;} return true;}}
Activity
Package Com.zhy.zhy_fragments;import Android.app.activity;import Android.app.fragmentmanager;import Android.app.fragmenttransaction;import Android.os.bundle;import Android.util.log;import Android.view.Menu;import Android.view.menuitem;import Android.view.window;import Android.widget.toast;public class MainActivity extends Activity{private static final String TAG = "Fragmentone";p rivate fragmentone mfone; @Overrideprotected void OnCreate ( Bundle savedinstancestate) {super.oncreate (savedinstancestate); Requestwindowfeature (Window.feature_no_title); Setcontentview (R.layout.activity_main); LOG.E (TAG, Savedinstancestate + ""); if (savedinstancestate = = null) {Mfone = new Fragmentone (); Fragmentmanager fm = Getfragmentmanager (); Fragmenttransaction tx = Fm.begintransaction (); Tx.add (R.id.id_content, Mfone, "one"); Tx.commit ();}} @Overridepublic boolean Oncreateoptionsmenu (Menu menu) {super.oncreateoptionsmenu (menu); Getmenuinflater (). Inflate ( R.menu.main, menu); return true;} @Overridepublic Boolean onoptionsItemselected (MenuItem Item) {switch (Item.getitemid ()) {case R.id.action_settings:toast.maketext (this, "setting", Toast.length_short). Show (); return true;default://If you want fragment to handle MenuItem Click events yourself, be sure not to forget to call Super.xxxreturn super.onoptionsitemselected (item);}}}
:
Well, can be very good to see, fragment can add MenuItem, you can also handle the Click ~ ~ ~
6, no layout of the role of the fragment
There is no layout file fragment is actually meant to be saved, and when the activity is restarted, a large amount of data is prepared
Please refer to blog:The best solution for Android screen rotation processing asynctask and ProgressDialog
7. Create a dialog box with fragment
This is the way Google recommended, I also wrote a separate blog introduction, please refer to:Android official Recommendation: dialogfragment Create dialog box
Well, finally the fragment related to the link together, the above basic contains all the use of fragment ~ ~ ~ I believe that if you can read, there must be a lot of harvest ~ ~ ~
Have any questions, welcome message ~ ~ ~
Two end, I believe you have a certain understanding of fragment, then what is the best practice in the project? Please take a look: Android Fragment everything you should know
Android Fragment Real Full parse (bottom)