Sie sind auf Seite 1von 39

Lesson 6.

Fragments

Android Fragments .............................................................................................3


Lesson 6
Android Fragments

Goals

The Android Eco-System


Parallelism through Fragments

Fragment's Life Cycle

1 2 3 4 5 6 7 8 9 10  11 

onAttach onCreate onCreateView onACtivityCreated onStart onResume onPause onStop onDestroyView onDestroy onDetach

Created Started Resumed Paused Stopped Destroyed


Rules for Inter-Fragment Communication



Integrating the Home Activity and its Fragments


<fragment>
android:name=fragmentName

Dynamic Binding
FragmentTransaction
add()
replace()

FragmentManager
FragmentTransaction ft= getFragmentManager().beginTransaction();

FragmentBlue blueFragment= FragmentBlue.newInstance("some_param_value");

ft.replace(R.id.main_holder_blue, blueFragment);

ft.commit();

// create a new BLUE fragment - show it


ft = getFragmentManager().beginTransaction();
blueFragment = FragmentBlue.newInstance("new-blue");
ft.replace(R.id.main_holder_blue, blueFragment);
ft.commit();

// create a new RED fragment - show it


ft = getFragmentManager().beginTransaction();
redFragment = FragmentRed.newInstance("new-red");
ft.replace(R.id.main_holder_red, redFragment);
ft.commit();
Note

import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.app.Fragment;

Example 6.1 An App using Dynamic Fragment Binding

TextView
TextView
MainActivity FragmentBlue FragmentRed
IFragmentCallbacks IMainCallbacks
MainActivity MainActivity
activity_main.xml layout_blue.xml layout_red

<?xml version="1.0" encoding="utf-8"?>


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:baselineAligned="false"
android:padding="16dp"
android:orientation="vertical">
<TextView
android:id="@+id/txtHomeMsg"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#ffea00"
android:layout_marginBottom="10dp"
android:text="MainActivity area"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<FrameLayout
android:id="@+id/main_holder_blue"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="#220000ff"
android:orientation="vertical"/>
<FrameLayout
android:id="@+id/main_holder_red"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="2"
android:background="#22ff0000"
android:orientation="vertical"/>
</LinearLayout>
</LinearLayout>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/layout_blue"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#220000FF"
android:orientation="vertical" >
<TextView
android:id="@+id/textView1Blue"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Blue Layout..."
android:textColor="@android:color/white"
android:background="#0000FF"
android:textAppearance="?android:attr/textAppearanceLarge" />
<ListView
android:id="@+id/listView1Blue"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</ListView>
</LinearLayout>

<?xml version="1.0" encoding="utf-8"?>


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/layout_red"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#22FF0000"
android:orientation="vertical">
<TextView
android:id="@+id/textView1Red"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#d50000"
android:text="Red Layout..."
android:textColor="@android:color/white"
android:textAppearance="?android:attr/textAppearanceLarge" />
<Button
android:id="@+id/button1Red"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="20dp"
android:ems="10"
android:text="Click me!" />
</LinearLayout>

package csu.matos;

import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentTransaction;
import android.util.Log;
import android.widget.TextView;
import android.widget.Toast;

//-----------------------------------------------------------------------
// GOAL: This example shows an Activity that includes two fragments.
// Fragments inflate layouts and then get attached to their corresponding
// layouts in the UI. The example includes two interfaces IMainCallbacks
// and IFragmentCallbacks. They implement inter-process communication from
// Main-to-fragments and from Fragments-to-Main.
// -----------------------------------------------------------------------
public class MainActivity extends FragmentActivity implements IMainCallbacks {

FragmentTransaction ft;
FragmentRed redFragment;
FragmentBlue blueFragment;
TextView txtHomeMsg;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
txtHomeMsg = (TextView) findViewById(R.id.txtHomeMsg);

// create a new BLUE fragment - show it


ft = getSupportFragmentManager().beginTransaction();
blueFragment = FragmentBlue.newInstance("first-blue");
ft.replace(R.id.main_holder_blue, blueFragment);
ft.commit();

// create a new RED fragment - show it


ft = getSupportFragmentManager().beginTransaction();
redFragment = FragmentRed.newInstance("first-red");
ft.replace(R.id.main_holder_red, redFragment);
ft.commit();

// MainCallback implementation (receiving messages coming from Fragments)


@Override
public void onMsgFromFragToMain(String sender, String strValue) {
// show message arriving to MainActivity
txtHomeMsg.setText("Sender=" + sender + " Message=" + strValue);
Toast.makeText(getApplication(),
" MAIN GOT>> " + sender + "\n" + strValue, Toast.LENGTH_LONG)
.show();

if (sender.equals("RED-FRAG")) {
// TODO: if needed, do here something on behalf of the RED fragment
}

if (sender.equals("BLUE-FRAG")) {
try {
// forward blue-data to redFragment using its callback method
redFragment.onMsgFromMainToFragment("\nSender: " + sender
+ "\nMsg: " + strValue);

} catch (Exception e) {
Log.e("ERROR", "onStrFromFragToMain " + e.getMessage());
}
}

beginTransaction commit

newInstance

activity_main.xml

onMsgFromFragToMain IMainCallbacks
redFragment blueFragment MainActivity

blueFragment redFragment
onMsgFromMainToFragment
import android.support.v4.app.Fragment;
import ...

public class FragmentBlue extends Fragment {


// this fragment shows a ListView
MainActivity main;
Context context = null;
String message = "";

// data to fill-up the ListView


private String items[] = { "Text-on-Line-00", "Text-on-Line-01",
"Text-on-Line-02", "Text-on-Line-03", "Text-on-Line-04",
"Text-on-Line-05", "Text-on-Line-06", "Text-on-Line-07",
"Text-on-Line-08", "Text-on-Line-09", "Text-on-Line-10", };

// convenient constructor(accept arguments, copy them to a bundle, binds bundle to fragment)


public static FragmentBlue newInstance(String strArg) {
FragmentBlue fragment = new FragmentBlue();
Bundle args = new Bundle();
args.putString("strArg1", strArg);
fragment.setArguments(args);
return fragment;
}

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
try {
context = getActivity(); // use this reference to invoke main callbacks
main = (MainActivity) getActivity();
} catch (IllegalStateException e) {
throw new IllegalStateException(
"MainActivity must implement callbacks");
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {

// inflate res/layout_blue.xml to make GUI holding a TextView and a ListView


LinearLayout layout_blue = (LinearLayout) inflater.inflate(R.layout.layout_blue, null);

// plumbing – get a reference to textview and listview


final TextView txtBlue = (TextView) layout_blue.findViewById(R.id.textView1Blue);
ListView listView = (ListView) layout_blue.findViewById(R.id.listView1Blue);
listView.setBackgroundColor(Color.parseColor("#ffccddff"));

// define a simple adapter to fill rows of the listview


ArrayAdapter<String> adapter = new ArrayAdapter<String>(context,
android.R.layout.simple_list_item_1, items);
listView.setAdapter(adapter);
// show listview from the top
listView.setSelection(0);
listView.smoothScrollToPosition(0);

// react to click events on listview’s rows


listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
// inform enclosing MainActivity of the row’s position just selected
main.onMsgFromFragToMain("BLUE-FRAG", "Blue selected row=" + position);
txtBlue.setText("Blue selected row=" + position);
}
});

// do this for each row (ViewHolder-Pattern could be used for better performance!)
return layout_blue;

}// onCreateView
}// class

Class.newInstance()

Bundle
<key,value>
setArguments()

onCreate() MainActivity
MainActivity

onCreateView()
layout_blue.xml TextView
ListView

ArrayAdapter ListView

ListView
onMsgFromFragToMain

import android.support.v4.app.Fragment;
import ...

public class FragmentRed extends Fragment implements IFragmentCallbacks {


MainActivity main;
TextView txtRed;
Button btnRedClock;

public static FragmentRed newInstance(String strArg1) {


FragmentRed fragment = new FragmentRed();
Bundle bundle = new Bundle();
bundle.putString("arg1", strArg1);
fragment.setArguments(bundle);
return fragment;
}// newInstance

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Activities containing this fragment must implement interface: IMainCallbacks
if (!(getActivity() instanceof IMainCallbacks)) {
throw new IllegalStateException( " Activity must implement IMainCallbacks");
}
main = (MainActivity) getActivity(); // use this reference to invoke main callbacks
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// inflate res/layout_red.xml which includes a textview and a button
LinearLayout view_layout_red = (LinearLayout) inflater.inflate(
R.layout.layout_red, null);
// plumbing - get a reference to widgets in the inflated layout
txtRed = (TextView) view_layout_red.findViewById(R.id.textView1Red);

// show string argument supplied by constructor (if any!)


try {
Bundle arguments = getArguments();
String redMessage = arguments.getString("arg1", "");
txtRed.setText(redMessage);
} catch (Exception e) {
Log.e("RED BUNDLE ERROR - ", "" + e.getMessage());
}
// clicking the button changes the time displayed and sends a copy to MainActivity
btnRedClock = (Button) view_layout_red.findViewById(R.id.button1Red);
btnRedClock.setOnClickListener(new View.OnClickListener() {

@Override
public void onClick(View v) {
String redMessage = "Red clock:\n" + new Date().toString();
txtRed.setText(redMessage);
main.onMsgFromFragToMain("RED-FRAG", redMessage);
}
});
return view_layout_red;
}

@Override
public void onMsgFromMainToFragment(String strValue) {
// receiving a message from MainActivity (it may happen at any point in time)
txtRed.setText("THIS MESSAGE COMES FROM MAIN:" + strValue);
}

}// FragmentRed
FragmentBlue

newInstance

FragmentRed onCreate() MainActivity

FragmentRed MainActivity
onMsgFromMainToFragment

blueFragment

public interface IMainCallbacks {

public void onMsgFromFragToMain (String senderId, String strMsg);

public interface IFragmentCallbacks {

public void onMsgFromMainToFragment(String strValue);

Fragments MainActivity onCreate()

Example 6.2 Static Fragment Binding

MainActivity FragmentRed
FragmentBlue

layout_red.xml layout_blue.xml


<fragment>

1. android:name="AppPackageName.FragmentClassName"

2. android:id="@id+/uniqueName"

3. android:tag="string"

<?xml version="1.0" encoding="utf-8"?>


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:baselineAligned="false"
android:orientation="vertical"
android:padding="16dp">

<TextView
android:id="@+id/txtHomeMsg"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:background="#ffea00"
android:text="MainActivity area"/>

<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">

<fragment
android:id="@+id/main_holder_blue"
android:name="csu.matos.FragmentBlue"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"/>

<fragment
android:id="@+id/main_holder_red"
android:name="csu.matos.FragmentRed"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="2"/>
</LinearLayout>
</LinearLayout>

package csu.matos;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.app.Fragment;
import ...
//-----------------------------------------------------------------------
// GOAL: This example shows an Activity that includes two fragments.
// Fragments inflate layouts and then get attached to their corresponding
// layouts in the UI. The example includes two interfaces IMainCallbacks
// and IFragmentCallbacks. They implement inter-process communication from
// Main-to-fragments and from Fragments-to-Main.
// -----------------------------------------------------------------------
public class MainActivity extends FragmentActivity implements IMainCallbacks {

FragmentTransaction ft;
FragmentRed redFragment;
FragmentBlue blueFragment;
TextView txtHomeMsg;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
txtHomeMsg = (TextView) findViewById(R.id.txtHomeMsg);

// NOTHING to do, fragments will be automatically created and added to the GUI
}

@Override
public void onAttachFragment(Fragment fragment) {
super.onAttachFragment(fragment);
// (just in case...) get a reference to each fragment now attached to the GUI
if (fragment.getClass() == FragmentRed.class ){
redFragment = (FragmentRed) fragment;

}
if (fragment.getClass() == FragmentBlue.class ){
blueFragment = (FragmentBlue) fragment;

}
}

// MainCallback implementation (receiving messages coming from Fragments)


@Override
public void onMsgFromFragToMain(String sender, String strValue) {
// show message arriving to MainActivity
txtHomeMsg.setText("Sender=" + sender + " Message=" + strValue);
Toast.makeText(getApplication(), " MAIN GOT>> " + sender
+ "\n" + strValue, Toast.LENGTH_LONG).show();

if (sender.equals("RED-FRAG")) {
// TODO: if needed, do here something on behalf of the RED fragment
}

if (sender.equals("BLUE-FRAG")) {
try {
// forward blue-data(master) to redFragment(detail) using its callback method
redFragment.onMsgFromMainToFragment("\nSender: " + sender
+ "\nMsg: " + strValue);

} catch (Exception e) {
Log.e("ERROR", "onStrFromFragToMain " + e.getMessage());
}
}

FragmentRed FragmentBlue layout_red.xml layout_blue.xml

onCreate() onCreateView()
android:name="csu.matos.FragmentXYZ"

onAttachFragment
redFragment blueFragment

onMsgFromFragToMain blueFragment MainActivity


blueFragment redFragment

Fragment FragmentACtivity
FragmentTransaction
Example 6.3 Mixed Mode Binding
Fragment1Blue
Fragment2Red
Fragment3Orange
IFragmentCallbacks
MainActivity MainActivity IMainCallbacks

EditText MainActivity

activity_main.xml
fragment1Blue layout2_red.xml layout_red.xml

<LinearLayout android:id="@+id/home0"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="@android:color/white"
android:padding="16dp">
<TextView
android:id="@+id/txtMsgMain"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="3dp"
android:background="#FFFFEA00"
android:textSize="25sp"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:padding="10dp"
android:orientation="horizontal">
<fragment
android:id="@+id/home1"
android:name="csu.matos.matos.Fragment1Blue"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"/>
<View
android:layout_width="5dp"
android:layout_height="match_parent"
android:layout_margin="3dp"
android:background="#616161"/>
<fragment
android:id="@+id/home2"
android:name="csu.matos.matos.Fragment2Red"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="2"/>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="5dp"
android:layout_margin="1dp"
android:background="#616161"/>
<LinearLayout
android:id="@+id/home3"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="2dp"
android:layout_weight="2"
android:background="#e0e0e0"
android:orientation="vertical"
android:padding="1dp"/>
</LinearLayout>

<LinearLayout> home3
Fragment3Orange, i
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffcc80"
android:orientation="vertical"
android:padding="3dp">
<TextView
android:id="@+id/txtMsg3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#E65100"
android:gravity="center"
android:padding="2dp"
android:text="THIS IS LAYOUT3"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textColor="@android:color/white"/>
<EditText
android:id="@+id/ediBox3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Enter some data here"
android:inputType="none"/>
<View
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="3"/>
<Button
android:id="@+id/btnGo3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ems="5"
android:background="@android:drawable/btn_default"
android:text="Go"/>
</LinearLayout>

ActivityMain.java

import android.app.Fragment; // not using compatibility lib


import android.app.FragmentTransaction;
import ...

public class MainActivity extends Activity implements IMainCallbacks {

//plumbing: defining space for three fragments to be shown


TextView txtMsgMain;
LinearLayout home3;
Fragment1Blue frag1Blue;
Fragment2Red frag2Red;
Fragment3Orange frag3Orange;
// var used to save values returned from fragments
String mainStrValue = "n.a.";

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
txtMsgMain =(TextView)findViewById(R.id.txtMsgMain);
home3 = (LinearLayout)findViewById(R.id.home3);

// create f3 (Fragment3Orange), pass to it a string param, collocate f3 into home3 UI area


FragmentTransaction fragTransMngr3 = getFragmentManager().beginTransaction();
Bundle args3 = new Bundle();
args3.putString("strParam", "Hello world");
Fragment3Orange f3 = new Fragment3Orange();
f3.setArguments(args3);
fragTransMngr3.replace(home3.getId(), f3, "F3TAG");
fragTransMngr3.commit();
}

@Override
public void onAttachFragment(Fragment fragment) {
super.onAttachFragment(fragment);
// get a reference to each fragment attached to the GUI
if (fragment.getClass() == Fragment1Blue.class) {
frag1Blue = (Fragment1Blue) fragment;
}
if (fragment.getClass() == Fragment2Red.class) {
frag2Red = (Fragment2Red) fragment;
}
if (fragment.getClass() == Fragment3Orange.class) {
frag3Orange = (Fragment3Orange) fragment;
}
}

@Override
public void onMsgFromFragmentToMain(String sender, String strValue) {
txtMsgMain.setText(sender + " strValue= " + strValue);
if (sender.equals("Frag1Blue")){
// Dynamically identify current fragment inside a given UI container: (1) use
// findFragmmebtById(...) to get a reference to current fragment hosted by UI,
// (2) then send a message to the fragment.
Fragment2Red redFrag = (Fragment2Red)getFragmentManager().findFragmentById(R.id.home2);
redFrag.onMsgFromMainToFragment("1Main says..." + strValue);
// NOTE: the state method onFragmentAttached already saved a reference to the red
// fragment in the global variable: frag2Red. Consequently the above code is
// equivalent to: frag2Red.onMsgFromMainToFragment("2Main says..." + strValue);
}
}

}
MainActivity onCreate, onAttachFragment onMsgFromFragentToMain
onCreate TextBox
onAttachFragment
onMsgFromFragmentToMain

frag1Blue
frag2Red Fragment1Blue Fragment2Red
IMainCallbacks IFragmentCallbacks
Fragment3Orange

public class Fragment3Orange extends Fragment {


// a reference to superclass hosting this fragment
IMainCallbacks mainCallbackRef;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

// TODO: do this inside try-catch or check instanceOf...


mainCallbackRef = (IMainCallbacks) getActivity();

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// echo supplied input parameter
String arg1 = getArguments().getString("strParam");
Log.e("Fragment3", "I got strParam=" + arg1);

// inflate a layout showing a textbox and a button


// do plumbing, get access to textbox and button-clicking
LinearLayout layout3 = (LinearLayout) inflater.inflate(R.layout.layout3_orange, null);
TextView txtMsg3 = (TextView) layout3.findViewById(R.id.txtMsg3);
final EditText ediBox3 = (EditText) layout3.findViewById(R.id.ediBox3);

Button btnGo3 = (Button) layout3.findViewById(R.id.btnGo3);


btnGo3.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {
String text = ediBox3.getText().toString();
Toast.makeText(getActivity(), text, Toast.LENGTH_SHORT).show();
mainCallbackRef.onMsgFromFragmentToMain("LAYOUT3-INT", text + " " + new Date());
}
});
// layout has been set
return layout3;
}
@Override
public void onPause() {
// save any important data here (row indices, textbox content)
super.onPause();
}

@Override
public void onDestroy() {
// the end is near! - release your possessions
super.onDestroy();
mainCallbackRef = null;
}
}

Saving Fragment's State Data

onSaveInstanceState

onCreate onCreateView onViewCreated onViewStateRestored

onRestoreInstanceState

saveInstanceState

savedInstanceState
.

if (savedInstanceState == null) {
//cold-start: create new fragment, pass arguments, add or replace fragment to UI
FragmentTransaction fragTransMngr = getFragmentManager().beginTransaction();
Bundle args = new Bundle();
args.putString("strParam1", "some string value here...");
frag = new YourFragment();
frag.setArguments(args);
fragTransMngr.replace(fragmentContainerInsideHostUI.getId(), frag, "FRAGMENT-TAG");
fragTransMngr.commit();
}
@Override
public void onCreate(Bundle savedInstanceState) {
...
String initialData = getArguments().getString("arg1", "cold-start-default-value");
...
if (savedInstanceState != null){
// warm-start: reusing fragments, extract state data from saved bundle
stateData1 = savedInstanceState.getString("stateData1","str-warm-default-1");
stateData2 = savedInstanceState.getInt("stateData2", int-warm-default-2);
}
}//onCreate
...

//use next method to temporarily save fragment's state data


@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("stateData1", someStringToBeSaved);
outstate.putInt("stateData2", someIntegerToBeSaved);
...
} //onSavedInstanceState

Operations on Fragments

FragmentTransaction

• add()

<FrameLayout>

<LinearLayout>
<LinearLayout>

• remove()
BackStack
• replace()
• show() / hide()
• attach() / detach()
redFragment <FrameLayout> main_ui_holder.

FragmentTransaction ft = getFragmentManager().beginTransaction();

redFragment = FragmentRed.newInstance(intValue);
ft.replace(R.id.main_ui_holder, redFragment, "RED-TAG"); //fragment's view is displayed
//destroying previous fragment (if any!)

ft.add(R.id.main_ui_holder, redFragment, "RED-TAG"); //fragment's view overlaps UI

ft.hide(redFragment); //fragment's view becomes invisible


ft.show(redFragment); //fragment's view is displayed

ft.detach(redFragment); //fragment's view is removed from UI (not destroyed)


ft.attach(redFragment); //fragment's view is displayed

ft.commit();

// find out what fragment is currently shown inside a given UI container


Fragment currentGuest = (Fragment)getFragmentManager().findFragmentById(R.id.main_holder);

Using the BackStack to Recreate State

BackStack
FragmentTransactions)

Back

BackStack
Back BackStack
BackStack

BackStack

BackStack
BackStack

BackStack

FragmentTransaction ft = getFragmentManager().beginTransaction();
Fragment redFragment = FragmentRed.newInstance(intParameterValue);
ft.replace(R.id.main_ui_holder, redFragment, "RED-FRAG1");
ft.addToBackStack("FRAGTRAN-RED1");
ft.commit();

FragmentTransaction ft
FragmentRed . "RED-FRAG1"

main_ui_holder "RED-FRAG1"

Fragment fragmentInstance = (Fragment)getFragmentManager().findFragmentById(R.id.ui_home)

ft.addToBackStack("FRAGTRAN-RED1");

BackStack
FRAGTRAN-RED1
BackStack BackStack
"FRAGTRAN-RED1"

BackStack

• .popBackStackImmediate(id,flag) BackStack
id
"FRAGTRAN-RED1" flag
FragmentManager.POP_BACK_STACK_INCLUSIVE.

// Remove current fragment’s UI and show its immediate predecessor


try {
FragmentTransaction ft = getFragmentManager().beginTransaction();
FragmentManager fragmentManager = getFragmentManager();
// find out how many entries are there in the BackStack
int bsCount = fragmentManager.getBackStackEntryCount();
// NOTE: bottom of the stack is at location 0, while its top is at position (bsCount – 1)
// obtain the id and tag of the BackStack's top (last) entry
String tag = fragmentManager.getBackStackEntryAt(bsCount-1).getName();
int id = fragmentManager.getBackStackEntryAt(bsCount-1).getId();
// use reference to remove fragments up to matching id (inclusive), expose previous (if any!)
fragmentManager.popBackStackImmediate(id, FragmentManager.POP_BACK_STACK_INCLUSIVE);
ft.commit();

} catch (Exception e) {
Log.e("ERROR-REMOVING-BS>>> ", e.getMessage() );
}

Back
BackStack getBackStackEntryCount()
bsCount. tag id
fragmentManager.getBackStackEntryAt(bsCount-1).getId().

.popBackStackImmediate(id,flag) BackStack
BackStack

POP_BACK_STACK_INCLUSIVE
BackStack Pop() Peek()

FragmentTransaction
BackStack "FTRAN0" "FTRAN1"

Back

try {
FragmentManager fragmentManager = getFragmentManager();
// VERSION 1: HIGH-ANCESTOR NAVIGATION (indexed as 0, 1, 2, ...)
// removes all BackStack entries up to given position, which is excluded from removal, and
// it is finally shown (remember that bottom of the BackStack is at position zero).
fragmentManager.popBackStackImmediate(0, 0);

// VERSION 2: Navigate back to a particular ancestor (Tagged here as 'FTRAN1')


fragmentManager.popBackStackImmediate("FTRAN1", FragmentManager.POP_BACK_STACK_INCLUSIVE);

} catch (Exception e) {
Log.e("HIGH-ANCESTOR>>>", "error: " + e.getMessage());
}

fragmentManager.popBackStackImmediate(0,0) BackStack

FragmentTransaction references BackStack


"FTRAN1" BackStack
FragmentManager.POP_BACK_STACK_INCLUSIVE. BackStack
"FTRAN0"
Example 6.4 BackStack Based Navigation

BackStack
BackStack

<?xml version="1.0" encoding="utf-8"?>


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:baselineAligned="false"
android:orientation="vertical"
android:gravity="center"
android:padding="10dp" >

<TextView
android:id="@+id/textView1Main"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#77ffff00"
android:text="\nMain Layout ..."
android:textAppearance="?android:attr/textAppearanceLarge" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:baselineAligned="false"
android:orientation="horizontal" >

<Button
android:id="@+id/button1MainAddRed"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="ADD new RedFragment" />
<Button
android:id="@+id/button2MainPop"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="POP Trans BackStack" />
</LinearLayout>

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:baselineAligned="false"
android:orientation="horizontal" >

<Button
android:id="@+id/button4MainReplace"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="REPLACE new RedFragment" />

<Button
android:id="@+id/button3MainRemove"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:enabled="false"
android:text="FIND &amp; REMOVE TAG \n 'FRAGTRAN-RED2'" />
</LinearLayout>

<FrameLayout
android:id="@+id/main_holder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="2"
android:orientation="vertical" />

</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/layout_red"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >

<TextView
android:id="@+id/textView1Red"
android:layout_width="match_parent"
android:layout_height="175dp"
android:layout_margin="20dp"
android:background="#d50000"
android:gravity="center"
android:text="Red Layout..."
android:textColor="@android:color/white"
android:textSize="35sp"
android:textStyle="bold" />

<Button
android:id="@+id/button1Red"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:text="Change Red Label" />

</LinearLayout>

package csu.matos;

import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends Activity implements IMainCallbacks, View.OnClickListener {

FragmentTransaction ft;
FragmentRed redFragment;
TextView txtMsg;
Button btnAddRedFragment;
Button btnReplaceRedFragment;
Button btnPop;
Button btnRemove;
int serialCounter = 0; //used to enumerate fragments
String redMessage;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// plumbing TextView and Buttons held in main layout
txtMsg = (TextView) findViewById(R.id.textView1Main);
//buttons
btnAddRedFragment = (Button) findViewById(R.id.button1MainAddRed);
btnPop = (Button) findViewById(R.id.button2MainPop);
btnRemove = (Button) findViewById(R.id.button3MainRemove);
btnReplaceRedFragment = (Button) findViewById(R.id.button4MainReplace);
btnAddRedFragment.setOnClickListener(this);
btnPop.setOnClickListener(this);
btnRemove.setOnClickListener(this);
btnReplaceRedFragment.setOnClickListener(this);

// CallBack method (receiving messages coming from Fragments)


@Override
public void onMsgFromFragToMain(String sender, String strValue) {
// show message arriving to MainActivity
txtMsg.setText( sender + "=>" + strValue );
}

// reacting to button's click events


public void onClick(View v) {
// ADD
if(v.getId() == btnAddRedFragment.getId() ){
addRedFragment(++serialCounter);
btnRemove.setEnabled(true);
//WhatFragmentIsSittingInsideUIRegion(); // try - for debugging purposes!

}
// REPLACE
// should not be mixed with .add fragment
if(v.getId() == btnReplaceRedFragment.getId() ){
replaceRedFragment(++serialCounter);
btnRemove.setEnabled(true);
}

// POP (come back to previous UI - if any!)


if(v.getId() == btnPop.getId() ){
FragmentManager fragmentManager = getFragmentManager();
int bsCount = fragmentManager.getBackStackEntryCount();
txtMsg.setText("\nBACKSTACK old size=" + bsCount);

if(bsCount>0) {
// popBackStack removes a Transaction from the BackStack, its view is also deleted
String tag = fragmentManager.getBackStackEntryAt(bsCount-1).getName();
int id = fragmentManager.getBackStackEntryAt(bsCount-1).getId();
Log.e(bsCount +"POPPING-1 (GONE): ", "TAG=" + tag + " ID=" + id);

// execute POP operation


fragmentManager.popBackStackImmediate(id, FragmentManager.POP_BACK_STACK_INCLUSIVE);
//fragmentManager.popBackStackImmediate(id, 0); //try - doesn't remove stack top

// complete any pending insertions in the BackStack, then report its size
getFragmentManager().executePendingTransactions();
bsCount = fragmentManager.getBackStackEntryCount();

//spying: the current stack top is...


spyStackTop("POPPING-2 (TOP): ");

txtMsg.append("\nBACKSTACK new size=" + fragmentManager.getBackStackEntryCount() );


}

}//Pop

// REMOVE
if(v.getId() == btnRemove.getId() ){
txtMsg.setText("Removing...");

try {

FragmentManager fragmentManager = getFragmentManager();


int bsCount = fragmentManager.getBackStackEntryCount();
txtMsg.setText("BACKSTACK old size=" + bsCount);

// VERSION 1: HIGH-ANCESTOR NAVIGATION (indexed as 0, 1, 2, ...)


// removes all BackStack entries up to given position (excluded).
// remember that bottom of the BackStack is at position zero.
fragmentManager.popBackStackImmediate(0, 0);

// VERSION 2: Navigate back to a particular ancestor (Tagged as 'FRAGTRAN-RED2')


// ----------------------------------------------------------------------------
//fragmentManager.popBackStackImmediate("FRAGTRAN-RED2",
// FragmentManager.POP_BACK_STACK_INCLUSIVE);

// EXTRA: TRY - CLEARING BACKSTACK


//fragmentManager.popBackStackImmediate(null,
// FragmentManager.POP_BACK_STACK_INCLUSIVE);
//Log.e("REMOVING>","1BACKSTACK new size=" +
// fragmentManager.getBackStackEntryCount() );

// complete any pending insertions in the BackStack, then report its size
fragmentManager.executePendingTransactions();
Log.e("REMOVING>","2BACKSTACK new size=" + fragmentManager.getBackStackEntryCount());

txtMsg.append("\nBACKSTACK new size=" + fragmentManager.getBackStackEntryCount());


} catch (Exception e) {
Log.e("REMOVING>", "Error: " + e.getMessage());
}

}//Remove

}//onClick

// user pushes the device's "BACK" button


@Override
public void onBackPressed() {
super.onBackPressed();
int counter = getFragmentManager().getBackStackEntryCount();
txtMsg.setText("BACKSTACK size=" + counter);
}

public void addRedFragment(int intValue) {


// create a new RED fragment, add fragment to the transaction
FragmentTransaction ft = getFragmentManager().beginTransaction();
redFragment = FragmentRed.newInstance(intValue);
// add the fragment to the UI
ft.add(R.id.main_holder, redFragment, "RED-TAG" + intValue);
// push reference to fragment-transaction on top of the BACKSTACK
ft.addToBackStack("FRAGTRAN-RED" + intValue);
ft.commit();

// complete any pending insertions in the BackStack, then report its size
getFragmentManager().executePendingTransactions();
txtMsg.setText("\nBACKSTACK size =" + getFragmentManager().getBackStackEntryCount() );

spyStackTop("SPYING TOP AFTER ADDING ");


}

public void replaceRedFragment(int intValue) {


// create a new RED fragment, replace fragments in the transaction
FragmentTransaction ft = getFragmentManager().beginTransaction();
redFragment = FragmentRed.newInstance(intValue);

ft.replace(R.id.main_holder, redFragment, "RED-TAG" + intValue);

ft.addToBackStack("FRAGTRAN-RED" + intValue);
ft.commit();
// complete any pending insertions in the BackStack, then report its size
getFragmentManager().executePendingTransactions();
txtMsg.setText("BACKSTACK size =" + getFragmentManager().getBackStackEntryCount() );
spyStackTop("AFTER REPLACE ");
}

private void spyStackTop(String callerIdMsg){


// show TAG and ID of top BACKSTACK entry together with callerIdMsg
FragmentManager fragmentManager = getFragmentManager();
int bsCount = fragmentManager.getBackStackEntryCount();

if(bsCount>0) {
String tag = fragmentManager.getBackStackEntryAt(bsCount-1).getName();
int id = fragmentManager.getBackStackEntryAt(bsCount-1).getId();
Log.e( "BACKSTACK-" + bsCount + " " + callerIdMsg, ">>> TAG=" + tag + " ID=" + id);
}
}

public void showBackStack(){


try {
FragmentTransaction ft = getFragmentManager().beginTransaction();
android.app.FragmentManager fragmentManager = getFragmentManager();
for (int bsCount = fragmentManager.getBackStackEntryCount();
bsCount >= 1; bsCount--) {
String tag = fragmentManager.getBackStackEntryAt(bsCount-1).getName();
int id = fragmentManager.getBackStackEntryAt(bsCount-1).getId();
Log.e(bsCount +"ShowBackStack: ", "" + tag + " " + id);
}
ft.commit();
} catch (Exception e) {
Log.e("ShowBackStack-Error>>> ", e.getMessage() );
}

private Fragment whatFragmentIsSittingInsideUIRegion(){


//tell the TAG and ID of fragment in given UI region
try {
Fragment fragmentInstance = getFragmentManager().findFragmentById(R.id.main_holder);
if (fragmentInstance != null){
String tag = fragmentInstance.getTag();
int id = fragmentInstance.getId();
Log.e("UTILITY >>> ", "TAG: " + tag + " ID:" + id);
}
return fragmentInstance;
} catch (Exception e) {
Log.e("ERROR-UTILITY>>> ", e.getMessage() );
return null;
}
}
}

 Add New Fragment


Change Red Label
FragmentTransaction
add() addRedFragment()
FrameLayout
BackStack FRAGTRAN-RED1
FRAGTRAN-RED2

Pop Trans BackStack

Pop

BackStack
Find & Remove FRAGTRAN-RED2
BackStack
BackStack

 Replace New Fragment Add New


RedFragment replace()
BackStack

pop BackStack
WARNING
.add() .replace()

public class FragmentRed extends Fragment {


MainActivity main;
TextView txtRed;
Button btnRedClock;
int fragmentId;
String selectedRedText = "";

public static FragmentRed newInstance(int fragmentId) {


FragmentRed fragment = new FragmentRed();
Bundle bundle = new Bundle();
bundle.putInt("fragmentId", fragmentId);
fragment.setArguments(bundle);
return fragment;
}// newInstance

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

// Activities containing this fragment must implement MainCallbacks


if (!(getActivity() instanceof IMainCallbacks)) {
throw new IllegalStateException(
">>> Activity must implement IMainCallbacks");
}
main = (MainActivity) getActivity();
fragmentId = getArguments().getInt("fragmentId", -1);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {

LinearLayout view_layout_red = (LinearLayout) inflater.inflate(


R.layout.layout_red, null);

txtRed = (TextView) view_layout_red.findViewById(R.id.textView1Red);


txtRed.setText( "Fragment " + fragmentId );

btnRedClock = (Button) view_layout_red.findViewById(R.id.button1Red);


btnRedClock.setOnClickListener(new View.OnClickListener() {

@Override
public void onClick(View v) {
selectedRedText = "\nRed Clock:\n" + new Date().toString();
txtRed.append(selectedRedText);
// main.onMsgFromFragToMain("RED-FRAG", selectedRedText );
}
});
return view_layout_red;
}

}// FragmentRed

FragmentTransaction
BackStack Change Red Label

// method to pass messages from fragments to MainActivity


// it must be implemented by the Host Activity

public interface IMainCallbacks {


public void onMsgFromFragToMain ( String sender, String strValue);

}
MainActivity
sender strValue MainActivity

Das könnte Ihnen auch gefallen