An in-depth analysis of the Android Fragment (next article) _android

Source: Internet
Author: User
Tags stub xmlns

In the previous article to introduce you to the in-depth analysis of Android Fragment (above), including some basic usage and various APIs, if you want to further study please continue to focus on this article.

This article describes how to manage the fragment fallback stack, fragment how to interact with the activity, fragment best practices to interact with the activity, the usefulness of not having a view fragment, and using fragment to create a dialog box, How to integrate with Actionbar,menuitem and so on ~ ~

1, management fragment back stack

Similar to the Android system, which maintains a task stack for the activity, we can also maintain a fallback stack through the event to save changes to each fragment transaction. If you add the fragment task to the fallback stack, when the user clicks 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 an effect chart like this:

Click on the first button, switch to the second interface, click the second button, switch to the third interface, and then click the Back button to return. It's not like a beginner Android activity jump, of course, it's definitely not here, or I'm on my knees. Here is fragment implementation, the user clicks back, the actual fragment is the stack of stacks.

How to add a fragment transaction to the fallback stack:

Fragmenttransaction.addtobackstack (String)

Here's the code: it's obvious that there are 3 fragment and one activity.

Look at the activity's layout file first:

<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 
{ 
  @Override 
  protected 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 (); 
  } 

Simply add Fragmentone 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 corresponding back key, that is, exiting 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;  
    @Override public 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; 
    @Override public void OnClick (View v) {fragmenttwo ftwo = new Fragmenttwo (); 
    Fragmentmanager fm = Getfragmentmanager (); 
    Fragmenttransaction tx = Fm.begintransaction (); Tx.replace (R.id.id_content, Ftwo, "two"); 
    Tx.addtobackstack (NULL); 
  Tx.commit (); } 
}

When we clicked on the button in Fragmentone, we used the Replace method, and if you read the previous blog, you must remember that replace is the combination of remove and add, and if you do not add a transaction to the fallback stack, the previous fragment instance is destroyed. It is obvious here that we call tx.addtobackstack (null); The current transaction is added to the fallback stack, so the Fragmentone instance is not destroyed, but the view hierarchy is still destroyed. The Ondestoryview and Oncreateview are called, and the evidence is: look at the effect chart above, the content that we entered in the text box before we jumped, and disappeared when the user got the first interface.

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;  
    @Override public 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; 
    @Override public 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, we do not use replace, but first hides the current fragment, then adds an instance of Fragmentthree, and finally adds the transaction to the fallback stack. The purpose of this is to provide you with a solution: If you do not want the view to redraw how to do, please carefully look at the effect of the picture, we fragmenttwo edittext fill in the content, the user back when the data is still ~ ~ ~

The final fragmentthree is the 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;  
    @Override public 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; 
        @Override public void OnClick (View v) {toast.maketext (getactivity (), ' I am a btn in Fragment three ', 
  Toast.length_short). Show (); } 
} 

Well, after the above introduction, should already know the fragment back stack is how, as well as hide,replace and other applications of the scene.
Here a great note: The overall code above does not have any reference value, purely in order to show the fallback stack, after explaining the fragment and activity after communication, will refactor the above code!

2, fragment and activity communication

Since 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 the fragment public methods directly by referencing

b, if no fragment references are saved in the activity, then it doesn't matter, each fragment has a unique tag or ID that can be passed through Getfragmentmanager.findfragmentbytag () or Findfragmentbyid () get any fragment instances, and then do the operation.

C, in fragment, you can get an instance of the currently bound activity through getactivity, and then do the operation.

Note: If context is required in fragment, you can use Getactivity () by calling Getactivity (), if it needs to exist after the activity has been destroyed. Getapplicationcontext ().

3, fragment and activity communication best practices

Since it is necessary to consider fragment reuse, the coupling of fragment and activity must be reduced, and fragment should not directly manipulate other fragment, after all, fragment operations should be determined by the activity of its managers.

Here's my two-way code, refactoring, Fragmentone and fragmenttwo clicks, and the activity response to the 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 Button click Callback * @author zhy * * */public interface Fonebtnclicklistener {void Onfonebtnclick ( 
  );  
  @Override public 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; /** * to host activity processing if it wants to process/@Override public void OnClick (View v) {if (getactivity () Insta Nceof fonebtnclicklistener) {(Fonebtnclicklistener) getactivity ()). Onfonebtnclick (); 

 } 
  } 
}

You can see that the current fragmentone is not coupled with any activity, and that any activity can be used, and we declare an interface to back and forth its click events to manage the activity of its click events to implement this interface. We can see in the onclick that we first determine whether the currently bound activity implements the interface, and if it is implemented, call it.

And look at Fragmenttwo.

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; 
  Private Ftwobtnclicklistener Ftwobtnclicklistener; 
  public interface Ftwobtnclicklistener {void Onftwobtnclick (); }//Set callback interface public void Setftwobtnclicklistener (Ftwobtnclicklistener ftwobtnclicklistener) {this.ftwobtnclic 
  Klistener = Ftwobtnclicklistener;  
  @Override public 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; } @Override Public void OnClick (View v) {if (Ftwobtnclicklistener!= null) {Ftwobtnclicklistener.onftwobtnclick (); } 
  } 
}

Very similar to Fragmentone, but we provide setlistener such a method, which means that the activity needs not only to implement the interface, but also to display the call Mftwo.setftwobtnclicklistener (this).

Last Look at 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 Fragme 
  Ntone Mfone; 
  Private Fragmenttwo Mftwo; 
  Private Fragmentthree Mfthree; 
    @Override protected 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 * * * @Override public VOID Onfonebtnclick () {if (mftwo = = null) {mftwo = new fragmenttwo (); 
    Mftwo.setftwobtnclicklistener (this); 
    Fragmentmanager fm = Getfragmentmanager (); 
    Fragmenttransaction tx = Fm.begintransaction (); 
    Tx.replace (R.id.id_content, Mftwo, "two"); 
    Tx.addtobackstack (NULL); 
  Tx.commit (); 
    /** * Fragmenttwo button click callback/@Override public 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 beginning. The above two kinds of communication methods are worth recommending, casually choose one of their favorite. Here again: Although fragment and activity can do anything through getactivity with Findfragmentbytag or Findfragmentbyid, Even in the fragment inside the operation of the other fragment, but there is no special reason is absolutely not advocated. The activity acts as a bus-like role between fragment, and it is up to it to decide how fragment operates. In addition, although fragment cannot respond to intent open, activity can, activity can receive intent, and then according to the parameters to determine which fragment to show.

4. How to handle changes in Run-time configuration

Runtime configuration changes, the most common is the screen rotation, if you do not know how to deal with screen changes can refer to: Android screen rotation to handle asynctask and progressdialog the best solution

Here's a note: Many people feel compelled to set the direction of the screen, but one thing, when your application is in the background (for example, when the user clicks Home), the application will be restarted when it does not return for a long time. For example: If you take the example above to 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 top fragmentthree and fragmentone superimposed together, This is because your activity was restarted and a fragmentone was drawn on the original fragmentthree.

OK, let's look at a piece 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; 
  @Override 
  protected 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";  
    @Override public View Oncreateview (layoutinflater inflater, ViewGroup container, Bundle savedinstancestate) { 
    LOG.E (TAG, "Oncreateview"); 
    View view = Inflater.inflate (R.layout.fragment_one, container, false); 
  return view; @Override public void OnCreate (Bundle savedinstancestate) {//TODO auto-generated method stub super. 
    OnCreate (savedinstancestate); 
  LOG.E (TAG, "onCreate"); 
    @Override public void Ondestroyview () {//TODO auto-generated Method Stub Super.ondestroyview (); 
  LOG.E (TAG, "Ondestroyview"); @Override public void OnDestroy () {//TODO auto-generated method stub supEr.ondestroy (); 
  LOG.E (TAG, "OnDestroy");

 } 
}

Very simple code, when you run, constantly rotate the screen, you will find that every time the screen is rotated, a fragmentone instance of the screen, and the background log will print many sets of life cycle callback.

Similar:

07-20 08:18:46.651:e/fragmentone (1633): OnCreate
07-20 08:18:46.651:e/fragmentone (1633): OnCreate
07-20 08:18:46.651:e/fragmentone (1633): OnCreate
07-20 08:18:46.681:e/fragmentone (1633): Oncreateview
07-20 08:18:46.831:e/fragmentone (1633): Oncreateview
07-20 08:18:46.891:e/fragmentone (1633): Oncreateview

This is why, because when the screen spins, the activity restarts, and the fragment in the default activity is recreated with the activity, which causes the fragment to be restarted when the rotation occurs, Then, when the oncreate of the activity is executed, a new fragment is instantiated again, which is why it appears.

So how to solve it:

In fact, by checking the parameters of OnCreate bundle Savedinstancestate can determine whether the current occurrence of the re-create activity:

The default Savedinstancestate stores some data, including instances of fragment: by printing, you can see:

07-20 08:23:12.952:e/fragmentone (1782): Bundle[{android:fragments=android.app.fragmentmanagerstate@40d0b7b8, android:viewhierarchystate=bundle[{android:focusedviewid=2131230721, android:views=android.util.sparsearray@ 40D0AF68}]}]

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"; 
  Private Fragmentone Mfone; 
  @Override 
  protected 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 made.

There is still a problem, that is, when redrawing, fragment, the original data how to maintain?

In fact, similar to activity, fragment also has a Onsaveinstancestate method for saving data in this method, and then restoring either OnCreate or Oncreateview or onactivitycreated.

For space reasons, no test code is posted.

5, Fragmeny and Actionbar and MenuItem integration

Fragment can add their own MenuItem to the Actionbar or optional menu of the activity.

A, call Sethasoptionsmenu (True) in the fragment OnCreate;

b, and then implement the Oncreateoptionsmenu in the fragment subclass

C, if you want to handle MenuItem clicks in fragment, you can also implement onoptionsitemselected; the activity can also handle the MenuItem click event directly.

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 {@Override public void onCreate (Bundle savedinstancestate) {sup 
    Er.oncreate (savedinstancestate); 
  Sethasoptionsmenu (TRUE);  
  @Override public View Oncreateview (layoutinflater inflater, ViewGroup container, Bundle savedinstancestate) 
    {View view = Inflater.inflate (R.layout.fragment_one, container, false); 
  return view; @Override public void Oncreateoptionsmenu (Menu menu, Menuinflater inflater) {inflater.inflate (R.menu.frag 
  Ment_menu, menu);  @Override public 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"; 
  Private Fragmentone Mfone; 
    @Override protected 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 (); }} @Override public boolean oncreateoptionsmeNu (Menu menu) {super.oncreateoptionsmenu (menu); 
    Getmenuinflater (). Inflate (R.menu.main, menu); 
  return true;  @Override public 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.xxx return super.onoptionsitemselected (item); } 
  } 
}

Effect Chart:

Well, can be very good to see, fragment can add MenuItem, you can also handle the Click ~ ~ ~

6, no layout of the role of fragment

No layout file fragment is actually meant to be saved, when the activity restarts, save a large amount of data prepared

Please refer to blog: The best solution for Android screen rotation to handle asynctask and ProgressDialog

7, use fragment to create a dialog box

This is the Google recommended way, I also wrote a separate blog introduction, please refer to: Android Official Recommendation: dialogfragment Create dialog box

Well, finally put fragment related to together, the above basic contains fragment all the usage ~ ~ ~ I believe that if you can read, there must be a lot of harvest ~ ~ ~ Through the combination of two articles to learn, I believe that the fragment have a lot of harvest it, Practical application to the project to go, have any questions, welcome to my message, thank you!

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.