Saturday, December 14, 2013

Life cycle of Fragments in ViewPager

In the exercise "Communication between Fragments in ViewPager" demonstrate how to pass data from Fragment A to Fragment B in a ViewPager. It's assumed that Fragment B is created when data is passed, and keep alive.

It's a case that the target Fragment haven't been created when data is passed, java.lang.NullPointerException will be thrown. And also another case the target Fragment have been destroyed after data passed.

So it's modified to keep buffer (saveToB and saveToC) in main activity (AndroidViewPagerActivity.java) to hold the data passed. In Fragment B and C, check any data exist in onResume() call-back method.

Life cycle of Fragments in ViewPager


fragment_a.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="It's Fragment A" />
<EditText
android:id="@+id/a_input"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:id="@+id/a_enter"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Enter to Fragment B"/>
<Button
android:id="@+id/a_enter_toC"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Enter to Fragment C"/>
</LinearLayout>


MyFragmentA.java
package com.exercise.AndroidViewPager;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

public class MyFragmentA extends Fragment {

EditText A_input;
Button A_enter;
Button A_enter_toC;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View myFragmentView = inflater.inflate(R.layout.fragment_a, container, false);

A_input = (EditText)myFragmentView.findViewById(R.id.a_input);
A_enter = (Button)myFragmentView.findViewById(R.id.a_enter);
A_enter.setOnClickListener(A_enterOnClickListener);
A_enter_toC = (Button)myFragmentView.findViewById(R.id.a_enter_toC);
A_enter_toC.setOnClickListener(AtoC_enterOnClickListener);

return myFragmentView;
}

OnClickListener A_enterOnClickListener
= new OnClickListener(){

@Override
public void onClick(View arg0) {

String textPassToB = A_input.getText().toString();

String TabOfFragmentB = ((AndroidViewPagerActivity)getActivity()).getTabFragmentB();

MyFragmentB fragmentB = (MyFragmentB)getActivity()
.getSupportFragmentManager()
.findFragmentByTag(TabOfFragmentB);

if(fragmentB == null){
((AndroidViewPagerActivity)getActivity()).putSaveToB(textPassToB);
Toast.makeText(getActivity(),
"fragmentB == null",
Toast.LENGTH_LONG).show();
}else{
((AndroidViewPagerActivity)getActivity()).putSaveToB(textPassToB);

fragmentB.b_updateText(textPassToB);
Toast.makeText(getActivity(),
"text sent to Fragment B:\n " + TabOfFragmentB,
Toast.LENGTH_LONG).show();
}


}};

OnClickListener AtoC_enterOnClickListener
= new OnClickListener(){

@Override
public void onClick(View arg0) {

String textPassToC = A_input.getText().toString();

String TabOfFragmentC = ((AndroidViewPagerActivity)getActivity()).getTabFragmentC();

MyFragmentC fragmentC = (MyFragmentC)getActivity()
.getSupportFragmentManager()
.findFragmentByTag(TabOfFragmentC);

if(fragmentC == null){
((AndroidViewPagerActivity)getActivity()).putSaveToC(textPassToC);
Toast.makeText(getActivity(),
"fragmentC == null",
Toast.LENGTH_LONG).show();
}else{
((AndroidViewPagerActivity)getActivity()).putSaveToC(textPassToC);

fragmentC.c_updateText(textPassToC);
Toast.makeText(getActivity(),
"text sent to Fragment C:\n " + TabOfFragmentC,
Toast.LENGTH_LONG).show();
}


}};

}


fragment_b.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="It's Fragment B" />
<TextView
android:id="@+id/b_received"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="center"
android:src="@drawable/ic_launcher"/>
</LinearLayout>


MyFragmentB.java
package com.exercise.AndroidViewPager;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;

public class MyFragmentB extends Fragment {

TextView b_received;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View myFragmentView = inflater.inflate(R.layout.fragment_b, container, false);

b_received = (TextView)myFragmentView.findViewById(R.id.b_received);
String myTag = getTag();

((AndroidViewPagerActivity)getActivity()).setTabFragmentB(myTag);

Toast.makeText(getActivity(),
"MyFragmentB.onCreateView(): " + myTag,
Toast.LENGTH_LONG).show();

return myFragmentView;
}

public void b_updateText(String t){
b_received.setText(t);
}

@Override
public void onResume() {
super.onResume();
String t = ((AndroidViewPagerActivity)getActivity()).getSaveToB();
if(t != null){
b_received.setText(t);
}

Toast.makeText(getActivity(),
"MyFragmentB.onResume()",
Toast.LENGTH_LONG).show();
}

@Override
public void onDestroyView() {
super.onDestroyView();
Toast.makeText(getActivity(),
"MyFragmentB.onDestroyView()",
Toast.LENGTH_LONG).show();
}

}


fragment_c.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="It's Fragment C" />
<TextView
android:id="@+id/c_received"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>


MyFragmentC.java
package com.exercise.AndroidViewPager;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;

public class MyFragmentC extends Fragment {

TextView c_received;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View myFragmentView = inflater.inflate(R.layout.fragment_c, container, false);

c_received = (TextView)myFragmentView.findViewById(R.id.c_received);
String myTag = getTag();

((AndroidViewPagerActivity)getActivity()).setTabFragmentC(myTag);

Toast.makeText(getActivity(),
"MyFragmentC.onCreateView(): " + myTag,
Toast.LENGTH_LONG).show();

return myFragmentView;
}

public void c_updateText(String t){
c_received.setText(t);
}

@Override
public void onResume() {
super.onResume();
String t = ((AndroidViewPagerActivity)getActivity()).getSaveToC();
if(t != null){
c_received.setText(t);
}

Toast.makeText(getActivity(),
"MyFragmentC.onResume()",
Toast.LENGTH_LONG).show();
}

@Override
public void onDestroyView() {
super.onDestroyView();
Toast.makeText(getActivity(),
"MyFragmentC.onDestroyView()",
Toast.LENGTH_LONG).show();
}

}


main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >

<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello" />

</LinearLayout>


AndroidViewPagerActivity.java
package com.exercise.AndroidViewPager;

import java.util.ArrayList;

import android.app.ActionBar;
import android.app.ActionBar.Tab;
import android.app.FragmentTransaction;
import android.content.Context;
import android.os.Bundle;

import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;

public class AndroidViewPagerActivity extends FragmentActivity {

ViewPager mViewPager;
TabsAdapter mTabsAdapter;

String TabFragmentB;
String TabFragmentC;

String saveToB = null;
String saveToC = null;

public void setTabFragmentB(String t){
TabFragmentB = t;
}

public String getTabFragmentB(){
return TabFragmentB;
}

public void setTabFragmentC(String t){
TabFragmentC = t;
}

public String getTabFragmentC(){
return TabFragmentC;
}

public void putSaveToB(String textToSave){
saveToB = textToSave;
}

public void putSaveToC(String textToSave){
saveToC = textToSave;
}

public String getSaveToB(){
String t = saveToB;
return t;
}

public String getSaveToC(){
String t = saveToC;
return t;
}

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

mViewPager = new ViewPager(this);
mViewPager.setId(R.id.pager);
setContentView(mViewPager);

final ActionBar bar = getActionBar();
bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
bar.setDisplayOptions(0, ActionBar.DISPLAY_SHOW_TITLE);

mTabsAdapter = new TabsAdapter(this, mViewPager);
mTabsAdapter.addTab(bar.newTab().setText("Fragment A"),
MyFragmentA.class, null);
mTabsAdapter.addTab(bar.newTab().setText("Fragment B"),
MyFragmentB.class, null);
mTabsAdapter.addTab(bar.newTab().setText("Fragment C"),
MyFragmentC.class, null);

if (savedInstanceState != null) {
bar.setSelectedNavigationItem(savedInstanceState.getInt("tab", 0));
}

}

@Override
protected void onSaveInstanceState(Bundle outState) {
//super.onSaveInstanceState(outState);
outState.putInt("tab", getActionBar().getSelectedNavigationIndex());
}

public static class TabsAdapter extends FragmentPagerAdapter
implements ActionBar.TabListener, ViewPager.OnPageChangeListener {

private final Context mContext;
private final ActionBar mActionBar;
private final ViewPager mViewPager;
private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();

static final class TabInfo {
private final Class<?> clss;
private final Bundle args;

TabInfo(Class<?> _class, Bundle _args) {
clss = _class;
args = _args;
}
}

public TabsAdapter(FragmentActivity activity, ViewPager pager) {
super(activity.getSupportFragmentManager());
mContext = activity;
mActionBar = activity.getActionBar();
mViewPager = pager;
mViewPager.setAdapter(this);
mViewPager.setOnPageChangeListener(this);
}

public void addTab(ActionBar.Tab tab, Class<?> clss, Bundle args) {
TabInfo info = new TabInfo(clss, args);
tab.setTag(info);
tab.setTabListener(this);
mTabs.add(info);
mActionBar.addTab(tab);
notifyDataSetChanged();
}

@Override
public void onPageScrollStateChanged(int state) {
// TODO Auto-generated method stub

}

@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
// TODO Auto-generated method stub

}

@Override
public void onPageSelected(int position) {
// TODO Auto-generated method stub
mActionBar.setSelectedNavigationItem(position);
}

@Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
// TODO Auto-generated method stub

}

@Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
Object tag = tab.getTag();
for (int i=0; i<mTabs.size(); i++) {
if (mTabs.get(i) == tag) {
mViewPager.setCurrentItem(i);
}
}
}

@Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
// TODO Auto-generated method stub

}

@Override
public Fragment getItem(int position) {
TabInfo info = mTabs.get(position);
return Fragment.instantiate(mContext, info.clss.getName(), info.args);
}

@Override
public int getCount() {
return mTabs.size();
}

}

}


AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.exercise.AndroidViewPager"
android:versionCode="1"
android:versionName="1.0" >

<uses-sdk android:minSdkVersion="11" android:targetSdkVersion="11" />

<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<activity
android:name=".AndroidViewPagerActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

</manifest>


download filesDownload the files.