Android Tutorial - Core Class : Fragment
extends Fragment
package app.test; import android.app.Activity; import android.app.Fragment; import android.app.FragmentManager; import android.app.FragmentTransaction; import android.app.ListFragment; import android.content.Intent; import android.content.res.Configuration; import android.os.Bundle; import android.util.AttributeSet; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.ListView; import android.widget.TextView; class TitlesFragment extends ListFragment { private Test myActivity = null; int mCurCheckPosition = 0; @Override public void onInflate(AttributeSet attrs, Bundle icicle) { for (int i = 0; i < attrs.getAttributeCount(); i++) { Log.v("",attrs.getAttributeName(i) + " = " + attrs.getAttributeValue(i)); } super.onInflate(attrs, icicle); } @Override public void onAttach(Activity myActivity) { super.onAttach(myActivity); this.myActivity = (Test) myActivity; } @Override public void onCreate(Bundle icicle) { if (icicle != null) { for (String key : icicle.keySet()) { Log.v(Test.TAG, " " + key); } }super.onCreate(icicle); if (icicle != null) { mCurCheckPosition = icicle.getInt("curChoice", 0); } } @Override public View onCreateView(LayoutInflater myInflater, ViewGroup container, Bundle icicle) { return super.onCreateView(myInflater, container, icicle); } @Override public void onActivityCreated(Bundle icicle) { if (icicle != null) { for (String key : icicle.keySet()) { Log.v(Test.TAG, " " + key); } } super.onActivityCreated(icicle); setListAdapter(new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1, new String[] { "A", "B", "C", "D", })); ListView lv = getListView(); lv.setChoiceMode(ListView.CHOICE_MODE_SINGLE); lv.setSelection(mCurCheckPosition); myActivity.showDetails(mCurCheckPosition); } @Override public void onStart() { super.onStart(); } @Override public void onResume() { super.onResume(); } @Override public void onPause() { super.onPause(); } @Override public void onSaveInstanceState(Bundle icicle) { super.onSaveInstanceState(icicle); icicle.putInt("curChoice", mCurCheckPosition); } @Override public void onListItemClick(ListView l, View v, int pos, long id) { myActivity.showDetails(pos); mCurCheckPosition = pos; } @Override public void onStop() { super.onStop(); } @Override public void onDestroyView() { super.onDestroyView(); } @Override public void onDestroy() { super.onDestroy(); } @Override public void onDetach() { super.onDetach(); myActivity = null; } } class DetailsActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) { finish(); return; } if (getIntent() != null) { DetailsFragment details = DetailsFragment.newInstance(getIntent() .getExtras()); getFragmentManager().beginTransaction() .add(android.R.id.content, details).commit(); } } } class DetailsFragment extends Fragment { private int mIndex = 0; public static DetailsFragment newInstance(int index) { DetailsFragment df = new DetailsFragment(); Bundle args = new Bundle(); args.putInt("index", index); df.setArguments(args); return df; } public static DetailsFragment newInstance(Bundle bundle) { int index = bundle.getInt("index", 0); return newInstance(index); } @Override public void onInflate(AttributeSet attrs, Bundle savedInstanceState) { for (int i = 0; i < attrs.getAttributeCount(); i++) Log.v("",attrs.getAttributeName(i) + " = " + attrs.getAttributeValue(i)); super.onInflate(attrs, savedInstanceState); } @Override public void onAttach(Activity myActivity) { super.onAttach(myActivity); } @Override public void onCreate(Bundle myBundle) { if (myBundle != null) { for (String key : myBundle.keySet()) { Log.v(Test.TAG, " " + key); } }super.onCreate(myBundle); mIndex = getArguments().getInt("index", 0); } public int getShownIndex() { return mIndex; } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View v = inflater.inflate(R.layout.row, container, false); TextView text1 = (TextView) v.findViewById(R.id.text1); text1.setText(""); return v; } @Override public void onActivityCreated(Bundle savedState) { if (savedState != null) { for (String key : savedState.keySet()) { Log.v(Test.TAG, " " + key); } } super.onActivityCreated(savedState); } @Override public void onStart() { super.onStart(); } @Override public void onResume() { super.onResume(); } @Override public void onPause() { super.onPause(); } @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); } @Override public void onStop() { super.onStop(); } @Override public void onDestroyView() { super.onDestroyView(); } @Override public void onDestroy() { super.onDestroy(); } @Override public void onDetach() { super.onDetach(); } } public class Test extends Activity { public static final String TAG = "Test"; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); FragmentManager.enableDebugLogging(true); setContentView(R.layout.main); } @Override public void onAttachFragment(Fragment fragment) { super.onAttachFragment(fragment); } @Override public void onStart() { super.onStart(); } @Override public void onResume() { super.onResume(); } @Override public void onPause() { super.onPause(); } @Override public void onStop() { super.onStop(); } @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); } @Override public void onDestroy() { super.onDestroy(); } public boolean isMultiPane() { return getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE; } public void showDetails(int index) { if (isMultiPane()) { DetailsFragment details = (DetailsFragment) getFragmentManager() .findFragmentById(R.id.details); if (details == null || details.getShownIndex() != index) { details = DetailsFragment.newInstance(index); FragmentTransaction ft = getFragmentManager() .beginTransaction(); ft.setCustomAnimations(R.animator.bounce_in_down, R.animator.slide_out_down); ft.replace(R.id.details, details); ft.commit(); getFragmentManager().executePendingTransactions(); } } else { Intent intent = new Intent(); intent.setClass(this, DetailsActivity.class); intent.putExtra("index", index); startActivity(intent); } } } //layout/main.xml <?xml version="1.0" encoding="utf-8"?> <!-- This file is res/layout/main.xml --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <fragment class="app.test.TitlesFragment" android:id="@+id/titles" android:layout_width="match_parent" android:layout_height="match_parent" /> android:background="#00550033" /> <FrameLayout android:id="@+id/details" android:layout_weight="2" android:layout_width="0px" android:layout_height="match_parent" /> </LinearLayout> //layout/row.xml <?xml version="1.0" encoding="utf-8"?> <!-- This file is res/layout/details.xml --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <ScrollView android:id="@+id/scroller" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id="@+id/text1" android:layout_width="match_parent" android:layout_height="match_parent" /> </ScrollView> </LinearLayout> //animator/bounce_in_down.xml <?xml version="1.0" encoding="utf-8" ?> <objectAnimator xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@android:interpolator/bounce" android:valueFrom="-1280" android:valueTo="0" android:valueType="floatType" android:propertyName="Y" android:duration="2000" /> //animator/slide_out_down.xml <?xml version="1.0" encoding="utf-8" ?> <set xmlns:android="http://schemas.android.com/apk/res/android"> <objectAnimator android:interpolator="@android:interpolator/accelerate_cubic" android:valueFrom="0" android:valueTo="1280" android:valueType="floatType" android:propertyName="Y" android:duration="2000" /> <objectAnimator android:interpolator="@android:interpolator/accelerate_cubic" android:valueFrom="1" android:valueTo="0" android:valueType="floatType" android:propertyName="Alpha" android:duration="2000" /> </set>
Demonstration of hiding and showing fragments.
package com.example.android.apis.app; import com.example.android.apis.R; import android.app.Activity; 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.ViewGroup; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.TextView; /** * Demonstration of hiding and showing fragments. */ public class FragmentHideShow extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.fragment_hide_show); // The content view embeds two fragments; now retrieve them and attach // their "hide" button. FragmentManager fm = getFragmentManager(); addShowHideListener(R.id.frag1hide, fm.findFragmentById(R.id.fragment1)); addShowHideListener(R.id.frag2hide, fm.findFragmentById(R.id.fragment2)); } void addShowHideListener(int buttonId, final Fragment fragment) { final Button button = (Button)findViewById(buttonId); button.setOnClickListener(new OnClickListener() { public void onClick(View v) { FragmentTransaction ft = getFragmentManager().beginTransaction(); ft.setCustomAnimations(android.R.animator.fade_in, android.R.animator.fade_out); if (fragment.isHidden()) { ft.show(fragment); button.setText("Hide"); } else { ft.hide(fragment); button.setText("Show"); } ft.commit(); } }); } public static class FirstFragment extends Fragment { TextView mTextView; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View v = inflater.inflate(R.layout.labeled_text_edit, container, false); View tv = v.findViewById(R.id.msg); ((TextView)tv).setText("The fragment saves and restores this text."); // Retrieve the text editor, and restore the last saved state if needed. mTextView = (TextView)v.findViewById(R.id.saved); if (savedInstanceState != null) { mTextView.setText(savedInstanceState.getCharSequence("text")); } return v; } @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); // Remember the current text, to restore if we later restart. outState.putCharSequence("text", mTextView.getText()); } } public static class SecondFragment extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View v = inflater.inflate(R.layout.labeled_text_edit, container, false); View tv = v.findViewById(R.id.msg); ((TextView)tv).setText("The TextView saves and restores this text."); // Retrieve the text editor and tell it to save and restore its state. // Note that you will often set this in the layout XML, but since // we are sharing our layout with the other fragment we will customize // it here. ((TextView)v.findViewById(R.id.saved)).setSaveEnabled(true); return v; } } } //fragment_hide_show.xml <?xml version="1.0" encoding="utf-8"?> <!-- Copyright (C) 2010 The Android Open Source Project Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. --> <!-- Top-level content view for the layout fragment sample. --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:gravity="center_horizontal" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_vertical|center_horizontal" android:textAppearance="?android:attr/textAppearanceMedium" android:text="Demonstration of hiding and showing fragments." /> <LinearLayout android:orientation="horizontal" android:padding="4dip" android:gravity="center_vertical" android:layout_weight="1" android:layout_width="match_parent" android:layout_height="wrap_content"> <Button android:id="@+id/frag1hide" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hide" /> <fragment android:name="com.example.android.apis.app.FragmentHideShow$FirstFragment" android:id="@+id/fragment1" android:layout_weight="1" android:layout_width="0px" android:layout_height="wrap_content" /> </LinearLayout> <LinearLayout android:orientation="horizontal" android:padding="4dip" android:gravity="center_vertical" android:layout_weight="1" android:layout_width="match_parent" android:layout_height="wrap_content"> <Button android:id="@+id/frag2hide" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hide" /> <fragment android:name="com.example.android.apis.app.FragmentHideShow$SecondFragment" android:id="@+id/fragment2" android:layout_weight="1" android:layout_width="0px" android:layout_height="wrap_content" /> </LinearLayout> </LinearLayout>
Demonstration of using ListFragment to show a list of items from a canned array.
package com.example.android.apis.app; import com.example.android.apis.Shakespeare; import android.app.Activity; import android.app.ListFragment; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.ArrayAdapter; import android.widget.ListView; /** * Demonstration of using ListFragment to show a list of items * from a canned array. */ public class FragmentListArray extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Create the list fragment and add it as our sole content. if (getFragmentManager().findFragmentById(android.R.id.content) == null) { ArrayListFragment list = new ArrayListFragment(); getFragmentManager().beginTransaction().add(android.R.id.content, list).commit(); } } public static class ArrayListFragment extends ListFragment { @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); setListAdapter(new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1, Shakespeare.TITLES)); } @Override public void onListItemClick(ListView l, View v, int position, long id) { Log.i("FragmentList", "Item clicked: " + id); } } } package com.example.android.apis; public final class Shakespeare { /** * Our data, part 1. */ public static final String[] TITLES = { "Henry IV (1)", "Henry V", "Henry VIII", "Richard II", "Richard III", "Merchant of Venice", "Othello", "King Lear" }; /** * Our data, part 2. */ public static final String[] DIALOGUE = { "So shaken as we are, so wan with care," + "Find we a time for frighted peace to pant," + "And breathe short-winded accents of new broils" + "To be commenced in strands afar remote." + "No more the thirsty entrance of this soil" + "Shall daub her lips with her own children's blood;" + "Nor more shall trenching war channel her fields," + "Nor bruise her flowerets with the armed hoofs" + "Of hostile paces: those opposed eyes," + "Which, like the meteors of a troubled heaven," + "All of one nature, of one substance bred," + "Did lately meet in the intestine shock" + "And furious close of civil butchery" + "Shall now, in mutual well-beseeming ranks," + "March all one way and be no more opposed" + "Against acquaintance, kindred and allies:" + "The edge of war, like an ill-sheathed knife," + "No more shall cut his master. Therefore, friends," + "As far as to the sepulchre of Christ," + "Whose soldier now, under whose blessed cross" + "We are impressed and engaged to fight," + "Forthwith a power of English shall we levy;" + "Whose arms were moulded in their mothers' womb" + "To chase these pagans in those holy fields" + "Over whose acres walk'd those blessed feet" + "Which fourteen hundred years ago were nail'd" + "For our advantage on the bitter cross." + "But this our purpose now is twelve month old," + "And bootless 'tis to tell you we will go:" + "Therefore we meet not now. Then let me hear" + "Of you, my gentle cousin Westmoreland," + "What yesternight our council did decree" + "In forwarding this dear expedience.", "Hear him but reason in divinity," + "And all-admiring with an inward wish" + "You would desire the king were made a prelate:" + "Hear him debate of commonwealth affairs," + "You would say it hath been all in all his study:" + "List his discourse of war, and you shall hear" + "A fearful battle render'd you in music:" + "Turn him to any cause of policy," + "The Gordian knot of it he will unloose," + "Familiar as his garter: that, when he speaks," + "The air, a charter'd libertine, is still," + "And the mute wonder lurketh in men's ears," + "To steal his sweet and honey'd sentences;" + "So that the art and practic part of life" + "Must be the mistress to this theoric:" + "Which is a wonder how his grace should glean it," + "Since his addiction was to courses vain," + "His companies unletter'd, rude and shallow," + "His hours fill'd up with riots, banquets, sports," + "And never noted in him any study," + "Any retirement, any sequestration" + "From open haunts and popularity.", "I come no more to make you laugh: things now," + "That bear a weighty and a serious brow," + "Sad, high, and working, full of state and woe," + "Such noble scenes as draw the eye to flow," + "We now present. Those that can pity, here" + "May, if they think it well, let fall a tear;" + "The subject will deserve it. Such as give" + "Their money out of hope they may believe," + "May here find truth too. Those that come to see" + "Only a show or two, and so agree" + "The play may pass, if they be still and willing," + "I'll undertake may see away their shilling" + "Richly in two short hours. Only they" + "That come to hear a merry bawdy play," + "A noise of targets, or to see a fellow" + "In a long motley coat guarded with yellow," + "Will be deceived; for, gentle hearers, know," + "To rank our chosen truth with such a show" + "As fool and fight is, beside forfeiting" + "Our own brains, and the opinion that we bring," + "To make that only true we now intend," + "Will leave us never an understanding friend." + "Therefore, for goodness' sake, and as you are known" + "The first and happiest hearers of the town," + "Be sad, as we would make ye: think ye see" + "The very persons of our noble story" + "As they were living; think you see them great," + "And follow'd with the general throng and sweat" + "Of thousand friends; then in a moment, see" + "How soon this mightiness meets misery:" + "And, if you can be merry then, I'll say" + "A man may weep upon his wedding-day.", "First, heaven be the record to my speech!" + "In the devotion of a subject's love," + "Tendering the precious safety of my prince," + "And free from other misbegotten hate," + "Come I appellant to this princely presence." + "Now, Thomas Mowbray, do I turn to thee," + "And mark my greeting well; for what I speak" + "My body shall make good upon this earth," + "Or my divine soul answer it in heaven." + "Thou art a traitor and a miscreant," + "Too good to be so and too bad to live," + "Since the more fair and crystal is the sky," + "The uglier seem the clouds that in it fly." + "Once more, the more to aggravate the note," + "With a foul traitor's name stuff I thy throat;" + "And wish, so please my sovereign, ere I move," + "What my tongue speaks my right drawn sword may prove.", "Now is the winter of our discontent" + "Made glorious summer by this sun of York;" + "And all the clouds that lour'd upon our house" + "In the deep bosom of the ocean buried." + "Now are our brows bound with victorious wreaths;" + "Our bruised arms hung up for monuments;" + "Our stern alarums changed to merry meetings," + "Our dreadful marches to delightful measures." + "Grim-visaged war hath smooth'd his wrinkled front;" + "And now, instead of mounting barded steeds" + "To fright the souls of fearful adversaries," + "He capers nimbly in a lady's chamber" + "To the lascivious pleasing of a lute." + "But I, that am not shaped for sportive tricks," + "Nor made to court an amorous looking-glass;" + "I, that am rudely stamp'd, and want love's majesty" + "To strut before a wanton ambling nymph;" + "I, that am curtail'd of this fair proportion," + "Cheated of feature by dissembling nature," + "Deformed, unfinish'd, sent before my time" + "Into this breathing world, scarce half made up," + "And that so lamely and unfashionable" + "That dogs bark at me as I halt by them;" + "Why, I, in this weak piping time of peace," + "Have no delight to pass away the time," + "Unless to spy my shadow in the sun" + "And descant on mine own deformity:" + "And therefore, since I cannot prove a lover," + "To entertain these fair well-spoken days," + "I am determined to prove a villain" + "And hate the idle pleasures of these days." + "Plots have I laid, inductions dangerous," + "By drunken prophecies, libels and dreams," + "To set my brother Clarence and the king" + "In deadly hate the one against the other:" + "And if King Edward be as true and just" + "As I am subtle, false and treacherous," + "This day should Clarence closely be mew'd up," + "About a prophecy, which says that 'G'" + "Of Edward's heirs the murderer shall be." + "Dive, thoughts, down to my soul: here" + "Clarence comes.", "To bait fish withal: if it will feed nothing else," + "it will feed my revenge. He hath disgraced me, and" + "hindered me half a million; laughed at my losses," + "mocked at my gains, scorned my nation, thwarted my" + "bargains, cooled my friends, heated mine" + "enemies; and what's his reason? I am a Jew. Hath" + "not a Jew eyes? hath not a Jew hands, organs," + "dimensions, senses, affections, passions? fed with" + "the same food, hurt with the same weapons, subject" + "to the same diseases, healed by the same means," + "warmed and cooled by the same winter and summer, as" + "a Christian is? If you prick us, do we not bleed?" + "if you tickle us, do we not laugh? if you poison" + "us, do we not die? and if you wrong us, shall we not" + "revenge? If we are like you in the rest, we will" + "resemble you in that. If a Jew wrong a Christian," + "what is his humility? Revenge. If a Christian" + "wrong a Jew, what should his sufferance be by" + "Christian example? Why, revenge. The villany you" + "teach me, I will execute, and it shall go hard but I" + "will better the instruction.", "Virtue! a fig! 'tis in ourselves that we are thus" + "or thus. Our bodies are our gardens, to the which" + "our wills are gardeners: so that if we will plant" + "nettles, or sow lettuce, set hyssop and weed up" + "thyme, supply it with one gender of herbs, or" + "distract it with many, either to have it sterile" + "with idleness, or manured with industry, why, the" + "power and corrigible authority of this lies in our" + "wills. If the balance of our lives had not one" + "scale of reason to poise another of sensuality, the" + "blood and baseness of our natures would conduct us" + "to most preposterous conclusions: but we have" + "reason to cool our raging motions, our carnal" + "stings, our unbitted lusts, whereof I take this that" + "you call love to be a sect or scion.", "Blow, winds, and crack your cheeks! rage! blow!" + "You cataracts and hurricanoes, spout" + "Till you have drench'd our steeples, drown'd the cocks!" + "You sulphurous and thought-executing fires," + "Vaunt-couriers to oak-cleaving thunderbolts," + "Singe my white head! And thou, all-shaking thunder," + "Smite flat the thick rotundity o' the world!" + "Crack nature's moulds, an germens spill at once," + "That make ingrateful man!" }; }
Fragment Stack
package com.example.android.apis.app; import com.example.android.apis.R; import android.app.Activity; import android.app.Fragment; import android.app.FragmentTransaction; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.TextView; public class FragmentStack extends Activity { int mStackLevel = 1; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.fragment_stack); // Watch for button clicks. Button button = (Button)findViewById(R.id.new_fragment); button.setOnClickListener(new OnClickListener() { public void onClick(View v) { addFragmentToStack(); } }); if (savedInstanceState == null) { // Do first time initialization -- add initial fragment. Fragment newFragment = CountingFragment.newInstance(mStackLevel); FragmentTransaction ft = getFragmentManager().beginTransaction(); ft.add(R.id.simple_fragment, newFragment).commit(); } else { mStackLevel = savedInstanceState.getInt("level"); } } @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putInt("level", mStackLevel); } void addFragmentToStack() { mStackLevel++; // Instantiate a new fragment. Fragment newFragment = CountingFragment.newInstance(mStackLevel); // Add the fragment to the activity, pushing this transaction // on to the back stack. FragmentTransaction ft = getFragmentManager().beginTransaction(); ft.replace(R.id.simple_fragment, newFragment); ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN); ft.addToBackStack(null); ft.commit(); } public static class CountingFragment extends Fragment { int mNum; /** * Create a new instance of CountingFragment, providing "num" * as an argument. */ static CountingFragment newInstance(int num) { CountingFragment f = new CountingFragment(); // Supply num input as an argument. Bundle args = new Bundle(); args.putInt("num", num); f.setArguments(args); return f; } /** * When creating, retrieve this instance's number from its arguments. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mNum = getArguments() != null ? getArguments().getInt("num") : 1; } /** * The Fragment's UI is just a simple text view showing its * instance number. */ @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View v = inflater.inflate(R.layout.hello_world, container, false); View tv = v.findViewById(R.id.text); ((TextView)tv).setText("Fragment #" + mNum); tv.setBackgroundDrawable(getResources().getDrawable(android.R.drawable.gallery_thumb)); return v; } } } //layout/fragment_stack.xml <?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"> <fragment class="com.example.android.apis.app.FragmentLayout$TitlesFragment" android:id="@+id/titles" android:layout_width="match_parent" android:layout_height="match_parent" /> </FrameLayout>
Use Fragment to propagate state across activity instances when an activity needs to be restarted due to a configuration change.
package com.example.android.apis.app; import com.example.android.apis.R; import android.app.Activity; import android.app.Fragment; import android.app.FragmentManager; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.ProgressBar; /** * This example shows how you can use a Fragment to easily propagate state * (such as threads) across activity instances when an activity needs to be * restarted due to, for example, a configuration change. This is a lot * easier than using the raw Activity.onRetainNonConfiguratinInstance() API. */ public class FragmentRetainInstance extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // First time init, create the UI. if (savedInstanceState == null) { getFragmentManager().beginTransaction().add(android.R.id.content, new UiFragment()).commit(); } } /** * This is a fragment showing UI that will be updated from work done * in the retained fragment. */ public static class UiFragment extends Fragment { RetainedFragment mWorkFragment; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View v = inflater.inflate(R.layout.fragment_retain_instance, container, false); // Watch for button clicks. Button button = (Button)v.findViewById(R.id.restart); button.setOnClickListener(new OnClickListener() { public void onClick(View v) { mWorkFragment.restart(); } }); return v; } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); FragmentManager fm = getFragmentManager(); // Check to see if we have retained the worker fragment. mWorkFragment = (RetainedFragment)fm.findFragmentByTag("work"); // If not retained (or first time running), we need to create it. if (mWorkFragment == null) { mWorkFragment = new RetainedFragment(); // Tell it who it is working with. mWorkFragment.setTargetFragment(this, 0); fm.beginTransaction().add(mWorkFragment, "work").commit(); } } } /** * This is the Fragment implementation that will be retained across * activity instances. It represents some ongoing work, here a thread * we have that sits around incrementing a progress indicator. */ public static class RetainedFragment extends Fragment { ProgressBar mProgressBar; int mPosition; boolean mReady = false; boolean mQuiting = false; /** * This is the thread that will do our work. It sits in a loop running * the progress up until it has reached the top, then stops and waits. */ final Thread mThread = new Thread() { @Override public void run() { // We'll figure the real value out later. int max = 10000; // This thread runs almost forever. while (true) { // Update our shared state with the UI. synchronized (this) { // Our thread is stopped if the UI is not ready // or it has completed its work. while (!mReady || mPosition >= max) { if (mQuiting) { return; } try { wait(); } catch (InterruptedException e) { } } // Now update the progress. Note it is important that // we touch the progress bar with the lock held, so it // doesn't disappear on us. mPosition++; max = mProgressBar.getMax(); mProgressBar.setProgress(mPosition); } // Normally we would be doing some work, but put a kludge // here to pretend like we are. synchronized (this) { try { wait(50); } catch (InterruptedException e) { } } } } }; /** * Fragment initialization. We way we want to be retained and * start our thread. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Tell the framework to try to keep this fragment around // during a configuration change. setRetainInstance(true); // Start up the worker thread. mThread.start(); } /** * This is called when the Fragment's Activity is ready to go, after * its content view has been installed; it is called both after * the initial fragment creation and after the fragment is re-attached * to a new activity. */ @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); // Retrieve the progress bar from the target's view hierarchy. mProgressBar = (ProgressBar)getTargetFragment().getView().findViewById( R.id.progress_horizontal); // We are ready for our thread to go. synchronized (mThread) { mReady = true; mThread.notify(); } } /** * This is called when the fragment is going away. It is NOT called * when the fragment is being propagated between activity instances. */ @Override public void onDestroy() { // Make the thread go away. synchronized (mThread) { mReady = false; mQuiting = true; mThread.notify(); } super.onDestroy(); } /** * This is called right before the fragment is detached from its * current activity instance. */ @Override public void onDetach() { // This fragment is being detached from its activity. We need // to make sure its thread is not going to touch any activity // state after returning from this function. synchronized (mThread) { mProgressBar = null; mReady = false; mThread.notify(); } super.onDetach(); } /** * API for our UI to restart the progress thread. */ public void restart() { synchronized (mThread) { mPosition = 0; mThread.notify(); } } } } //layout/fragment_retain_instance.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="8dp"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:textAppearance="?android:attr/textAppearanceMedium" android:text="fragment_retain_instance_msg" /> <ProgressBar android:id="@+id/progress_horizontal" style="?android:attr/progressBarStyleHorizontal" android:layout_width="200dip" android:layout_height="wrap_content" android:layout_gravity="center" android:padding="6dp" android:max="500" /> <Button android:id="@+id/restart" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:text="restart"> <requestFocus /> </Button> </LinearLayout>
extends Fragment to display result
package com.example.android.apis.app; import com.example.android.apis.R; import android.app.Activity; import android.app.Fragment; import android.app.FragmentTransaction; import android.content.Intent; import android.os.Bundle; import android.text.Editable; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.Button; import android.widget.FrameLayout; import android.widget.TextView; public class FragmentReceiveResult extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); FrameLayout frame = new FrameLayout(this); frame.setId(R.id.simple_fragment); setContentView(frame, lp); if (savedInstanceState == null) { // Do first time initialization -- add fragment. Fragment newFragment = new ReceiveResultFragment(); FragmentTransaction ft = getFragmentManager().beginTransaction(); ft.add(R.id.simple_fragment, newFragment).commit(); } } public static class ReceiveResultFragment extends Fragment { // Definition of the one requestCode we use for receiving resuls. static final private int GET_CODE = 0; private TextView mResults; private OnClickListener mGetListener = new OnClickListener() { public void onClick(View v) { // Start the activity whose result we want to retrieve. The // result will come back with request code GET_CODE. Intent intent = new Intent(getActivity(), SendResult.class); startActivityForResult(intent, GET_CODE); } }; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View v = inflater.inflate(R.layout.receive_result, container, false); // Retrieve the TextView widget that will display results. mResults = (TextView)v.findViewById(R.id.results); // This allows us to later extend the text buffer. mResults.setText(mResults.getText(), TextView.BufferType.EDITABLE); // Watch for button clicks. Button getButton = (Button)v.findViewById(R.id.get); getButton.setOnClickListener(mGetListener); return v; } /** * This method is called when the sending activity has finished, with the * result it supplied. */ @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { // You can use the requestCode to select between multiple child // activities you may have started. Here there is only one thing // we launch. if (requestCode == GET_CODE) { // We will be adding to our text. Editable text = (Editable)mResults.getText(); // This is a standard resultCode that is sent back if the // activity doesn't supply an explicit result. It will also // be returned if the activity failed to launch. if (resultCode == RESULT_CANCELED) { text.append("(cancelled)"); // Our protocol with the sending activity is that it will send // text in 'data' as its result. } else { text.append("(okay "); text.append(Integer.toString(resultCode)); text.append(") "); if (data != null) { text.append(data.getAction()); } } text.append("\n"); } } } } //layout/receive_result.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:padding="4dip" android:gravity="center_horizontal" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="0" android:paddingBottom="4dip" android:textAppearance="?android:attr/textAppearanceMedium" android:text="@string/receive_result_instructions"/> <TextView android:id="@+id/results" android:layout_width="match_parent" android:layout_height="10dip" android:layout_weight="1" android:paddingBottom="4dip" android:textAppearance="?android:attr/textAppearanceMedium" android:textColor="#000" android:background="@drawable/green"> </TextView> <Button android:id="@+id/get" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="0" android:text="@string/receive_result_result"> <requestFocus /> </Button> </LinearLayout>
Demonstration of PreferenceFragment, showing a single fragment in an activity.
package com.example.android.apis.preference; import com.example.android.apis.R; import android.app.Activity; import android.os.Bundle; import android.preference.PreferenceFragment; /** * Demonstration of PreferenceFragment, showing a single fragment in an * activity. */ public class FragmentPreferences extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Display the fragment as the main content. getFragmentManager().beginTransaction().replace(android.R.id.content, new PrefsFragment()).commit(); } public static class PrefsFragment extends PreferenceFragment { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Load the preferences from an XML resource addPreferencesFromResource(R.xml.preferences); } } } //xml/preferences.xml <?xml version="1.0" encoding="utf-8"?> <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> <PreferenceCategory android:title="@string/inline_preferences"> <CheckBoxPreference android:key="checkbox_preference" android:title="@string/title_toggle_preference" android:summary="@string/summary_toggle_preference" /> </PreferenceCategory> <PreferenceCategory android:title="@string/dialog_based_preferences"> <EditTextPreference android:key="edittext_preference" android:title="@string/title_edittext_preference" android:summary="@string/summary_edittext_preference" android:dialogTitle="@string/dialog_title_edittext_preference" /> <ListPreference android:key="list_preference" android:title="@string/title_list_preference" android:summary="@string/summary_list_preference" android:entries="@array/entries_list_preference" android:entryValues="@array/entryvalues_list_preference" android:dialogTitle="@string/dialog_title_list_preference" /> </PreferenceCategory> <PreferenceCategory android:title="@string/launch_preferences"> <!-- This PreferenceScreen tag serves as a screen break (similar to page break in word processing). Like for other preference types, we assign a key here so it is able to save and restore its instance state. --> <PreferenceScreen android:key="screen_preference" android:title="@string/title_screen_preference" android:summary="@string/summary_screen_preference"> <!-- You can place more preferences here that will be shown on the next screen. --> <CheckBoxPreference android:key="next_screen_checkbox_preference" android:title="@string/title_next_screen_toggle_preference" android:summary="@string/summary_next_screen_toggle_preference" /> </PreferenceScreen> <PreferenceScreen android:title="@string/title_intent_preference" android:summary="@string/summary_intent_preference"> <intent android:action="android.intent.action.VIEW" android:data="http://www.android.com" /> </PreferenceScreen> </PreferenceCategory> <PreferenceCategory android:title="@string/preference_attributes"> <CheckBoxPreference android:key="parent_checkbox_preference" android:title="@string/title_parent_preference" android:summary="@string/summary_parent_preference" /> <!-- The visual style of a child is defined by this styled theme attribute. --> <CheckBoxPreference android:key="child_checkbox_preference" android:dependency="parent_checkbox_preference" android:layout="?android:attr/preferenceLayoutChild" android:title="@string/title_child_preference" android:summary="@string/summary_child_preference" /> </PreferenceCategory> </PreferenceScreen>
Get child element, inner element, outer element, parse Fragment
import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.StringReader; import java.io.StringWriter; import java.util.ArrayList; import java.util.List; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.OutputKeys; import javax.xml.transform.Result; import javax.xml.transform.Source; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.TransformerFactoryConfigurationError; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import org.w3c.dom.Document; import org.w3c.dom.DocumentFragment; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.xml.sax.InputSource; import org.xml.sax.SAXException; class XmlUtils { public static List<Element> getChildrenByTagName(Element parent, String name) { return XmlUtils.getChildrenByTagName(parent, new String[] { name }); } public static List<Element> getChildrenByTagName(Element parent, String[] names) { List<Element> nodeList = new ArrayList<Element>(); for (Node child = parent.getFirstChild(); child != null; child = child .getNextSibling()) { if (child.getNodeType() == Node.ELEMENT_NODE) { for (String name : names) { if (name.equals(child.getNodeName())) { nodeList.add((Element) child); break; } } } } return nodeList; } public static Element getFirstChildByTagName(Element parent, String name) { List<Element> list = XmlUtils.getChildrenByTagName(parent, new String[] { name }); if (list.size() > 0) return list.get(0); else return null; } public static String getInnerXml(Node node) throws ParserConfigurationException, TransformerFactoryConfigurationError, TransformerException { StringBuilder sb = new StringBuilder(); for (int i = 0; i < node.getChildNodes().getLength(); i++) sb.append(getOuterXml(node.getChildNodes().item(i))); return sb.toString(); } public static String getOuterXml(Node n) throws ParserConfigurationException, TransformerFactoryConfigurationError, TransformerException { Transformer xformer = TransformerFactory.newInstance().newTransformer(); xformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); // initialize StreamResult with File object to save to file StreamResult result = new StreamResult(new StringWriter()); DOMSource source = new DOMSource(n); xformer.transform(source, result); String xmlString = result.getWriter().toString(); return xmlString; } public static DocumentFragment parseFragment(Document doc, String xml) throws SAXException, IOException, ParserConfigurationException { DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentFragment fragment = doc.createDocumentFragment(); String wellformedxml = "<__parseFragment__>" + xml + "</__parseFragment__>"; Document fragmentdoc = dbf.newDocumentBuilder().parse( new InputSource(new StringReader(wellformedxml))); Node node = doc.importNode(fragmentdoc.getDocumentElement(), true); while (node.hasChildNodes()) { fragment.appendChild(node.removeChild(node.getFirstChild())); } return fragment; } public static void removeAllChildren(Node node) { while (node.hasChildNodes()) { node.removeChild(node.getFirstChild()); } } public static void setInnerXml(Node node, String xml) throws SAXException, IOException, ParserConfigurationException { DocumentFragment fragment; fragment = XmlUtils.parseFragment(node.getOwnerDocument(), xml); XmlUtils.removeAllChildren(node); node.appendChild(fragment); return; } /* * save a XML Document to a file */ public static void writeXmlFile(Document doc, String filename) throws TransformerConfigurationException, TransformerException, IOException { writeXmlFile(doc, filename, true); } public static void writeXmlFile(Document doc, String filename, boolean indent) throws TransformerConfigurationException, TransformerException, IOException { Source source = new DOMSource(doc); FileOutputStream outputStream = new FileOutputStream(filename); Result result = new StreamResult(new OutputStreamWriter(outputStream, "UTF8")); doc.setXmlStandalone(true); // Write the DOM document to the file TransformerFactory factory = TransformerFactory.newInstance(); factory.setAttribute("indent-number", 4); Transformer xformer = factory.newTransformer(); xformer.setOutputProperty(OutputKeys.INDENT, "yes"); xformer.setOutputProperty(OutputKeys.METHOD, "xml"); xformer.setOutputProperty(OutputKeys.ENCODING, "UTF8"); xformer.transform(source, result); } }