0. Review
Fragment represents an action or part of the user interface in an activity. Multiple Fragment in an activity can be grouped together to form a patchwork of user-interface components that can be reused in multiple activity. A Fragment can be viewed as a modular part of an activity that has its own lifecycle and receives its own input events, which can be added or removed at any time during the running of the event (a bit like "child activity", which can be weighed in different instances) Used).
Fragment must be embedded in an activity whose lifecycle is directly affected by the life cycle of the host activity. For example, when an activity is paused (paused), all Fragment within it are paused. And when the activity is destroyed, its Fragment will be destroyed. However, during the activity run (the lifecycle State is in the recovery (resumed) state), each Fragment can be manipulated independently, such as add or remove. When performing these operational transactions, you can also add them to the activity's fallback stack (back stack), where each entry to the-activity fallback stack is an Fragment transaction record. The fallback stack allows the user to back up the Fragment transaction (one step back) by pressing the back key.
When Fragment is added to the activity Layout (Layout), it is located in a viewgroup of the Activity View hierarchy (hierarchy) and has its own view layout definition. By declaring the <fragment> element in the Layout file of the activity, you can add a fragment to the Layout. You can also add a Fragment to an existing viewgroup with program code. However, Fragment does not necessarily have to be part of the activity layout, it may not have its own interface, but rather as a non-visual workgroup for activity.
1. Overview
I believe that everyone is not unfamiliar with the fragment, for the use of fragment, on the one hand, the activity needs to be arranged in the layout for the fragment position, on the other hand, the need to manage the fragment life cycle. There is a fragmentmanager in the activity that maintains the fragment queue internally and the fallback stack for the fragment transaction.
In general, we add fragment to the activity:
public class Mainactivity extends fragmentactivity
{
private contentfragment mcontentfragment;
@Override
protected void onCreate (Bundle savedinstancestate)
{
super.oncreate (savedinstancestate);
Setcontentview (r.layout.activity_main);
Fragmentmanager fm = Getsupportfragmentmanager ();
Mcontentfragment = (contentfragment) Fm.findfragmentbyid (r.id.id_fragment_container);
if (mcontentfragment = = null)
{
mcontentfragment = new Contentfragment ();
Fm.begintransaction (). Add (R.id.id_fragment_container,mcontentfragment). commit ();
}
}
For the above code, ask two questions:
(1) Why should we be sentenced to null?
The main reason is that when the activity changes (the screen spins) or the memory is not enough to be killed by the system, causing the fragment to be recreated, we will be saved, but a new fragmentmanager will be created, The new Fragmentmanager will first get the saved fragment queue, rebuild the fragment queue, and restore the previous state.
(2) How does the ID of the layout in Add (r.id.id_fragment_container,mcontentfragment) work?
On the one hand, it is to inform the Fragmentmanager, the position of this fragment, on the other hand, is the unique identification of this fragment; like we're above through Fm.findfragmentbyid (R.id.id_fragment_ Container) Find ~ ~
OK, a brief review of the basic usage, the specific also please refer to the above blog or other materials, next, introduce some of the views of use ~ ~
2, Fragment Arguments
The following describes a simple scenario, such as one of our buttons that triggers an activity jump and needs to pass intent parameters to the fragment of the target activity, so how does this fragment get the current intent value?
A guy would say, this is simple? Look at my Code (question code):
public class Contentfragment extends Fragment
{
private String margument;
public static final String ARGUMENT = "ARGUMENT";
@Override public
void OnCreate (Bundle savedinstancestate)
{
super.oncreate (savedinstancestate);
Margument = Getactivity (). Getintent (). Getstringextra (ARGUMENT);
We are directly in the fragment OnCreate, to get the host activty, host activity will certainly be able to get intent through the getintent, and then through get method, random take parameters ~ ~
So write, functional is realized, but? There is a big problem: one of the big reasons we use fragment is to reuse it. You write this, the equivalent of this fragment has been completely and the current host activity binding, reuse direct waste ~ ~ ~ So? We recommend using arguments to create fragment in a different way.
public class Contentfragment extends Fragment {private String margument;
public static final String ARGUMENT = "ARGUMENT";
@Override public void OnCreate (Bundle savedinstancestate) {super.oncreate (savedinstancestate);
Margument = Getactivity (). Getintent (). Getstringextra (ARGUMENT);
Bundle Bundle = getarguments ();
if (bundle!= null) Margument = bundle.getstring (ARGUMENT); /** * Incoming required parameters, set to arguments * @param argument * * @return/public static contentfragment Newinsta
NCE (String argument) {Bundle Bundle = new Bundle ();
Bundle.putstring (ARGUMENT, ARGUMENT);
Contentfragment contentfragment = new Contentfragment ();
Contentfragment.setarguments (bundle);
return contentfragment; }
Add the Newinstance method to the fragment, pass the required parameters to the bundle, then setarguments (bundle) and obtain it in the OnCreate;
This completes the decoupling between the fragment and the activity. Of course, you need to be aware of this:
The Setarguments method must be completed before the activity is added to the fragment after it is created. Never, first call add, then set arguments.
3, fragment of Startactivityforresult
It's still a simple scene: Two fragment, a fragment (called listtitlefragment) that shows the list of articles, a fragment that displays details (called contentfragment), and of course, These two fragment have their host activity.
Now, we clicked the list item in the list fragment, passed the corresponding parameter, went to the detailed information fragment to show the detailed information, in the detailed information page, the user can carry on the comment, when the user clicks back, Our previous reviews results are displayed in the list item for the fragment of the list;
That is, we click to jump to the fragment of the corresponding activity, and we want it to be able to return parameters, then we definitely use Fragment.startactivityforresult;
There are Startactivityforresult () and Onactivityresult () methods in fragment, but there is no Setresult () method for setting the returned intent. So we need to call Getactivity (). Setresult (Listtitlefragment.request_detail, intent);
Detailed code:
Listtitlefragment
public class Listtitlefragment extends Listfragment {public static final int request_detail = 0x110;
Private list<string> Mtitles = Arrays.aslist ("Hello", "World", "Android");
private int mcurrentpos;
Private arrayadapter<string> Madapter; @Override public void onactivitycreated (Bundle savedinstancestate) {super.onactivitycreated (savedinstancestate
); Setlistadapter (madapter = new arrayadapter<string> (Getactivity (), Android.
R.layout.simple_list_item_1, Mtitles)); @Override public void Onlistitemclick (ListView l, View v, int position, long id) {Mcurrentpos = posit
Ion;
Intent Intent = new Intent (getactivity (), contentactivity.class);
Intent.putextra (Contentfragment.argument, mtitles.get (position));
Startactivityforresult (Intent, request_detail); @Override public void Onactivityresult (int requestcode, int resultcode, Intent data) {LOG.E ("TAG"), "Onactivityresult");
Super.onactivityresult (Requestcode, ResultCode, data); if (Requestcode = = Request_detail) {mtitles.set (Mcurrentpos, Mtitles.get (mcurrentpos) + "--" +data.getstringext
RA (contentfragment.response));
Madapter.notifydatasetchanged ();
}
}
}
Contentfragment
public class Contentfragment extends Fragment {private String margument;
public static final String ARGUMENT = "ARGUMENT";
public static final String RESPONSE = "RESPONSE";
@Override public void OnCreate (Bundle savedinstancestate) {super.oncreate (savedinstancestate);
Bundle Bundle = getarguments ();
if (bundle!= null) {margument = bundle.getstring (ARGUMENT);
Intent Intent = new Intent ();
Intent.putextra (RESPONSE, "good");
Getactivity (). Setresult (Listtitlefragment.request_detail, intent);
} public static Contentfragment newinstance (String argument) {Bundle Bundle = new Bundle ();
Bundle.putstring (ARGUMENT, ARGUMENT);
Contentfragment contentfragment = new Contentfragment ();
Contentfragment.setarguments (bundle);
return contentfragment; @Override public View Oncreateview (layoutinflater inflater, ViewGroup container, Bundle savedinstancestat
E) { Random Random = new Random ();
TextView TV = new TextView (getactivity ());
Tv.settext (margument);
Tv.setgravity (Gravity.center); Tv.setbackgroundcolor (Color.argb (Random.nextint), Random.nextint (255), Random.nextint (255), Random.nextInt (25
5));
return TV;
}
}
The
posted two fragment code, We can see that we are in Listtitlefragment.onlistitemclick, using Startactivityforresult () to jump to the target activity and get it in the fragment (contentfragment) of the target activity. parameter, and then call Getactivity (). Setresult (Listtitlefragment.request_detail, intent); Set the returned data Finally, the Listtitlefragment.onactivityresult () gets the returned data to Echo;
provides a solution for you later when you encounter a similar problem Also illustrates a problem: fragment can receive return results from an activity, but its own cannot produce return results, only the activity has the return result.
Next I want to post a host of these two fragment activity:
Listtitleactivity
public class Listtitleactivity extends fragmentactivity
{
private listtitlefragment mlistfragment;
@Override
protected void onCreate (Bundle savedinstancestate)
{
super.oncreate (savedinstancestate);
Setcontentview (r.layout.activity_single_fragment);
Fragmentmanager fm = Getsupportfragmentmanager ();
Mlistfragment = (listtitlefragment) Fm.findfragmentbyid (r.id.id_fragment_container);
if (mlistfragment = = null)
{
mlistfragment = new Listtitlefragment ();
Fm.begintransaction (). Add (R.id.id_fragment_container,mlistfragment). commit ();
}
}
Contentactivity:
public class Contentactivity extends fragmentactivity
{
private contentfragment mcontentfragment;
@Override
protected void onCreate (Bundle savedinstancestate)
{
super.oncreate (savedinstancestate);
Setcontentview (r.layout.activity_single_fragment);
Fragmentmanager fm = Getsupportfragmentmanager ();
Mcontentfragment = (contentfragment) Fm.findfragmentbyid (r.id.id_fragment_container);
if (mcontentfragment = = null)
{
String title = Getintent (). Getstringextra (contentfragment.argument);
Mcontentfragment = contentfragment.newinstance (title);
Fm.begintransaction (). Add (R.id.id_fragment_container,mcontentfragment). commit ();
}
}
Did you find that the code in the two activity was extremely similar and used the same layout file:
Activity_single_fragment.xml
<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 "
android:id= "@+id/id_fragment_container"
>
</RelativeLayout>
Why do you have to put this acticity code on? Because in our project, if we use Fragment in principle, we will find a lot of similar code, then we can abstract an activity out, hosting our single Fragment.
4, Singlefragmentactivity
so the code for the abstract activity is:
Package com.example.demo_zhy_23_fragments;
Import Android.os.Bundle;
Import android.support.v4.app.Fragment;
Import android.support.v4.app.FragmentActivity;
Import Android.support.v4.app.FragmentManager;
Public abstract class Singlefragmentactivity extends fragmentactivity
{
protected abstract Fragment Createfragment ();
@Override
protected void onCreate (Bundle savedinstancestate)
{
super.oncreate (savedinstancestate);
Setcontentview (r.layout.activity_single_fragment);
Fragmentmanager fm = Getsupportfragmentmanager ();
Fragment Fragment =fm.findfragmentbyid (r.id.id_fragment_container);
if (fragment = = null)
{
fragment = Createfragment ();
Fm.begintransaction (). Add (R.id.id_fragment_container,fragment). commit ();
}
}
So, with this singlefragmentactivity, our contentactivity and listtitleactivity can also change to a big body ~
Package com.example.demo_zhy_23_fragments;
Import android.support.v4.app.Fragment;
public class Contentactivity extends singlefragmentactivity
{
private contentfragment mcontentfragment;
@Override
protected Fragment createfragment ()
{
String title = Getintent (). Getstringextra ( contentfragment.argument);
Mcontentfragment = contentfragment.newinstance (title);
Return mcontentfragment
}
}
Package com.example.demo_zhy_23_fragments;
Import android.support.v4.app.Fragment;
public class Listtitleactivity extends singlefragmentactivity
{
private listtitlefragment mlistfragment;
@Override
protected Fragment createfragment ()
{
mlistfragment = new Listtitlefragment ();
Return mlistfragment
}
}
is not a lot of simplicity, believe that priority to use fragment projects, similar activity is very much, using singlefragmentactivity to simplify your code it ~ ~
OK, this code is from the beginning of the book recommended, recommended again ~ ~.
5, Fragmentpageradapter and Fragmentstatepageradapter
believe that these two pageradapter, we are not unfamiliar with it ~ ~ Since the advent of fragment, the use of Viewpager combined with any one of the above examples of the production of the app homepage of the case particularly much ~ ~ ~
So what's the difference between these two classes?
The main difference is in relation to whether or not the fragment is destroyed, the following elaborate:
(1) Fragmentpageradapter: For fragment that are no longer needed, select the Invoke Detach method, destroy only the view, and do not destroy the fragment instance.
(2) Fragmentstatepageradapter: Destroys the fragment that is no longer needed, and when the current transaction is committed, the Fragmeng is completely removed from the fragmentmanager of the current activity, the state indicates, When destroyed, the Bundle information in its onsaveinstancestate (Bundle outstate) is saved, and when the user switches back, a new Bundle can be generated through the fragment, that is to say, You can save some data in the Onsaveinstancestate (Bundle outstate) method and restore the creation in OnCreate.
As mentioned above, the use of Fragmentstatepageradapter of course more memory, but it also takes time to destroy new. In general, if you are making the main page, 3, 4 tab, then you can choose to use Fragmentpageradapter, if you are used to viewpager display a large number of items, Then it is recommended to use Fragmentstatepageradapter.
Space reasons, the specific case will not be written, we test themselves.
6, data transfer between fragment
above 3, we show the data transfer between two general fragment.
Then there is a special case where two fragment are in the same activity: for example, click the current Fragment button and pop up a dialog box (dialogfragment), The operation in the dialog box needs to be returned to the triggering fragment, so how is the data passed? Recommended for use with dialogs: Android Official recommendation: Dialogfragment Create a dialog box
We continue to modify our code: Now Listtitlefragment, Contentfragment, Add a dialog box: Evaluatedialog, the user clicks Contentfragment content when pop-up an evaluation list, the user chooses the appraisal.
Now our focus is on how to gracefully get the evaluatedialog back in the contentfragment:
Remember that we're in an activity and then definitely not using Startactivityforresult , but the data we return is still being received in Onactivityresult.
Okay, look at the code:
contentfragment
public class Contentfragment extends Fragment {private String margument;
public static final String ARGUMENT = "ARGUMENT";
public static final String RESPONSE = "RESPONSE";
public static final String Evaluate_dialog = "Evaluate_dialog";
public static final int request_evaluate = 0x110; ... @Override public View oncreateview (layoutinflater inflater, ViewGroup container, Bundle savedinstance
State) {Random Random = new Random ();
TextView TV = new TextView (getactivity ()); Viewgroup.layoutparams params = new Viewgroup.layoutparams (layoutparams.match_parent, layoutparams.match_parent)
;
Tv.setlayoutparams (params);
Tv.settext (margument);
Tv.setgravity (Gravity.center); Tv.setbackgroundcolor (Color.argb (Random.nextint), Random.nextint (255), Random.nextint (255), Random.nextInt (25
5)); Set Click Tv.setonclicklistener (New Onclicklistener () {@Override public voidOnClick (View v) {evaluatedialog dialog = new Evaluatedialog ();
Note Settargetfragment dialog.settargetfragment (contentfragment.this, request_evaluate);
Dialog.show (Getfragmentmanager (), evaluate_dialog);
}
});
return TV; //Receive returned data @Override public void Onactivityresult (int requestcode, int resultcode, Intent data) {su
Per.onactivityresult (Requestcode, ResultCode, data); if (Requestcode = = request_evaluate) {String EVALUATE = data. Getstringextra (evaluatedialog.respon
Se_evaluate);
Toast.maketext (Getactivity (), evaluate, Toast.length_short). Show ();
Intent Intent = new Intent ();
Intent.putextra (RESPONSE, evaluate);
Getactivity (). Setresult (ACTIVITY.REQUEST_OK, intent);
}
}
}
Remove some extraneous code, and notice that we added the Click event for TextView in Oncreateview to eject our dialog and note one line of code:
Dialog.settargetfragment ( Contentfragment.this, request_evaluate);
We call the Fragment.settargetfragment, this method, is generally used for the current fragment by other fragment start, after the completion of the operation to return data, in line with our needs ~ ~ ~ Note, this sentence is very important.
Next look at the Evaluatedialog code:
Package com.example.demo_zhy_23_fragments;
Import android.app.Activity;
Import Android.app.AlertDialog;
Import Android.app.Dialog;
Import Android.content.DialogInterface;
Import Android.content.DialogInterface.OnClickListener;
Import android.content.Intent;
Import Android.os.Bundle;
Import android.support.v4.app.DialogFragment; public class Evaluatedialog extends Dialogfragment {private string[] mevalutevals = new string[] {"Good", "bad", "NO"
Rmal "};
public static final String response_evaluate = "Response_evaluate"; @Override public Dialog Oncreatedialog (Bundle savedinstancestate) {Alertdialog.builder Builder = new alertdial og.
Builder (Getactivity ());
Builder.settitle ("Evaluate:"). Setitems (Mevalutevals, New Onclicklistener () {@Override
public void OnClick (Dialoginterface dialog, int which) {setresult (which);
}
});
return Builder.create ();
}Set return data protected void Setresult (int which) {//To determine if the targetfragment if (gettargetfragment () = null) is set
Return
Intent Intent = new Intent ();
Intent.putextra (Response_evaluate, Mevalutevals[which]);
Gettargetfragment (). Onactivityresult (Contentfragment.request_evaluate, ACTIVITY.RESULT_OK, intent);
}
}
The point is to look at the Setresult after the click, we first determine whether the set up targetfragment, if set, means we want to return some data to targetfragment.
We create intent encapsulation good need to pass data, finally manually call Onactivityresult to return data ~ ~
Finally, we can receive the Onactivityresult in Contentfragment.
OK, finally put these tips into the together, to this our fragment some of the recommendations of the use of the end ~ ~ ~ Then, finally provide the source code, also by the way to put a effect map: