Sherlock, Fragments, Tabs and MapView - android

As i point in the headline I have implemented ActionBar Sherlock and Tab navigation inside. Tabs are fragments. Inside one Fragment I have a mapView. I have some problems when i change between tabs. Two tabs are just lists, inside one is MapView with some other views and one with some settings informations.
My problem is that when i change tabs i get some flickering... It's just long enough to catch it with an eye. This is when i move in regular tabs, but when i go to a mapview tab first i get a black screen that lasts a bit longer then a flickering.
Does somebody had some issues with this or some similar problems???
EDITED CODE:
#Override
protected void onCreate(Bundle arg0) {
super.onCreate(arg0);
//setContentView(R.layout.sherlock);
Log.i(TAG, "onCreate");
settings_drawable = new StateListDrawable();
settings_drawable.addState(new int [] {STATE_PRESSED}, getResources().getDrawable(R.drawable.jk_uma_button_settings_pressed));
settings_drawable.addState(new int[] {}, getResources().getDrawable(R.drawable.jk_uma_button_settings_normal));
home = new StateListDrawable();
home.addState(new int [] {STATE_PRESSED}, getResources().getDrawable(R.drawable.jk_button_home_pressed));
home.addState(new int[] {}, getResources().getDrawable(R.drawable.jk_button_home_normal));
bar = getSupportActionBar();
bar.setDisplayShowTitleEnabled(false);
bar.setIcon(R.drawable.jk_uma_logo);
bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
bar.setHomeButtonEnabled(true);
tabs_adapter = new TabAdapter(this);
tabs_adapter.addTab(bar.newTab().setText(" Home").setIcon(R.drawable.jk_icon_home), "Tab1", MapHome.class, null);
tabs_adapter.addTab(bar.newTab().setText(" Explore").setIcon(R.drawable.jk_icon_explore), "Tab2", MapExplore.class, null);
tabs_adapter.addTab(bar.newTab().setText(" My Views").setIcon(R.drawable.jk_icon_myview), "Tab3", MapMyStreams.class, null);
}
public static class TabAdapter implements ActionBar.TabListener {
private final Context context;
private final ActionBar action_bar;
private final HashMap<String, TabInfo> tabs = new HashMap<String, TabInfo>();
private TabInfo last_tab = null;
private TabInfo camera_info;
private String current_camera_tab;
private String current_fragment_tab;
private class TabInfo {
private String tag;
private Class clss;
private Bundle args;
private Fragment fragment;
private Fragment fragment_details;
private String current_fragment;
TabInfo(String tag, Class clazz, Bundle args, String curent) {
this.tag = tag;
this.clss = clazz;
this.args = args;
this.current_fragment = curent;
}
}
public TabAdapter(SherlockFragmentActivity activity) {
super();
this.context = activity;
this.action_bar = activity.getSupportActionBar();
}
public void addTab(ActionBar.Tab tab, String tag, Class<?> clss, Bundle args){
Log.i(((Sherlock)context).TAG, "addTab");
TabInfo info = new TabInfo(tag, clss, args, "1");
tab.setTag(tag);
tab.setTabListener(this);
tabs.put(tag, info);
action_bar.addTab(tab);
}
Handler h = new Handler(){
#Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switchTab(String.valueOf(msg.obj));
}
};
public void changeOnRuntime(String camera_no){
Log.i("TABS ADAPTER", "=================changeOnRuntime========="+camera_no);
Bundle args = new Bundle();
args.putString("camera_no", camera_no);
FragmentTransaction ft = ((Sherlock)context).getSupportFragmentManager().beginTransaction();
String tag = (String) action_bar.getSelectedTab().getTag();
TabInfo tab = tabs.get(tag);
Fragment fragm = MapCamera.newInstance(camera_no);
tab.fragment_details = fragm;
tab.current_fragment = "2";
ft.hide(tab.fragment);
ft.add(android.R.id.content, tab.fragment_details, "Tab5");
ft.commit();
}
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
Log.i("TAB SELECTED", "===================NOT NULL=============="+ ft);
if(ft == null){
Log.i("TAB SELECTED", "===================NULLLLLLLLLLLL==============");
}
String tag = (String) tab.getTag();
TabInfo newTab = (TabInfo) this.tabs.get(tag);
if (last_tab != newTab) {
if (newTab != null) {
Log.i("TAB SELECTED", "===================NEW TAB==============");
if(newTab.current_fragment.equalsIgnoreCase("1")){
Log.i("TAB SELECTED", "===================NEW TAB 1==============");
if (newTab.fragment == null) {
Log.i("TAB SELECTED", "===================NEW TAB 1 NULL==============");
newTab.fragment = Fragment.instantiate(context,
newTab.clss.getName(), newTab.args);
ft.add(android.R.id.content, newTab.fragment, newTab.tag);
}else {
Log.i("TAB SELECTED", "===================NEW TAB 1 NOT NULL==============");
ft.attach(newTab.fragment);
}
}else{
Log.i("TAB SELECTED", "===================NEW TAB 2==============");
ft.attach(newTab.fragment_details);
}
}
last_tab = newTab;
}
}
}
public void switchTab(String tab){
if(tab.equalsIgnoreCase("Tab1")){
action_bar.setSelectedNavigationItem(0);
}else if (tab.equalsIgnoreCase("Tab2")) {
action_bar.setSelectedNavigationItem(1);
}else if (tab.equalsIgnoreCase("Tab4")) {
action_bar.setSelectedNavigationItem(3);
}
}
#Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
Log.i("TAB SELECTED", "=================== 2222 ==============");
if (last_tab != null) {
if (last_tab.fragment != null) {
if(last_tab.current_fragment.equalsIgnoreCase("1")){
Log.i("TAB SELECTED", "=================== detach 1 ==============");
ft.detach(last_tab.fragment);
}else{
Log.i("TAB SELECTED", "=================== detach 2 ==============");
ft.detach(last_tab.fragment_details);
}
}
}
}
#Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
// TODO Auto-generated method stub
}
}

The "black view" that it sounds like you're describing is a know issue when switching between fragments, one of which is a v2 map. You can read more about it in this post. I have encountered this issue myself. The solution proposed in the cited post is very simple.
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent" >
<android.support.v4.view.ViewPager
android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</android.support.v4.view.ViewPager>
<!-- hack to fix ugly black artefact with maps v2 -->
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/transparent" />
</FrameLayout>
Adding a view over the black view that is transparent removes the issue. Not sure why but it does.

Related

FragmentManager not calling onCreateView with second tab after orientation change

I have 3 fragments in TabA, and a PreferenceFragment in TabB. To recreate the problem I start the program, TabA displays fine. I click TabB and it also displays fine. If I return to TabA, and do an orientation change, the next time I click on TabB there is just a blank screen. I've narrowed it down to the FragmentManager not calling onCreateView on the Fragment in TabB.
I'm checking that the Fragments are not null and don't need to be recreated and getting references to them with their findFragmentByTag after orientation changes. TabA never has an issue, i tried to recreate the issue with TabA but onCreateView would always get called by the FragmentManager for each Fragment. I have min API 15, target 19.
Pruned down version of MyActivity.java to be runnable
public class MyActivity extends Activity {
private static final String TAG = "MainActivity";
public FragmentManager fm;
#Override
protected void onCreate(Bundle savedInstanceState) {
Log.d(TAG, "onCreate");
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_master);
fm = getFragmentManager();
final ActionBar actionBar = getActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
ActionBar.Tab tabA = actionBar.newTab().setText("Main");
ActionBar.Tab tabB = actionBar.newTab().setText("Settings");
tabA.setTabListener(new TabAListener(this));
actionBar.addTab(tabA);
tabB.setTabListener(new TabBListener(this));
actionBar.addTab(tabB);
if (savedInstanceState != null) {
int index = savedInstanceState.getInt("index");
actionBar.setSelectedNavigationItem(index);
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
Log.d(TAG, "onSaveInstanceState");
super.onSaveInstanceState(outState);
int i = getActionBar().getSelectedNavigationIndex();
outState.putInt("index", i);
}
public class TabAListener implements ActionBar.TabListener {
private static final String genTag = "GenerateFragment";
private static final String aboutTag = "AboutFragment";
public static final String resultsTag = "ResultsListFragment";
private ArrayList<Fragment> fragList;
public TabAListener(Activity activity) {
fragList = null;
}
public void onTabReselected(ActionBar.Tab tab, FragmentTransaction ft) {
// Reselected don't do anything
Log.d(TAG, "Tab A: on Tab reselected");
}
public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) {
Log.d(TAG, "Tab A: on Tab Selected");
// attach all the fragments
if (fragList == null) {
fragList = new ArrayList<Fragment>();
TestFragment genFrag;
if (fm.findFragmentByTag(genTag) == null) {
genFrag = new TestFragment();
ft.add(R.id.gen_fragment, genFrag, genTag);
} else genFrag = (TestFragment) fm.findFragmentByTag(genTag);
TestFragment aboutFrag;
if (fm.findFragmentByTag(aboutTag) == null) {
aboutFrag = new TestFragment();
ft.add(R.id.about_fragment, aboutFrag, aboutTag);
} else aboutFrag = (TestFragment) fm.findFragmentByTag(aboutTag);
TestFragment resultsFrag;
if (fm.findFragmentByTag(resultsTag) == null) {
resultsFrag = new TestFragment();
ft.add(R.id.results_fragment, resultsFrag, resultsTag);
} else {
resultsFrag = (TestFragment) fm.findFragmentByTag(resultsTag);
}
fragList.add(genFrag);
fragList.add(aboutFrag);
fragList.add(resultsFrag);
Log.d(TAG, "Tab A: Added fragments to the ArrayList");
} else {
Iterator iter = fragList.iterator();
while (iter.hasNext()) {
Log.d(TAG, "Tab A: Attaching fragments");
ft.attach((Fragment) iter.next());
}
}
}
public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft) {
Log.d(TAG, "Tab A: on Tab Unselected");
if (fragList != null) {
Iterator iter = fragList.iterator();
while (iter.hasNext()) {
Log.d(TAG, "Tab A: Fragments detached");
ft.detach((Fragment) iter.next());
}
}
}
}
public class TabBListener implements ActionBar.TabListener {
private static final String settingsTag = "SettingsFragment";
private ArrayList<Fragment> fragList;
public TabBListener(Activity activity) {
fragList = null;
}
public void onTabReselected(ActionBar.Tab tab, FragmentTransaction ft) {
// Reselected don't do anything
Log.d(TAG, "Tab B: on Tab reselected");
}
public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) {
Log.d(TAG, "Tab B: on Tab Selected");
// attach all the fragments
if (fragList == null) {
fragList = new ArrayList<Fragment>();
TestFragment settingsFrag;
if (fm.findFragmentByTag(settingsTag) == null) {
settingsFrag = new TestFragment();
ft.add(R.id.frame_main, settingsFrag, settingsTag);
} else {
Log.d(TAG, "Tab B: not null");
settingsFrag = (TestFragment) fm.findFragmentByTag(settingsTag);
}
fragList.add(settingsFrag);
Log.d(TAG, "Tab B: Added fragments to the ArrayList");
} else {
Iterator iter = fragList.iterator();
while (iter.hasNext()) {
Log.d(TAG, "Tab B: Attaching fragments");
ft.attach((Fragment) iter.next());
}
}
}
public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft) {
Log.d(TAG, "Tab B: on Tab Unselected");
if (fragList != null) {
Iterator iter = fragList.iterator();
while (iter.hasNext()) {
Log.d(TAG, "Tab B: Fragments detached");
ft.detach((Fragment) iter.next());
}
}
}
}
public static class TestFragment extends Fragment {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
return inflater.inflate(R.layout.fragment_text, container, false);
}
}
}
activity_master.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/frame_main"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<LinearLayout
android:layout_width="0dip"
android:layout_height="match_parent"
android:layout_weight="3"
android:orientation="vertical">
<FrameLayout
android:id="#+id/gen_fragment"
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="1" />
<FrameLayout
android:id="#+id/about_fragment"
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="1" />
</LinearLayout>
<FrameLayout
android:id="#+id/results_fragment"
android:layout_width="0dip"
android:layout_height="match_parent"
android:layout_weight="2" />
</LinearLayout>
</FrameLayout>
fragment_text.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="test" />
</LinearLayout>
So, I guess I have to remove the super call in MainActivity.onSaveInstanceState in order for onCreateView to be called correctly for TabB's fragment after an orientation change. Umm, I'm not sure why that works so could someone explain why?
I've been able to gather that the super.onSaveInstanceState saves the activities views for when the user navigates away from the application and eventually returns. And the FragmentManager also has responsibility for the contents of the fragment through orientation changes. I'm kind of lost at that point.

Unable to start activity componentInfo Tablistener suddenly crashing the app

So i'm getting this annoying problem. I'm pretty noob when it comes to android, so any help would be nice.
This is my MainActivity which seems to be crashing according to LogCat.
The app i'm trying to create must pull data from XML data, which i'm trying to get. Then from this data it must set the tabs name (that's what i'm trying to do).
public class MainActivity extends SherlockActivity {
private String uniqeAppId;
private ArrayList<StartupInfo> info;
private String ChannelTab;
private String VicinityTab;
private String CustomTab;
private String TrackingTab;
private String MoreTab;
public static Context appContext;
private DownloadXmlTask downloadxml = new DownloadXmlTask(this);
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
info = new ArrayList<StartupInfo>();
downloadxml.loadPage();
appContext = getApplicationContext();
ActionBar actionbar = getSupportActionBar();
actionbar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
actionbar.setTitle(uniqeAppId);
ActionBar.Tab Frag1 = actionbar.newTab().setText(ChannelTab);
ActionBar.Tab Frag2 = actionbar.newTab().setText(VicinityTab);
ActionBar.Tab Frag3 = actionbar.newTab().setText(CustomTab);
ActionBar.Tab Frag4 = actionbar.newTab().setText(TrackingTab);
ActionBar.Tab Frag5 = actionbar.newTab().setText(MoreTab);
Fragment Fragment1 = new Channeltab();
Fragment Fragment2 = new Vicinitytab();
Fragment Fragment3 = new Customtab();
Fragment Fragment4 = new Trackingtab();
Fragment Fragment5 = new Moretab();
Frag1.setTabListener(new MyTabListener(Fragment1));
Frag2.setTabListener(new MyTabListener(Fragment2));
Frag3.setTabListener(new MyTabListener(Fragment3));
Frag4.setTabListener(new MyTabListener(Fragment4));
Frag5.setTabListener(new MyTabListener(Fragment5));
actionbar.addTab(Frag1);
actionbar.addTab(Frag2);
actionbar.addTab(Frag3);
actionbar.addTab(Frag4);
actionbar.addTab(Frag5);
}
public void GetTextForTabs(ArrayList<StartupInfo> info2) {
this.info = info2;
StartupInfo info3 = info.get(0);
this.ChannelTab = info3.getChannelTab();
this.VicinityTab = info3.getVicinityTab();
this.CustomTab = info3.getCustomTab();
this.TrackingTab = info3.getTrackingTab();
this.MoreTab = info3.getMoreTab();
}
#Override
public void onStart() {
super.onStart();
}
public void setInfo(ArrayList<StartupInfo> info) {
this.info = info;
}
public void alert(String msg) {
Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_LONG).show();
}
public class MyTabListener implements ActionBar.TabListener {
public Fragment fragment;
public MyTabListener(Fragment fragment) {
this.fragment = fragment;
}
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
ft.replace(R.id.fragment_container, fragment);
}
#Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
ft.remove(fragment);
}
#Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
}
}
}
Then the LogCat:
It seems to be the TabListener. But I don't understand why. It wasn't doing that earlier. It was when i tried to add data it started to crash. Can anyone help me here ?
You have a null pointer exception at line 111 of your activity (in onTabSelected). It looks as though the null reference is probably to "fragment". Look at the section on "Performing fragment transactions":
http://developer.android.com/guide/components/fragments.html
This code will not fit your program exactly, but it gives you the general idea. You need to begin, do your add/replace/why and then commit.
By the by, since you are using ActionBarSherlock why not use the Support library so as to be able to support older versions of Android ?
Here is a simple example (it contains some superfluous stuff that you don't need) that might help:
public class ExtraContent extends SherlockFragmentActivity {
// Declare Tab Variable
com.actionbarsherlock.app.ActionBar.Tab tab;
boolean mDebugLog = false;
String mDebugTag="ian_";
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//mDebugLog = true;
debugLog("ExtraContent onCreate" );
// Create the actionbar
com.actionbarsherlock.app.ActionBar bar = getSupportActionBar();
// Show Actionbar Home Icon (as normal)
bar.setDisplayShowHomeEnabled(true);
// Show Actionbar Title (as normal)
bar.setDisplayShowTitleEnabled(true);
// Create Actionbar Tabs
bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
//enable home ...
bar.setDisplayHomeAsUpEnabled(true); // ?
bar.setHomeButtonEnabled(true); // this is the one that enables home navigation
//ib18 view for fragments ...
setContentView(R.layout.extra_content);
//create the fragment we want to use for display content
Fragment ExtraLogin = new ExtraLogIn();
// Create First Tab
ActionBar.Tab tab0 = bar.newTab();
tab0 = bar.newTab();
tab0.setText("Unlock");
tab0.setTabListener(new TabListener<ExtraTab0>(this, "tab0",ExtraTab0.class, null));
bar.addTab(tab0);
// Create Second Tab
ActionBar.Tab tab1 = bar.newTab();
tab1 = bar.newTab();
tab1.setText("Level 1");
tab1.setTabListener(new TabListener<ExtraTab1>(this, "tab1",ExtraTab1.class, null));
bar.addTab(tab1);
// Create Third Tab
ActionBar.Tab tab2 = bar.newTab();
tab2 = bar.newTab();
tab2.setText("Level 2");
tab2.setTabListener(new TabListener<ExtraTab2>(this, "tab2",ExtraTab2.class, null));
bar.addTab(tab2);
if (savedInstanceState != null) { //if there is a saved bundle use it ...
bar.setSelectedNavigationItem(savedInstanceState.getInt("tab", 0));
}
else {
//ib18 savedInstanceState null so fti so start Login frag ...
FragmentManager fm = getSupportFragmentManager();
fm.beginTransaction().replace(R.id.fb, ExtraLogin, "ExtraLogin").commit();
}
}
public boolean onMenuItemSelected(int featureId, MenuItem item) {
debugLog("ExtraContent onMenuItemSelected" );
int itemId = item.getItemId();
switch (itemId) {
case android.R.id.home:
// app icon in action bar clicked; go home
Intent intent = new Intent(this, QuizLaunch.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
debugLog("ExtraContent onSaveInstanceState");
super.onSaveInstanceState(outState);
outState.putInt("tab", getSupportActionBar().getSelectedNavigationIndex());
}
public class TabListener<T extends Fragment> implements ActionBar.TabListener{
private final FragmentActivity mActivity;
private final String mTag;
private final Class<T> mClass;
private final Bundle mArgs;
private Fragment mFragment;
public TabListener (FragmentActivity activity, String tag, Class<T> clz,
Bundle args) {
mActivity = activity;
mTag = tag;
mClass = clz;
mArgs = args;
debugLog("ExtraContent TabListener" );
FragmentTransaction ft = mActivity.getSupportFragmentManager().beginTransaction();
// Check to see if we already have a fragment for this tab, probably
// from a previously saved state. If so, deactivate it, because our
// initial state is that a tab isn't shown.
mFragment = mActivity.getSupportFragmentManager().findFragmentByTag(mTag);
//
if (mFragment != null && !mFragment.isDetached()) {
ft.detach(mFragment);
}
ft.commit();
}
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
debugLog("ExtraContent onTabSelected");
ft = mActivity.getSupportFragmentManager()
.beginTransaction();
if (mFragment == null) {
mFragment = Fragment.instantiate(mActivity, mClass.getName(),mArgs);
debugLog("adding fragment "+mTag );
ft.add(R.id.tab, mFragment, mTag); //ib18 add to "tab" holder
ft.show(mFragment); //ib1.6 show fragment ...
ft.commit();
} else {
debugLog("attaching fragment "+mTag );
ft.attach(mFragment);
ft.show(mFragment); //ib1.6 show fragment ...
ft.commit();
}
}
#Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
debugLog("ExtraContent onTabUnSelected");
ft = mActivity.getSupportFragmentManager()
.beginTransaction();
if (mFragment != null) {
debugLog("hide and detach fragment "+mFragment );
ft.hide(mFragment); //ib1.6 hide fragment ...
ft.detach(mFragment);
ft.commitAllowingStateLoss();
}
}
#Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
// TODO Auto-generated method stub
debugLog("ExtraContent onTabReSelected");
}
}
void debugLog(String message) {
if (mDebugLog)
Log.d(mDebugTag, message);
}
}

how to put an expandable list inside a ActionBar tab fragment?

Hi im a bit noob in android so i hope anyone can help me
i have an actionBar tab fragment, and i wanted to make a expandable list with data and put it on the fragment, i´ve been searching online but the examples are too complex and dont match my situation i just want a simple expandable list, can anyone help?
If I understand you correctly, you should only put ExpandableList inside of your fragment layout for particular layout for actionBar tab fragment. This should be really easy actually...
Can you provide us with some code maybe?
this is my class tabActionBarActivity:
public class TabActionBarActivity extends Activity {
String contextoId;
String BuId;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tab_action_bar);
ActionBar actionBar = getActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
String label1 = getResources().getString(R.string.label1);
Tab tab = actionBar.newTab();
tab.setText(label1);
TabListener<Tab1Fragment> tl = new TabListener<Tab1Fragment>(this, label1, Tab1Fragment.class);
tab.setTabListener(tl);
actionBar.addTab(tab);
String label2 = getResources().getString(R.string.label2);
tab = actionBar.newTab();
tab.setText(label2);
TabListener<Tab2Fragment> tl2 = new TabListener<Tab2Fragment>(this, label2, Tab2Fragment.class);
tab.setTabListener(tl2);
actionBar.addTab(tab);
BuId = getIntent().getExtras().getString("BUId");
contextoId = getIntent().getExtras().getString("CId");
Log.i("BUIdTabFrag", BuId);
private class TabListener<T extends Fragment> implements
ActionBar.TabListener {
private Fragment mFragment;
private final Activity mActivity;
private final String mTag;
private final Class<T> mClass;
public TabListener(Activity activity, String tag, Class<T> clz) {
mActivity = activity;
mTag = tag;
mClass = clz;
}
#Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
// TODO Auto-generated method stub
}
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
// Check if the fragment is already initialized
if (mFragment == null) {
// If not, instantiate and add it to the activity
mFragment = Fragment.instantiate(mActivity, mClass.getName());
ft.add(android.R.id.content, mFragment, mTag);
} else {
// If it exists, simply attach it in order to show it
ft.attach(mFragment);
}
}
#Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
if (mFragment != null) {
// Detach the fragment, because another one is being attached
ft.detach(mFragment);
}
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.tab_action_bar, menu);
return true;
}
and

Custom Back Stack for each Fragment in TabHost in Android

Since the TabActivity is deprecated I tried to replace it with Fragments which has been already mentioned in developer android website. But as you guys already know there was an issue about replacing tabs with fragments, since there will be only one activity ,which is Fragment Activity, there is no back stack for each of the fragments and as you can see in the other SO questions most of the developers were saying that you need to manage your own custom back stack as a solution.
I have created and implemented my own custom back stack as you can see below, it works perfect I can track each fragment in each tab.
Tab1
Fragment1 > Fragment2 > Fragment3
Tab2
Fragment5 > Fragment6
According to navigation above, if I navigate from Fragment1 through Fragment 3 and After that If I change the tab to Tab2 to and come back to Tab1, I can still see the Fragment3 and I can even navigate back to Fragment1 with my custom back stack.
But the issue is, When I come back to Tab1 and see the Fragment3, the Fragment3 is re-created and I can not see the changes as I left behind before I change the tab to Tab2.
Here is my Custom back stack;
public static HashMap<String, Stack<Fragment>> customBackStack;
public static Stack<Fragment> simpleStack;
public static Stack<Fragment> contactStack;
public static Stack<Fragment> customStack;
public static Stack<Fragment> throttleStack;
public static Stack<Fragment> homeStack;
customBackStack = new HashMap<String, Stack<Fragment>>();
homeStack = new Stack<Fragment>();
simpleStack = new Stack<Fragment>();
contactStack = new Stack<Fragment>();
customStack = new Stack<Fragment>();
throttleStack = new Stack<Fragment>();
customBackStack.put("home", homeStack);
customBackStack.put("simple", simpleStack);
customBackStack.put("contacts", contactStack);
customBackStack.put("custom", customStack);
customBackStack.put("throttle", throttleStack);
And here is onTabChanged method;
public void onTabChanged(String tabId) {
TabInfo newTab = mTabs.get(tabId);
if (mLastTab != newTab) {
FragmentTransaction ft = mActivity.getSupportFragmentManager().beginTransaction();
if (mLastTab != null) {
if (mLastTab.fragment != null) {
ft.detach(mLastTab.fragment);
}
}
if (newTab != null) {
if (newTab.fragment == null) {
if (!customBackStack.get(tabId).isEmpty()) {
Fragment fragment = customBackStack.get(tabId).pop();
customBackStack.get(tabId).push(fragment);
ft.replace(mContainerId, fragment);
}
} else {
if (!customBackStack.get(tabId).isEmpty()) {
Fragment fragment = customBackStack.get(tabId).pop();
customBackStack.get(tabId).push(fragment);
ft.replace(mContainerId, fragment);
}
}
}
mLastTab = newTab;
ft.commit();
mActivity.getSupportFragmentManager().executePendingTransactions();
}
}
And here is onBackPressed;
public void onBackPressed() {
Stack<Fragment> stack = customBackStack.get(mTabHost.getCurrentTabTag());
if (stack.isEmpty()) {
super.onBackPressed();
} else {
Fragment fragment = stack.pop();
if (fragment.isVisible()) {
if (stack.isEmpty()) {
super.onBackPressed();
} else {
Fragment frg = stack.pop();
customBackStack.get(mTabHost.getCurrentTabTag()).push(frg);
transaction = getSupportFragmentManager().beginTransaction();
transaction.setCustomAnimations(R.anim.slide_in_left, R.anim.slide_out_right,
R.anim.slide_in_right, R.anim.slide_out_left);
transaction.replace(R.id.realtabcontent, frg).commit();
}
} else {
getSupportFragmentManager().beginTransaction().replace(R.id.realtabcontent, fragment).commit();
}
}
}
As a result, custom back stack works fine except the last fragment before changing the tab is getting re-created after coming back to the tab, its not resuming as like in tab activity.
Any idea how to solve it ?
EDIT
You can find my sample Application here as a solution regarding to this issue.
GitHub
I modified googles sample tablistener to following:
public static class TabListener<T extends SherlockFragment> implements ActionBar.TabListener {
private final SherlockFragmentActivity mActivity;
private final String mTag;
private final Class<T> mClass;
private final Bundle mArgs;
public SherlockFragment mFragment;
private final Stack<SherlockFragment> mStack;
public TabListener(SherlockFragmentActivity activity, String tag, Class<T> clz) {
this(activity, tag, clz, null, null);
}
public TabListener(SherlockFragmentActivity activity, String tag, Class<T> clz, Bundle args, Stack<SherlockFragment> stack) {
mActivity = activity;
mTag = tag;
mClass = clz;
mArgs = args;
mStack = stack;
// Check to see if we already have a fragment for this tab, probably
// from a previously saved state. If so, deactivate it, because our
// initial state is that a tab isn't shown.
mFragment = (SherlockFragment) mActivity.getSupportFragmentManager().findFragmentByTag(mTag);
if (mFragment != null && !mFragment.isDetached()) {
FragmentTransaction ft = mActivity.getSupportFragmentManager().beginTransaction();
ft.detach(mFragment);
ft.commit();
}
}
public void onTabSelected(Tab tab, FragmentTransaction ft) {
// we need to reattach ALL fragments thats in the custom stack, if we don't we'll have problems with setCustomAnimation for fragments.
if (mFragment == null) {
mFragment = (SherlockFragment) SherlockFragment.instantiate(mActivity, mClass.getName(), mArgs);
ft.replace(android.R.id.content, mFragment, mTag);
} else {
ft.attach(mFragment);
}
if(mStack != null) {
for(SherlockFragment fragment: mStack) {
ft.attach(fragment);
}
}
}
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
if (mFragment != null) {
ft.detach(mFragment);
}
if(mStack != null) {
for(SherlockFragment fragment: mStack) {
if(fragment!= null && !fragment.isDetached()) {
ft.detach(fragment);
}
}
}
}
public void onTabReselected(Tab tab, FragmentTransaction ft) {
}
}
And the activity onKeyDown methode I override to following:
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
int index = getSupportActionBar().getSelectedNavigationIndex();
Stack<SherlockFragment> stack = null;
SherlockFragment fragment = null;
String rootTag = null;
switch(index) {
case 0:
stack = mWatersTabListener.mStack;
fragment = mWatersTabListener.mFragment;
rootTag = mWatersTabListener.mTag;
break;
case 1:
stack = mHarborTabListener.mStack;
fragment = mHarborTabListener.mFragment;
rootTag = mHarborTabListener.mTag;
break;
}
if(stack.isEmpty()) {
return super.onKeyDown(keyCode, event);
} else {
SherlockFragment topFragment = stack.pop();
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction ft = fragmentManager.beginTransaction();
ft.setCustomAnimations(R.anim.fragment_slide_right_enter,
R.anim.fragment_slide_right_exit);
if(topFragment != null && !topFragment.isDetached()) {
ft.detach(topFragment);
}
if(stack.isEmpty()) {
ft.replace(android.R.id.content, fragment, rootTag);
ft.commit();
return true;
} else {
SherlockFragment nextFragment = stack.peek();
ft.replace(android.R.id.content, nextFragment);
ft.commit();
return true;
}
}
}
return super.onKeyDown(keyCode, event);
}
The important things to take note of is that you have to attach all fragments in your custom stack when selected and you have to detach all as well when unselected. If there is problem with understanding the code snippets just ask.

tab contents using actionbarsherlock tab style

referring to this code below (taken from https://gist.github.com/1126843 ) how do i set the contents of the tabs?
public class NativeTabActivity extends Activity {
private TabHost mTabHost;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mTabHost = (TabHost)findViewById(android.R.id.tabhost);
mTabHost.setup();
addTab(new TextView(this), "Tab 1");
addTab(new TextView(this), "Tab 2");
addTab(new TextView(this), "Tab 3");
}
private void addTab(final View content, final String title) {
View tabView = LayoutInflater.from(this).inflate(R.layout.abs__action_bar_tab_layout, null);
TextView tv = (TextView) tabView.findViewById(R.id.abs__tab);
tv.setText(title);
TabSpec setContent = mTabHost.newTabSpec(title).setIndicator(tabView).setContent(new TabContentFactory() {
public View createTabContent(String tag) {
return content;
}
});
mTabHost.addTab(setContent);
}
}
from the code, it seems I need to put the contents under the View createTabContent(String tag) but how do I do it?
I found Rymnel's answer very helpful, but I had to make some changes to get it working properly with ActionBarSherlock 4.0. I was having problems with overriding the onTab methods passing in FragmentTransactions, so I just used the default methods and reassigned the "ft" var inside the method. I'm sure there's a cleaner way to do this, but here is my working code:
public class TabTestActivity extends SherlockFragmentActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActionBar bar = getSupportActionBar();
bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
bar.setDisplayOptions(0, ActionBar.DISPLAY_SHOW_TITLE);
bar.setDisplayHomeAsUpEnabled(true);
bar.setDisplayShowTitleEnabled(true);
bar.setTitle("Activity Title");
bar.addTab(bar
.newTab()
.setText("Tab 1")
.setTabListener(
new TabListener<TabTest1>(this, "tab1",
TabTest1.class, null)));
bar.addTab(bar
.newTab()
.setText("Tab 2")
.setTabListener(
new TabListener<TabTest2>(this, "tab2",
TabTest2.class, null)));
bar.addTab(bar
.newTab()
.setText("Tab 3")
.setTabListener(new TabListener<TabTest3>(this, "tab3", TabTest3.class, null)));
if (savedInstanceState != null) {
bar.setSelectedNavigationItem(savedInstanceState.getInt("tab", 0));
}
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
// app icon in action bar clicked; go home
Intent intent = new Intent(this, DashboardActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("tab", getSupportActionBar()
.getSelectedNavigationIndex());
}
public class TabListener<T extends Fragment> implements
ActionBar.TabListener {
private final FragmentActivity mActivity;
private final String mTag;
private final Class<T> mClass;
private final Bundle mArgs;
private Fragment mFragment;
public TabListener(FragmentActivity activity, String tag, Class<T> clz,
Bundle args) {
mActivity = activity;
mTag = tag;
mClass = clz;
mArgs = args;
FragmentTransaction ft = mActivity.getSupportFragmentManager()
.beginTransaction();
// Check to see if we already have a fragment for this tab, probably
// from a previously saved state. If so, deactivate it, because our
// initial state is that a tab isn't shown.
mFragment = mActivity.getSupportFragmentManager()
.findFragmentByTag(mTag);
if (mFragment != null && !mFragment.isDetached()) {
ft.detach(mFragment);
}
}
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
ft = mActivity.getSupportFragmentManager()
.beginTransaction();
if (mFragment == null) {
mFragment = Fragment.instantiate(mActivity, mClass.getName(),
mArgs);
ft.add(android.R.id.content, mFragment, mTag);
ft.commit();
} else {
ft.attach(mFragment);
ft.commit();
}
}
#Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
ft = mActivity.getSupportFragmentManager()
.beginTransaction();
if (mFragment != null) {
ft.detach(mFragment);
ft.commitAllowingStateLoss();
}
}
#Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
}
}
I use Fragments for my Sherlock implementation.
public class ActionBarTabs extends FragmentActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActionBar bar = getSupportActionBar();
bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
bar.setDisplayOptions(0, ActionBar.DISPLAY_SHOW_TITLE);
bar.addTab(bar.newTab()
.setText("Home")
.setTabListener(new TabListener<DashBoardFragment>(
this, "home", DashBoardFragment.class, null)));
bar.addTab(bar.newTab()
.setText("Inventory")
.setTabListener(new TabListener<InventoryFragment>(
this, "inventory", InventoryFragment.class, null)));
if (savedInstanceState != null) {
bar.setSelectedNavigationItem(savedInstanceState.getInt("tab", 0));
}
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
// app icon in action bar clicked; go Location selection
Intent intent = new Intent(ActionBarTabs.this, LocationSelectorActivity.class);
ActionBarTabs.this.startActivityForResult(intent,0);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("tab", getSupportActionBar().getSelectedNavigationIndex());
}
public class TabListener<T extends Fragment> implements ActionBar.TabListener {
private final FragmentActivity mActivity;
private final String mTag;
private final Class<T> mClass;
private final Bundle mArgs;
private Fragment mFragment;
public TabListener(FragmentActivity activity, String tag, Class<T> clz, Bundle args) {
mActivity = activity;
mTag = tag;
mClass = clz;
mArgs = args;
FragmentTransaction ft = mActivity.getSupportFragmentManager().beginTransaction();
// Check to see if we already have a fragment for this tab, probably
// from a previously saved state. If so, deactivate it, because our
// initial state is that a tab isn't shown.
mFragment = mActivity.getSupportFragmentManager().findFragmentByTag(mTag);
if (mFragment != null && !mFragment.isDetached()) {
ft.detach(mFragment);
}
}
#Override
public void onTabSelected(Tab tab) {
FragmentTransaction ft = mActivity.getSupportFragmentManager().beginTransaction();
if (mFragment == null) {
mFragment = Fragment.instantiate(mActivity, mClass.getName(), mArgs);
ft.add(android.R.id.content, mFragment, mTag);
ft.commit();
} else {
ft.attach(mFragment);
ft.commit();
}
}
#Override
public void onTabUnselected(Tab tab) {
FragmentTransaction ft = mActivity.getSupportFragmentManager().beginTransaction();
if (mFragment != null) {
ft.detach(mFragment);
ft.commitAllowingStateLoss();
}
}
#Override
public void onTabReselected(Tab tab) {
}
}
}
The key change to load different fragments into the tabs is to simply change the "YOUR_FRAGMENT_NAME" to the name of your fragment class in these lines:
bar.addTab(bar.newTab()
.setText("Home")
.setTabListener(new TabListener<YOUR_FRAGMENT_NAME>(
this, "home", YOUR_FRAGMENT_NAME.class, null)));
Hope this helps!

Categories

Resources