Android Retain-Fragment + ActionBar-Tabs = Absturz!?

Natac

Bekanntes Mitglied
Ich habe Tabs in der ActionBar, die ich wie folgt aufbaue:

Java:
public MainActivity extends Activity{

  public void onCreate(Bundle b){
        setContentView(R.layout.main_activity);
        final Tab tab = getActionBar().newTab();
        tab.setText("Tab 1");
        tab.setTabListener(new TabListener<T>(new Tab1Fragment()));
        getActionBar().addTab(tab);

        tab.setText("Tab 2");
        tab.setTabListener(new TabListener<T>(new Tab2Fragment()));
        getActionBar().addTab(tab);
  }

   private static final class TabListener<T extends Fragment> implements ActionBar.TabListener {
        private final T fragment;
        public TabListener(final T fragment) {this.fragment = fragment;}
        
        public void onTabSelected(final Tab tab, final FragmentTransaction ft) {ft.replace(R.id.tab_target, this.fragment, null);}
        
        public void onTabUnselected(final Tab tab, final FragmentTransaction ft) {}
        public void onTabReselected(final Tab tab, final FragmentTransaction ft) {}
    }
}
Das Funktioniert auch alles wunderbar.

"Problem" scheint zu sein, dass ich in [c]Tab1Fragment[/c] ein weiteres Fragment habe, dass [c]retain = true[/c] ist:

Java:
public class Tab1Fragment extends Fragment{
  
   public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle b) {
        return inflater.inflate(R.layout.tab_1_fragment, null);
   }

   public void onActivityCreated(Bundle b){
      MyRetainFragment retainFrag = (MyRetainFragment) getFragmentManager().findFragmentByTag("my_frag");
      if (retainFrag == null) {
        retainFrag = new MyRetainFragment(); // retain = true im Konstruktor
      }
      getFragmentManager().beginTransaction().replace(R.id.retain_target, retainFrag, "my_frag").commit(); // HIER KNALLTS ! (Vermutlich)
  }
}

Die verwendeten Layouts sind:
main_activity.xml
[xml]<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" >
<LinearLayout android:id="@+id/tab_target"/>
</RelativeLayout>[/xml]

tab_1_fragment.xml
[xml]<TableLayout xmlns:android="http://schemas.android.com/apk/res/android">
<TableRow>
<LinearLayout android:id="@+id/retain_target"/> <!-- Hier soll das Retain-Fragment rein! -->
</TableRow>
</TableLayout>[/xml]

Die Fehlermeldung:
Code:
11-07 16:33:03.804: E/AndroidRuntime(10895): Caused by: java.lang.IllegalArgumentException: No view found for id 0x7f0a0024 for fragment MyRetainFragment{41fb88a0 #1 id=0x7f0a0024 retain_target}
11-07 16:33:03.804: E/AndroidRuntime(10895): 	at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:823)
11-07 16:33:03.804: E/AndroidRuntime(10895): 	at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1035)
11-07 16:33:03.804: E/AndroidRuntime(10895): 	at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1017)
11-07 16:33:03.804: E/AndroidRuntime(10895): 	at android.app.FragmentManagerImpl.dispatchActivityCreated(FragmentManager.java:1806)
11-07 16:33:03.804: E/AndroidRuntime(10895): 	at android.app.Activity.performCreate(Activity.java:5166)
11-07 16:33:03.804: E/AndroidRuntime(10895): 	at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1094)
11-07 16:33:03.804: E/AndroidRuntime(10895): 	at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2061)
11-07 16:33:03.804: E/AndroidRuntime(10895): 	... 12 more
Beim starten geht alles gut. Drehe ich das Tablet in Tab1, verschwindet der gesamt Content. Wechlse ich auf Tab2 und drehe das Tablet, kommt dieser Fehler.

Mir siehts so aus, als würde er die ID [c]retain_target[/c] nicht finden. Aber zu dem Zeitpunkt sollte das Tab1Fragment doch schon in der Activity hängen, so dass der FragmentManager die id finden sollte!? Bin verwirrt.
 
Zuletzt bearbeitet:

dzim

Top Contributor
Ich hab es jetzt nur Überflogen, aber für Fragmente in Fragmenten sollte man doch den ChildFragmentManager verwenden, oder?

Java:
// versuch' mal bitte statt
getFragmentManager().beginTransaction().replace(R.id.retain_target, retainFrag, "my_frag").commit(); // HIER KNALLTS ! (Vermutlich)

// ...das hier
getChildFragmentManager().beginTransaction().replace(R.id.retain_target, retainFrag, "my_frag").commit(); // HIER KNALLTS ! (Vermutlich)

Hab gehört, dass macht sonst Probleme und ausserdem ist's sauberer. Ich drück die Daumen, dass es das vielleicht schon ist!

Grüsse,
Daniel
 

dzim

Top Contributor
Doch: die Support Library (v4 glaub ich) müsste dass enthalten. Was Fragmente angeht, arbeite ich fast ausschließlich mit der.
Du musst dann aber alle Fragment-Dependencies auf android.support.v4.* umstellen.
Es wird von Google (und ist auch von meiner Warte her sinnvoll) empfohlen, wenn es sinnvoll ist, diese Libs zu verwenden, dann kannst du wenigstens diesen Teil für alle Android-4+-Geräte anbieten (für unsere Kleine App entfallen nur noch 15% auf 2.x-Varianten, so dass wir mit zwei Varianten der App ganz gut fahren - eine für die alten Geräte ohne Fragmente, ActionBar etc. und eine für alle ab 4+).
 
Zuletzt bearbeitet:

Natac

Bekanntes Mitglied
So... nachdem ich mich lange genug mit den Fragments rumgeschlagen habe, bin ich jetzt zu folgender "Lösung" gekommen. Ich habe mich von den Fragments verabschiedet und schalte einfach die entsprechende Views in meiner Activity sichtbar bzw. unsichbar, je nachdem, welches "Tab" ausgewählt ist. Spart ne Menge Stress. ;)

Java:
public MainActivity extends Activity{
  public void onCreate(Bundle b){
        setContentView(R.layout.main_activity);
        final Tab tab = getActionBar().newTab();
        tab.setText("Tab 1");
        tab.setTabListener(new TabListener(findViewById(R.id.tab1)));
        getActionBar().addTab(tab);
 
        tab.setText("Tab 2");
        tab.setTabListener(new TabListener(findViewById(R.id.tab2)));
        getActionBar().addTab(tab);
  }
   private static final class TabListener implements ActionBar.TabListener {
        private final View view;
        public TabListener(final View view) {this.view = view;}
        public void onTabSelected(final Tab tab, final FragmentTransaction ft) {view.setVisible(View.VISIBLE);}
        public void onTabUnselected(final Tab tab, final FragmentTransaction ft) {view.setVisible(View.GONE);}
        public void onTabReselected(final Tab tab, final FragmentTransaction ft) {}
    }
}
Damit habe ich zwar keine "echten" Tabs, bin allerdings ne Menge Fragement-Geraffel los. Es funktioniert und ist super einfach.

Für alle, die "echte" Tabs haben wollen und auf diesen Thread stoßen: Über die Support-Library soll es wohl möglich sein nested Fragments auch vor 4.2 zu nutzen (habe 4.1.2). Habe das nicht ausprobiert, da mir diese einfache Lösung lieber ist ;)
 

dzim

Top Contributor
Ich gebe ja zu, dass es für kleine Aufgaben so genügt, aber Grundsätzlich würde ich dir dringlichst empfehlen doch wieder auf Fragment zu setzen! Der Grund ist einfach: Flexibilität und Wiederverwendbarkeit!
Die (kleine) App die ich betreue z.B. hatte früher nur ein statisches UI, das hat ein Kollege dann mal auf Fragmente umgestellt, was die GUI für mich wesentlich besser zu verstehen gemacht hat, als ich sie dann übernommen habe. Ich habe es so ausgebaut, dass dann eine Anpassung für Tablet innerhalb von 2-3 Tagen stand. Mit deiner Variante wirst du leider viel mehr Arbeit haben, wenn die Oberfläche auf Tablets mal anders aussehen soll.

Ich werde dir mal ein paar Beispiele in den nächsten Tagen zeigen, dann wird vielleicht klar, warum ich hier tatsächlich etwas enttäuscht von deiner Einstellung bin. (BTW: es gib unter Eclipse einen Wizard beim Anlegen eines Android-Projekts, der einem bereits sehr viel Vorarbeit für Activities mit ActionBar und Swipefähigen Tabs abnimmt!)
 

Natac

Bekanntes Mitglied
Da bin ich gespannt. Danke für dein Engagement. :toll:

Ich gebe zu, das das Frustpotential hoch war, als ich das zu lösen hatte. Und da ich Fragments vielleicht auch noch nicht bis ins letzte Detail verstanden habe, fühle ich mich mit der aktuellen Lösung natürlich viel wohler. Bin aber gerne bereit dazu zulernen um auch Fragments gänzlich zu verstehen und einsetzten zu können :rtfm:
 
Zuletzt bearbeitet:

dzim

Top Contributor
Löblich! Ich weiß nicht, wann ich die Zeit dazu finde, mal alles zusammen zu sammeln, aber ich poste - wenn es halt gerade geht - mal ab und an etwas :)

Mein Beispiel wird eine vereinfachte Variante von einem Navigation-Drawer Layout sein, an dem ich gerade arbeite. Ich stelle gerade unsere App darauf um und hab in dem Zug auch einiges über Fragmente in Fragmenten lernen müssen.
Ich warne dich aber bereits vorab: Auch wenn ich die Kreativität habe, es meist irgendwie zum Laufen zu bringen, ist der von mir fabrizierte Code nicht immer allererste Sahne! Also hab etwas Nachsicht, wenn es etwas chaotisch wird... :)

(Wie gesagt: Ein Teil ist auch für mich relatives Neuland und ich bastel an den meisten Stellen gerade herum und versuche noch möglichst generische Lösungen zu finden.)


Da ich gerade einen schönen neuen Auftrag von einem meiner Chefs bekommen hab, musst du dich noch etwas gedulden, bis die ersten Code-Schnipsel eintrudeln werden. Der Ablauf wird aber ungefähr wie folgt sein:

PhoneMainActivity extends BaseMainActivity --> ich werde also an einigen Stellen im Code Methoden verwenden, die du nicht von Android kennst, die ich mir reingebastelt hab. Im wesentlich aber gilt BaseMainActivity extends FragmentActivity. Das ist quasi die Basis von all dem.
Das UI dieser Activity kann ich dir auch schon zeigen:
HTML:
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/black" >

    <FrameLayout
        android:id="@+id/content_frame"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <ListView
        android:id="@+id/left_drawer"
        android:layout_width="320dp"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:background="#111"
        android:choiceMode="singleChoice"
        android:divider="@android:color/transparent"
        android:dividerHeight="0dp" />

    <!--<FrameLayout
        android:id="@+id/left_drawer"
        android:layout_width="320dp"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:background="#111"
        android:divider="@android:color/transparent"
        android:dividerHeight="0dp" />-->

</android.support.v4.widget.DrawerLayout>
Die FrameLayouts werden hier im wesentlichen als Platzhalter verwendet. Von der Verwendung von LinearLayouts rate ich hier ab!
Das untere FrameLayout ist noch auskommentiert, da ich es erst später verwenden werde - im ersten Schritt wird der Navigation Drawer wirklich nur eine blöde Liste werden - später mache ich ihn dann "hübsch".

Im nächsten Post werde ich dir den Stub der Activity zeigen. Dabei wird initial das erste Fragment geladen - in meinem Fall ein Fragment das einen ViewPager enthält - der wiederum wird seine Tabs über einen FragmentPagerAdapter laden - also weitere Fragmente. Eines der Fragmente des ViewPagers wird eine Map sein. den Code hierzu habe ich kürzlich in einem anderen Post gezeigt:
OpenStreetMap in der Google Maps API v2
Hier habe ich nur einen Nachtrag: Im Code habe ich die Methode #setUpMapIfNeeded() gezeigt, dort im Code hatte ich noch ein Problem, wenn die Map in ein Fragment eingebunden wurde, das selbst nur in einem anderen Fragment lag:
Java:
// instead of
/*
        FragmentManager fm = getFragmentManager();
        Fragment frag = fm.findFragmentById(R.id.fragment_mapview);
        
        if (frag == null) {
            if ((mView != null) && (mView.getParent() != null)) {
                ((ViewGroup) mView.getParent()).removeView(mView);
                mView = null;
            }
            return;
        } else {
            if (mMap == null) {
                mMap = ((com.google.android.gms.maps.SupportMapFragment) frag).getMap();
            }
        }
*/

// use
		FragmentManager fm = getActivity().getSupportFragmentManager();
		Fragment frag = fm.findFragmentById(R.id.fragment_mapview);
		
		if (frag == null) {
			// if ((mView != null) && (mView.getParent() != null)) {
			// ((ViewGroup) mView.getParent()).removeView(mView);
			// mView = null;
			// }
			// frag = new CustomSupportMapFragment();
			// ((CustomSupportMapFragment) frag).applyBasicSetup(true); // this is my "invention" - you don't probably need that!
			frag = SupportMapFragment.newInstance();
			fm.beginTransaction().replace(R.id.fragment_mapview, frag).commit();
			fm.executePendingTransactions();
			if (mMap == null) {
				mMap = ((com.google.android.gms.maps.SupportMapFragment) frag).getMap();
			}
			return;
		} else {
			if (mMap == null) {
				mMap = ((com.google.android.gms.maps.SupportMapFragment) frag).getMap();
			}
		}

That's all for now!
C ya!

Daniel
 

dzim

Top Contributor
So. Mein neuer Ansatz fängt - wie zuvor - damit an, dass es eine Activity - die hier als Container fungiert - gibt, die dann alle weiteren Fragmente enthält.

Hinweis: Das Layout ist im Wesentlichen eine abgeänderte Variante des cnlab SpeedTest.

Hier die...
activity_main_phone.xml
[XML]
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/black" >

<FrameLayout
android:id="@+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent" />

<FrameLayout
android:id="@+id/left_drawer_frame"
android:layout_width="320dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="@drawable/base_shape_drawer" />

</android.support.v4.widget.DrawerLayout>
[/XML]

fragment_drawer.xml
[XML]
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:eek:rientation="horizontal" >

<TextView
android:id="@+id/fragment.header"
style="@style/cnlabHeader.Grey"
android:layout_marginLeft="5dp"
android:layout_marginTop="5dp"
android:layout_toLeftOf="@+id/sep"
android:text="@string/drawer.header" />

<View
android:id="@+id/sep"
android:layout_width="5dp"
android:layout_height="match_parent"
android:layout_alignParentRight="true"
android:layout_marginLeft="5dp"
android:background="@drawable/sep"
android:visibility="visible" />

<ListView
android:id="@android:id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/fragment.header"
android:layout_alignParentBottom="true"
android:layout_alignRight="@+id/fragment.header"
android:layout_below="@+id/fragment.header"
android:layout_marginBottom="5dp"
android:layout_marginTop="5dp"
android:cacheColorHint="#00000000"
android:choiceMode="singleChoice"
android:divider="@android:color/transparent"
android:dividerHeight="0dp"
android:fadeScrollbars="false"
android:fastScrollEnabled="true"
android:listSelector="@drawable/result_list_selector"
android:scrollbarAlwaysDrawVerticalTrack="true" >
</ListView>

</RelativeLayout>
[/XML]

drawer_row.xml
[XML]
<?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:minHeight="50dp"
android:eek:rientation="horizontal" >

<ImageView
android:id="@+id/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="5dp"
android:contentDescription="@string/three_dots"
android:scaleType="fitCenter"
android:src="@drawable/empty" />

<TextView
android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:text="@string/mock"
android:textStyle="bold" />

</LinearLayout>
[/XML]
Damit das auch verwendet wird, hab ich eine neue Activity erstellt (siehe letzter Post):
Java:
import android.app.ActionBar;
import android.content.Intent;
import android.content.res.Configuration;
import android.os.Bundle;
import android.support.v4.app.ActionBarDrawerToggle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.widget.DrawerLayout;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

public class PhoneMainActivity extends BaseMainActivity {
	
	private DrawerLayout mDrawerLayout;
	private ActionBarDrawerToggle mDrawerToggle;
	private View mLeftDrawer;
	
	private CharSequence mTitle = Constants.EMPTY_STRING;
	private CharSequence mSubTitle = Constants.EMPTY_STRING;
	
	private PhoneDrawerFragment mDrawerFragment = null;
	private MainViewPagerFragment mMainFragment = null;
	private SettingsViewPagerFragment mSettingsFragment = null;
	private GenericWebDialogFragment changelogFragment = null;
	private GenericWebDialogFragment aboutFragment = null;

	private DrawerItemEnum mSelectedDrawerItem = null;
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main_phone);
		final ActionBar actionBar = getActionBar();
		mTitle = getString(R.string.appName);
		actionBar.setSubtitle(mSubTitle = getVersion());
		actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
		actionBar.setDisplayHomeAsUpEnabled(true);
		actionBar.setHomeButtonEnabled(true);
		mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
		mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, R.drawable.ic_drawer_dark, R.string.drawer_open, R.string.drawer_close) {
			
			public void onDrawerClosed(View view) {
				updateActionBar();
			}
			
			public void onDrawerOpened(View drawerView) {
				mDrawerFragment.setSelectedItem(mSelectedDrawerItem);
				final ActionBar actionBar = getActionBar();
				actionBar.setTitle(R.string.appName);
				actionBar.setSubtitle(getVersion());
				invalidateOptionsMenu();
			}
		};
		mDrawerLayout.setDrawerListener(mDrawerToggle);
		mLeftDrawer = findViewById(R.id.left_drawer_frame);
		if (mDrawerFragment == null) {
			mDrawerFragment = new PhoneDrawerFragment();
			mDrawerFragment.setOnItemClickHandler(new OnDrawerListItemClickHandler());
		}
		if (mMainFragment == null) {
			mMainFragment = new MainViewPagerFragment();
		}
		if (mSettingsFragment == null) {
			mSettingsFragment = new SettingsViewPagerFragment();
		}
		// you can use DialogFramgents as regular fragments as well...
		if (changelogFragment == null) {
			changelogFragment = new GenericWebDialogFragment();
			changelogFragment.setTitleResource(R.string.changelogDialog_title);
			changelogFragment.setHtmlResource(R.string.html_changelog);
			changelogFragment.setShowsDialog(false);
		}
		if (aboutFragment == null) {
			aboutFragment = new GenericWebDialogFragment();
			aboutFragment.setTitleResource(R.string.aboutDialog_title);
			aboutFragment.setHtmlResource(R.string.about);
			aboutFragment.setShowsDialog(false);
		}
		FragmentManager fm = getSupportFragmentManager();
		FragmentTransaction ft = null;
		Fragment drawerFragment = fm.findFragmentById(R.id.left_drawer_frame);
		if (drawerFragment == null) {
			drawerFragment = mDrawerFragment;
			if (ft == null)
				ft = fm.beginTransaction();
			ft.replace(R.id.left_drawer_frame, drawerFragment, null);
		}
		Fragment contentFragment = fm.findFragmentById(R.id.content_frame);
		if (contentFragment == null) {
			contentFragment = mMainFragment;
			if (ft == null)
				ft = fm.beginTransaction();
			ft.replace(R.id.content_frame, contentFragment, null);
		}
		if (ft != null) {
			ft.commit();
			fm.executePendingTransactions();
			mDrawerFragment.setSelectedItem(mSelectedDrawerItem = DrawerItemEnum.MAIN);
		}
	}
	
	private void updateActionBar() {
		FragmentManager fm = getSupportFragmentManager();
		Fragment contentFragment = fm.findFragmentById(R.id.content_frame);
		// #getVersion() is a method from the extended BaseMainActivity
		if (contentFragment == mMainFragment) {
			mTitle = getString(R.string.appName);
			mSubTitle = getVersion();
		} else if (contentFragment == mSettingsFragment) {
			mTitle = getString(R.string.title_settings);
			mSubTitle = getString(R.string.appName) + " - " + getVersion();
		} else if (contentFragment == changelogFragment) {
			mTitle = getString(R.string.changelogDialog_title);
			mSubTitle = getString(R.string.appName) + " - " + getVersion();
		} else if (contentFragment == aboutFragment) {
			mTitle = getString(R.string.aboutDialog_title);
			mSubTitle = getString(R.string.appName) + " - " + getVersion();
		}
		final ActionBar actionBar = getActionBar();
		actionBar.setTitle(mTitle);
		if (Constants.EMPTY_STRING.equals(mSubTitle) || mSubTitle.equals("?")) {
			mSubTitle = getVersion(); // hack - sometimes the version string was empty
		}
		actionBar.setSubtitle(mSubTitle);
		invalidateOptionsMenu();
	}
	
	@Override
	protected void onResume() {
		super.onResume();
		final ActionBar actionBar = getActionBar();
		actionBar.setSubtitle(getVersion());
		updateIntentExtras(getIntent());
	}
	
	@Override
	protected void onNewIntent(Intent intent) {
		super.onNewIntent(intent);
		setIntent(intent);
	}
	
	private void updateIntentExtras(Intent intent) {
		// I used this once for a home screen widget - wasn't happy with it, so the method is only a stub right now
	}
	
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		boolean result = super.onCreateOptionsMenu(menu);
		getMenuInflater().inflate(R.menu.activity_main, menu);
		return result;
	}
	
	@Override
	public boolean onPrepareOptionsMenu(Menu menu) {
		// XXX If the nav drawer is open, hide action items related to the content view
		boolean drawerOpen = mDrawerLayout.isDrawerOpen(mLeftDrawer);
		boolean result = super.onPrepareOptionsMenu(menu);
		MenuItem helpItem = menu.findItem(R.id.menu_help);
		MenuItem filterItem = menu.findItem(R.id.menu_result_filter);
		FragmentManager fm = getSupportFragmentManager();
		Fragment contentFragment = fm.findFragmentById(R.id.content_frame);
		if (drawerOpen) {
			setVisibleMenuItems(false, helpItem);
		} else if (contentFragment != null) {
			if (contentFragment == mMainFragment) {
				if (helpItem != null) {
					helpItem.setVisible(!drawerOpen);
				}
				if (settingsItem != null) {
					settingsItem.setEnabled(isAllowSettings());
					settingsItem.setIcon(!isAllowSettings() ? R.drawable.ic_action_settings_light : R.drawable.ic_action_settings);
					settingsItem.setVisible(false);
				}
				// setVisibleMenuItems(false, ...);
			} else if (contentFragment == mSettingsFragment) {
				if (helpItem != null) {
					// visitResultsItem.setVisible(!drawerOpen);
					helpItem.setVisible(false);
				}
				// setVisibleMenuItems(false, ...);
				
			} else {
				setVisibleMenuItems(false, helpItem);
			}
			
		} else {
			setVisibleMenuItems(false, helpItem);
		}
		
		return result;
	}
	
	// private void enableMenuItems(boolean enabled, MenuItem... items) {
	// if (items == null || items.length == 0) return;
	// for (MenuItem item : items) { if (item == null) continue; item.setEnabled(enabled);}}
	
	private void setVisibleMenuItems(boolean visible, MenuItem... items) {
		if (items == null || items.length == 0)
			return;
		for (MenuItem item : items) {
			if (item == null)
				continue;
			item.setVisible(visible);
		}
	}
	
	@Override
	public boolean onMenuOpened(int featureId, Menu menu) {
		if (menu == null) {
			return false;
		}
		return super.onMenuOpened(featureId, menu);
	}
	
	@Override
	protected void onPostCreate(Bundle savedInstanceState) {
		super.onPostCreate(savedInstanceState);
		mDrawerToggle.syncState();
	}
	
	@Override
	public void onConfigurationChanged(Configuration newConfig) {
		super.onConfigurationChanged(newConfig);
		mDrawerToggle.onConfigurationChanged(newConfig);
	}
	
	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		
		// Pass the event to ActionBarDrawerToggle, if it returns
		// true, then it has handled the app icon touch event
		if (mDrawerToggle.onOptionsItemSelected(item)) {
			return true;
		}
		
		// Handle your other action bar items...
		switch (item.getItemId()) {
		case R.id.menu_help:
			showHelp();
			return true;
		case android.R.id.home:
			// showHomeScreen();
			return true;
		default:
			return super.onOptionsItemSelected(item);
		}
	}
	
	protected void showHelp() {
		FragmentManager fm = getSupportFragmentManager();
		Fragment contentFragment = fm.findFragmentById(R.id.content_frame);
		if (contentFragment != null) {
			if (contentFragment == mMainFragment)
				mMainFragment.showHelp();
		}
	}
	
	protected void showHomeScreen() {
		if (mDrawerLayout.isDrawerOpen(mLeftDrawer))
			mDrawerLayout.closeDrawer(mLeftDrawer);
		FragmentManager fm = getSupportFragmentManager();
		Fragment contentFragment = fm.findFragmentById(R.id.content_frame);
		if (contentFragment == mMainFragment && mMainFragment.getCurrentFragmentIndex() > 0) {
			mMainFragment.setCurrentTab(0);
		} else {
			// do something?
		}
	}
	
	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		// there was some code here, but since I don't rely on activities that much any more it is most likly unnecessary to keep
	}
	
	@Override
	public void onBackPressed() {
		// if the drawer is currently open, close it and stop here
		if (mDrawerLayout.isDrawerOpen(mLeftDrawer)) {
			mDrawerLayout.closeDrawer(mLeftDrawer);
			return;
		}
		FragmentManager fm = getSupportFragmentManager();
		Fragment contentFragment = fm.findFragmentById(R.id.content_frame);
		if (contentFragment != null) {
			// if we are on the main fragment, but not on the first tab, go to the first tab and stop
			if (contentFragment == mMainFragment) {
				if (mMainFragment.getCurrentFragmentIndex() > 0) {
					showHomeScreen();
					return;
				} else {
					// do something?
				}
			}
			// otherwise if we currently see a different fragment just return to the main fragment and stop
			else if (contentFragment != mMainFragment) {
				FragmentTransaction ft = fm.beginTransaction();
				ft.detach(contentFragment);
				ft.replace(R.id.content_frame, mMainFragment, null);
				ft.attach(mMainFragment);
				ft.commit();
				fm.executePendingTransactions();
				updateActionBar();
				mDrawerFragment.setSelectedItem(mSelectedDrawerItem = DrawerItemEnum.MAIN);
				return;
			}
		}
		// if none of the other things were true, we are allowed to go back - in this case most likly we leave the app
		super.onBackPressed();
	}
	
	// these two methods replace the default (and imho dull Toast with another version)
	private View getToastView(String message) {
		LinearLayout layout = new LinearLayout(this);
		View v = getLayoutInflater().inflate(R.layout.toast_message, layout, true);
		((TextView) v.findViewById(R.id.textView_toast_message)).setText(message);
		return layout;
	}
	
	private View getToastView(int stringResourceId) {
		return getToastView(getString(stringResourceId));
	}
	
	// IAdditionalHandler is only a small Interface containing this method
	// it is triggered by the drawer framgment implementation, if it is set
	private class OnDrawerListItemClickHandler implements IAdditionalHandler {
		
		@Override
		public void handle(Object... data) {
			if (data == null || data.length == 0)
				return;
			DrawerItemEnum selection = (DrawerItemEnum) data[0];
			if (selection == null)
				return;
			mSelectedDrawerItem = selection;
			FragmentManager fm = getSupportFragmentManager();
			Fragment contentFragment = fm.findFragmentById(R.id.content_frame);
			switch (selection) {
			case MAIN:
				if (contentFragment == mMainFragment) {
					mDrawerLayout.closeDrawer(mLeftDrawer);
				} else {
					FragmentTransaction ft = fm.beginTransaction();
					ft.detach(contentFragment);
					ft.replace(R.id.content_frame, mMainFragment, null);
					ft.attach(mMainFragment);
					ft.commit();
					mDrawerLayout.closeDrawer(mLeftDrawer);
				}
				break;
			case HELP:
				mDrawerLayout.closeDrawer(mLeftDrawer);
				break;
			case SETTINGS:
				if (!isAllowSettings()) {
					Toast toast = Toast.makeText(PhoneMainActivity.this, R.string.drawer_settings_impossible, Toast.LENGTH_LONG);
					toast.setView(getToastView(R.string.drawer_settings_impossible));
					toast.show();
				} else if (contentFragment == mSettingsFragment) {
					mDrawerLayout.closeDrawer(mLeftDrawer);
				} else {
					FragmentTransaction ft = fm.beginTransaction();
					ft.detach(contentFragment);
					ft.replace(R.id.content_frame, mSettingsFragment, null);
					ft.attach(mSettingsFragment);
					ft.commit();
					mDrawerLayout.closeDrawer(mLeftDrawer);
				}
				break;
			case VIEW_RESULTS:
				mDrawerLayout.closeDrawer(mLeftDrawer);
				openResultsWebIntent();
				break;
			case SEND_FEEDBACK:
				mDrawerLayout.closeDrawer(mLeftDrawer);
				openFeedbackIntent();
				break;
			case CHANGELOG:
				if (contentFragment == changelogFragment) {
					mDrawerLayout.closeDrawer(mLeftDrawer);
				} else {
					mDrawerLayout.closeDrawer(mLeftDrawer);
					FragmentTransaction ft = fm.beginTransaction();
					ft.detach(contentFragment);
					ft.replace(R.id.content_frame, changelogFragment, null);
					ft.attach(changelogFragment);
					ft.commit();
					fm.executePendingTransactions();
					aboutFragment.relaodPage();
				}
				break;
			case ABOUT:
				if (contentFragment == aboutFragment) {
					mDrawerLayout.closeDrawer(mLeftDrawer);
				} else {
					mDrawerLayout.closeDrawer(mLeftDrawer);
					FragmentTransaction ft = fm.beginTransaction();
					ft.detach(contentFragment);
					ft.replace(R.id.content_frame, aboutFragment, null);
					ft.attach(aboutFragment);
					ft.commit();
					fm.executePendingTransactions();
					aboutFragment.relaodPage();
				}
				break;
			}
			
			mDrawerFragment.setSelectedItem(mSelectedDrawerItem);
		}
	}
}
Der Drawer ist recht simpel:
Das Fragment:
Java:
import android.os.Bundle;
import android.support.v4.app.ListFragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListView;

public class PhoneDrawerFragment extends ListFragment {
	
	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
		View view = inflater.inflate(R.layout.fragment_drawer_phone, container, false);
		return view;
	}
	
	private DrawerItemEnum.DrawerItemArrayAdapter mAdapter = null;
	
	@Override
	public void onActivityCreated(Bundle savedInstanceState) {
		super.onActivityCreated(savedInstanceState);
		if (mAdapter == null) {
			mAdapter = new DrawerItemEnum.DrawerItemArrayAdapter(getActivity());
		}
		this.setListAdapter(null);
		// this.getListView().addHeaderView(headerView);
		this.setListAdapter(mAdapter);
	}
	
	protected void setSelectedItem(DrawerItemEnum item) {
		if (item == null)
			return;
		if (mAdapter != null) {
			// do something?
		}
	}
	
	private IAdditionalHandler mOnItemClickHandler = null;
	
	public void setOnItemClickHandler(IAdditionalHandler onItemClickHandler) {
		this.mOnItemClickHandler = onItemClickHandler;
	}

	@Override
	public void onListItemClick(ListView l, View v, int position, long id) {
		if (mAdapter == null) {
			return;
		}
		super.onListItemClick(l, v, position, id);
		if (Constants.PREF_DEFAULT_LONG == id) {
			return;
		}
		if (mOnItemClickHandler != null) {
			mOnItemClickHandler.handle(mAdapter.getItem(position));
		}
	}
}

Der ListAdapter ist jetzt eher ugly: Man sollte eigentlich das ViewHolder-Pattern verwenden, dass habe ich hier einmal geflissentlich ignoriert und baue die Views immer wieder neu. Das macht in meinem Fall aber nicht so viel, dass ich nur eine Handvoll Elemente habe :)
Java:
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;

public enum DrawerItemEnum {

	MAIN(R.drawable.cnlab_notification, R.string.drawer_measurement),
	//
	HELP(R.drawable.ic_action_help, R.string.drawer_help),
	//
	SETTINGS(R.drawable.ic_action_settings, R.string.drawer_settings),
	//
	VIEW_RESULTS(Constants.PREF_DEFAULT_INTEGER, R.string.drawer_view_results),
	//
	SEND_FEEDBACK(Constants.PREF_DEFAULT_INTEGER, R.string.drawer_send_feedback),
	//
	CHANGELOG(Constants.PREF_DEFAULT_INTEGER, R.string.drawer_changelog),
	//
	ABOUT(Constants.PREF_DEFAULT_INTEGER, R.string.drawer_about), ;
	
	private final int mItemIconId;
	private final int mItemTextId;
	
	private DrawerItemEnum(final int itemIconId, final int itemTextId) {
		this.mItemIconId = itemIconId;
		this.mItemTextId = itemTextId;
	}
	
	public int getItemIconId() {
		return mItemIconId;
	}
	
	public int getItemTextId() {
		return mItemTextId;
	}
	
	public static DrawerItemEnum findBySortId(int sortId) {
		for (DrawerItemEnum o : values()) {
			if (o.mItemIconId == sortId)
				return o;
		}
		return null;
	}
	
	public static DrawerItemEnum[] getDefaultValues() {
		return new DrawerItemEnum[] { MAIN, SETTINGS, VIEW_RESULTS, SEND_FEEDBACK, CHANGELOG, ABOUT };
	}
	
	public static final class DrawerItemArrayAdapter extends ArrayAdapter<DrawerItemEnum> {
		
		private LayoutInflater mInflater;
		
		public DrawerItemArrayAdapter(Context context) {
			super(context, R.layout.simple_selection_item, android.R.layout.simple_list_item_single_choice, getDefaultValues());
			mInflater = LayoutInflater.from(getContext());
		}
		
		private DrawerItemEnum selection = MAIN;
		
		public void setSelection(DrawerItemEnum selection) {
			this.selection = selection;
		}
		
		public DrawerItemEnum getSelection() {
			return selection;
		}
		
		@Override
		public View getDropDownView(int position, View convertView, ViewGroup parent) {
			final DrawerItemEnum currentItem = getItem(position);
			View v = null;
			switch (currentItem) {
			default:
				v = mInflater.inflate(R.layout.drawer_row, parent, false);
				v.setSelected(currentItem == selection);
				ImageView icon = (ImageView) v.findViewById(R.id.icon);
				if (icon != null) {
					icon.getLayoutParams().height = UIUtils.getDipsFromPixel(getContext(), 32);
					icon.getLayoutParams().width = UIUtils.getDipsFromPixel(getContext(), 32);
					if (Constants.PREF_DEFAULT_INTEGER != currentItem.mItemIconId) {
						icon.setImageResource(currentItem.mItemIconId);
					} else {
						icon.setImageResource(R.drawable.empty);
					}
				}
				TextView text = (TextView) v.findViewById(R.id.text);
				if (text != null) {
					text.setText(currentItem.mItemTextId);
				}
				break;
			}
			return v;
		}
		
		@Override
		public View getView(int position, View convertView, ViewGroup parent) {
			final DrawerItemEnum currentItem = getItem(position);
			View v = null;
			switch (currentItem) {
			default:
				v = mInflater.inflate(R.layout.drawer_row, parent, false);
				v.setSelected(currentItem == selection);
				ImageView icon = (ImageView) v.findViewById(R.id.icon);
				if (icon != null) {
					icon.getLayoutParams().height = UIUtils.getDipsFromPixel(getContext(), 32);
					icon.getLayoutParams().width = UIUtils.getDipsFromPixel(getContext(), 32);
					if (Constants.PREF_DEFAULT_INTEGER != currentItem.mItemIconId) {
						icon.setImageResource(currentItem.mItemIconId);
					} else {
						icon.setImageResource(R.drawable.empty);
					}
				}
				TextView text = (TextView) v.findViewById(R.id.text);
				if (text != null) {
					text.setText(currentItem.mItemTextId);
				}
				break;
			}
			return v;
		}
	}
}
Das alles ist noch Teil der Vorbereitung: Die App hat jetzt eine leere Oberfläche. Die in der Activity verlinkten Fragmente habe ich ja noch nicht gepostet.

Und gleich geht's weiter
 

dzim

Top Contributor
Dieser Post soll das hier einmal abschliessen...

Um mir in den nächsten Schritten die Arbeit zu erleichtern, habe ich eine Reihe von Hilfsklassen erstellt:
Da wäre z.B. der CustomViewPager, der android.support.v4.view.ViewPager erweitert, damit man auf der Map ungestört herumwischen kann, ohne dass jedes Mal bei horizontalen wischgesten der ViewPager getriggert wird.
Java:
import android.content.Context;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.View;

import com.google.android.maps.MapView;

public class CustomViewPager extends ViewPager {
	
	public CustomViewPager(Context context) {
		super(context);
	}
	
	public CustomViewPager(Context context, AttributeSet attrs) {
		super(context, attrs);
	}
	
	@Override
	protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) {
		if (v instanceof MapView || v.getClass().getName().startsWith("maps.")) {
			return true;
		}
		return super.canScroll(v, checkV, dx, x, y);
	}
}

Mein MainViewPagerFragment und SettingsViewPagerFragment erben von der Klasse CustomViewPagerFragment, das einen ViewPager enthält (dieser wird im XML gesetzt und ist der zuvor gezeigte CustomviewPager).
Java:
import java.lang.reflect.InvocationTargetException;
import java.util.Locale;

import android.animation.ObjectAnimator;
import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.view.ViewPager;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.HorizontalScrollView;
import android.widget.TabHost;
import android.widget.TabHost.TabContentFactory;
import android.widget.TabHost.TabSpec;
import android.widget.TextView;

public abstract class CustomViewPagerFragment extends Fragment implements TabHost.OnTabChangeListener, ViewPager.OnPageChangeListener {
	
	// --------------------------------------------------------------
	// setup part
	// --------------------------------------------------------------
	
	protected Class<? extends CustomFragmentPagerAdapter> mCustomFragmentPagerAdapterClass = null;
	protected String[] mListenTo;
	protected boolean mSeparatorVisible = false;
	protected Fragment mCurrentFragment = null;
	protected int mCurrentFragmentIndex = Constants.PREF_DEFAULT_INTEGER;
	public void setCustomFragmentPagerAdapterClass(Class<? extends CustomFragmentPagerAdapter> customFragmentPagerAdapterClass) {
		if (customFragmentPagerAdapterClass == null)
			throw new IllegalArgumentException("Specify a valid CustomFragmentPagerAdapter!");
		this.mCustomFragmentPagerAdapterClass = customFragmentPagerAdapterClass;
	}
	
	public abstract String[] createListenTo();
	
	public String[] getListenTo() {
		return mListenTo;
	}
	
	public void setListenTo(String[] listenTo) {
		this.mListenTo = listenTo;
	}
	
	public boolean isSeparatorVisible() {
		return mSeparatorVisible;
	}
	
	public void setSeparatorVisible(boolean separatorVisible) {
		this.mSeparatorVisible = separatorVisible;
	}
	
	public Fragment getCurrentFragment() {
		return mCurrentFragment;
	}
	
	public int getCurrentFragmentIndex() {
		return mCurrentFragmentIndex;
	}

	/**
	 * Use this method to handle your custom events (see {@link #setListenTo(String[])}).
	 * 
	 * @param event
	 *          the event passed to this method from the registered listener
	 */
	public abstract void handleEvent(Event event);
	public abstract void onTabFragmentSelected(Fragment fragment);
	/**
	 * <b>Example Usage:</b><br/>
	 * <code>
	 * if (getString(R.string.testSettings_subscription).equals(tabTitle))<br/>
	 * 		onPageSelected(0);<br/>
	 * else if (getString(R.string.historyServer).equals(tabTitle))<br/>
	 * 		onPageSelected(1);<br/>
	 * else if (getString(R.string.testSettings).equals(tabTitle))<br/>
	 * 		onPageSelected(2);<br/>
	 * else if (getString(R.string.advancedPage_title).equals(tabTitle))<br/>
	 * 		onPageSelected(3);<br/>
	 * else if (getString(R.string.uiOptionsPage_title).equals(tabTitle))<br/>
	 * 		onPageSelected(4);<br/>
	 * </code>
	 * 
	 * @param tabTitle
	 *          the tab to switch to - defined by it's name
	 */
	public abstract void setCurrentTab(String tabTitle);
	
	// --------------------------------------------------------------
	// internal part
	// --------------------------------------------------------------
	
	protected EventHandlerListener mEventHandlerListener;
	/**
	 * The {@link android.support.v4.view.PagerAdapter} that will provide fragments for each of the sections. We use a
	 * {@link android.support.v4.app.FragmentPagerAdapter} derivative, which will keep every loaded fragment in memory. If this becomes too memory
	 * intensive, it may be best to switch to a {@link android.support.v4.app.FragmentStatePagerAdapter}.
	 */
	protected CustomFragmentPagerAdapter mCustomFragmentPagerAdapter;
	/**
	 * The {@link ViewPager} that will host the section contents.
	 */
	protected ViewPager mViewPager;
	private TabHost mTabHost;
	
	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
		mListenTo = createListenTo();
		mEventHandlerListener = new EventHandlerListener() {
			@Override
			public void handleEvent(Event event) {
				CustomViewPagerFragment.this.handleEvent(event);
			}
		};
		if (mEventHandlerListener != null && mListenTo != null) {
			EventHandler.getInstance().addListener(mEventHandlerListener, mListenTo);
		}
		View view = inflater.inflate(R.layout.fragment_viewpager, container, false);
		mViewPager = (ViewPager) view.findViewById(R.id.pager);
		mTabHost = (TabHost) view.findViewById(android.R.id.tabhost);
		mTabHost.setup();
		View sep = view.findViewById(R.id.sep);
		if (sep != null) {
			if (mSeparatorVisible) {
				sep.setVisibility(View.VISIBLE);
			} else {
				sep.setVisibility(View.GONE);
			}
		}
		try {
			mCustomFragmentPagerAdapter = mCustomFragmentPagerAdapterClass.getConstructor(Context.class, FragmentManager.class).newInstance(getActivity(),
					getChildFragmentManager());
		} catch (Exception e) {
			Log.e(CustomViewPagerFragment.class.getSimpleName() + "#onCreateView:mCustomFragmentPagerAdapter", e.getMessage(), e);
		}
		updateTabs(mCustomFragmentPagerAdapter, Constants.PREF_DEFAULT_INTEGER);
		mViewPager.setOnPageChangeListener(this);
		mTabHost.setOnTabChangedListener(this);
		mCurrentFragment = mCustomFragmentPagerAdapter.mFragments.get(0);
		return view;
	}
	
	protected void updateTabs(final CustomFragmentPagerAdapter adapter, final int currentTab) {
		mViewPager.setAdapter(adapter);
		mTabHost.clearAllTabs();
		for (int i = 0; i < mCustomFragmentPagerAdapter.getCount(); i++) {
			TabSpec tabSpec = mTabHost.newTabSpec(String.format(Locale.ENGLISH, CustomFragmentPagerAdapter.FRAGMENT_TAG, R.id.pager, i))
					.setIndicator(mCustomFragmentPagerAdapter.getPageTitle(i)).setContent(new TabFactory(getActivity()));
			mTabHost.addTab(tabSpec);
		}
		setTabStyle(mTabHost);
		if (currentTab > Constants.PREF_DEFAULT_INTEGER) {
			mViewPager.setCurrentItem(currentTab);
		}
		triggerScrollAnimation();
	}

	// without this tab programatic changes look aweful!
	protected void triggerScrollAnimation() {
		if (getView() == null)
			return;
		final HorizontalScrollView hScrollView = (HorizontalScrollView) getView().findViewById(android.R.id.tabs).getParent();
		if (hScrollView == null)
			return;
		hScrollView.post(new Runnable() {
			@Override
			public void run() {
				int scrollX = (mTabHost.getCurrentTabView().getLeft() - (hScrollView.getWidth() / 2)) + (mTabHost.getCurrentTabView().getWidth() / 2);
				// hScrollView.smoothScrollTo(scrollX, 0);
				ObjectAnimator animator = ObjectAnimator.ofInt(hScrollView, "scrollX", scrollX);
				animator.setDuration(250);
				animator.start();
			}
		});
	}
	
	private class TabFactory implements TabContentFactory {
		
		private final Context mContext;
		
		public TabFactory(Context context) {
			mContext = context;
		}
		
		@Override
		public View createTabContent(String tag) {
			View v = new View(mContext);
			v.setMinimumWidth(0);
			v.setMinimumHeight(0);
			return v;
		}
	}
	
	public void setTabStyle(TabHost tabhost) {
		tabhost.getTabWidget().setBackgroundResource(R.drawable.tab_bg_shape);
		for (int i = 0; i < tabhost.getTabWidget().getChildCount(); i++) {
			TextView tv = (TextView) tabhost.getTabWidget().getChildAt(i).findViewById(android.R.id.title);
			tv.setTextAppearance(getActivity(), R.style.cnlabTextView_Medium);
			tv.setAllCaps(false);
			tv.setPadding(UIUtils.getDipsFromPixel(getActivity(), 5), tv.getPaddingTop(), UIUtils.getDipsFromPixel(getActivity(), 5), tv.getPaddingBottom());
			tv.setTextColor(getResources().getColor(R.color.white));
			tabhost.getTabWidget().getChildAt(i).setBackgroundResource(R.drawable.tab_selector);
		}
	}
	
	@Override
	public void onResume() {
		EventHandler.getInstance().addListener(mEventHandlerListener, mListenTo);
		super.onResume();
	}
	
	@Override
	public void onDestroyView() {
		EventHandler.getInstance().removeListener(mEventHandlerListener, mListenTo);
		super.onDestroyView();
	}
	
	@Override
	public void onDestroy() {
		EventHandler.getInstance().removeListener(mEventHandlerListener, mListenTo);
		super.onDestroy();
	}
	
	@Override
	public void onPageScrollStateChanged(int arg0) {}
	
	@Override
	public void onPageScrolled(int arg0, float arg1, int arg2) {}
	
	@Override
	public void onPageSelected(int position) {
		mTabHost.setCurrentTab(position);
		triggerScrollAnimation();
	}
	
	@Override
	public void onTabChanged(String tabId) {
		mViewPager.setCurrentItem(mTabHost.getCurrentTab());
		if (mCustomFragmentPagerAdapter != null) {
			// Fragment fragment = mCustomFragmentPagerAdapter.mFragments.get(mViewPager.getCurrentItem());
			FragmentManager fm = getChildFragmentManager();
			Fragment fragment = fm.findFragmentByTag(String.format(CustomFragmentPagerAdapter.FRAGMENT_TAG, R.id.pager, mViewPager.getCurrentItem()));
			if (fragment != null) {
				mCurrentFragment = fragment;
				mCurrentFragmentIndex = mViewPager.getCurrentItem();
				onTabFragmentSelected(fragment);
			}
		}
		triggerScrollAnimation();
	}
	
	public void setCurrentTab(int position) {
		onPageSelected(position);
	}
}

Die konkreten Implementierungen für MainViewPagerFragment und SettingsViewPagerFragment spielen hier keine Rolle, wichtig ist nur noch der CustomFragmentPagerAdapter der in diesen Klassen verwendet wird (bzw. eine Implementierung dieser Klasse, die hier aber auch eher unwichtig ist).
Java:
import java.util.ArrayList;
import java.util.List;

import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;

public abstract class CustomFragmentPagerAdapter extends FragmentPagerAdapter {
	
	/**
	 * <b>Hint, how the fragments tag are created</b><br/>
	 * <br/>
	 * <code>viewId</code> is the ID of the pager, here: <code>@+id/pager</code><br/>
	 * <br/>
	 * <code>
	 * private static String makeFragmentName(int viewId, int index) {<br/>
	 * return "android:switcher:" + viewId + ":" + index;<br/>
	 * }
	 * </code><br/>
	 * <br/>
	 * <b>Usage example:</b><br/>
	 * <code>
	 * FragmentManager fm = getSupportFragmentManager();<br/>
	 * Fragment fragment = fm.findFragmentByTag(String.format(MainSectionsPagerAdapter.FRAGMENT_TAG, R.id.pager, mViewPager.getCurrentItem()));
	 * </code>
	 */
	public static final String FRAGMENT_TAG = "android:switcher:%d:%d";
	
	protected final Context mContext;
	protected final FragmentManager mFragmentManager;
	
	protected final List<Fragment> mFragments = new ArrayList<Fragment>();
	
	protected Bundle mArguments = null;
	
	public CustomFragmentPagerAdapter(Context context, FragmentManager fragmentManager) {
		super(fragmentManager);
		this.mContext = context;
		this.mFragmentManager = fragmentManager;
		mFragments.addAll(createFraments());
	}
	
	public abstract List<Fragment> createFraments();
	
	public List<Fragment> getFragments() {
		return mFragments;
	}
	
	public void setArguments(Bundle arguments) {
		this.mArguments = arguments;
	}
}

Es sei anzumerken, dass ich hier einige Klassen nicht zeige, weil sie z.T. unwichtig sind. Wenn du einen ähnlichen Ansatz verfolgen willst, musst du den Code eh auf deine Bedürfnisse anpassen!

Berichte mal, ob dir das hilft.
Daniel
 
Ähnliche Java Themen

Ähnliche Java Themen

Neue Themen


Oben