I am fairly new to android programming but what I am trying to do seems fairly simple though. I have this setup with 4 different tabs in the action bar, the first should display a Fragment with the Google maps API and the others some other stuff i haven't done yet. Following some tutorials online I managed to get the functionality I wanted for the tabs and get the map to appear.
The app is working fine when changing from the initial tab with the map (tab 1) to any other, but when trying to come back it crashes. Weirdly enough when the map fragment is in one of the tabs it makes the second tab crash as well on some transitions, in the image bellow the transitions shown as blue arrows work fine, while the ones with yellow arrows make the app crash.
http://imageshack.com/a/img839/4796/kf7w.png
If I change the first tab fragment for one of the others all the transitions work fine again, therefore I think the problem must indeed be with the map fragment.
My code is as follows:
MainActivity.java
public class MainActivity extends FragmentActivity implements ActionBar.TabListener {
private ViewPager viewPager;
private TabsPagerAdapter mAdapter;
private ActionBar actionBar;
private String[] tabs = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewPager = (ViewPager) findViewById(R.id.pager);
actionBar = getActionBar();
mAdapter = new TabsPagerAdapter(getSupportFragmentManager());
viewPager.setAdapter(mAdapter);
actionBar.setHomeButtonEnabled(false);
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
tabs = getResources().getStringArray(R.array.tab_names);
for (String tab_name : tabs)
actionBar.addTab(actionBar.newTab().setText(tab_name).setTabListener(this));
/**
* on swiping the viewpager make respective tab selected
* */
viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageSelected(int position) {
// on changing the page
// make respected tab selected
actionBar.setSelectedNavigationItem(position);
}
#Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
}
#Override
public void onPageScrollStateChanged(int arg0) {
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
// TODO Auto-generated method stub
}
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
viewPager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
// TODO Auto-generated method stub
}
}
TabsPagerAdapter.java
public class TabsPagerAdapter extends FragmentPagerAdapter {
public TabsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int index) {
switch (index){
case 0:
return new GoogleMapsFragment();
case 1:
return new SampleFragment();
case 2:
return new ContactFragment();
case 3:
return new WhoFragment();
default:
Log.e("switch", "default");
}
return null;
}
#Override
public int getCount() {
// get item count - equal to number of tabs
return 4;
}
}
GoogleMapsFragment.java
public class GoogleMapsFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.activity_map, container, false);
return rootView;
}
#Override
public void onDestroyView() {
super.onDestroyView();
Fragment f = (Fragment) getFragmentManager().findFragmentById(R.id.map);
if (f != null) {
getFragmentManager().beginTransaction().remove(f).commit();
}
}
}
And the xml files:
activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context=".MainActivity"
android:background="#ffff0000"
android:id="#+id/mainLayout"
android:tag="#+id/mainLayoutTag" >
<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:tag="pagerTag">
</android.support.v4.view.ViewPager>
</RelativeLayout>
activity_map.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:orientation="vertical"
android:id="#+id/mapLayout"
android:tag="mapLayoutTag" >
<fragment android:id="#+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:name="com.google.android.gms.maps.MapFragment"
android:tag="gMaps"/>
</RelativeLayout>
The other java classes are pretty much empty and the other xml files only contain the default RelativeLayout.
Any suggestion as to what I could do to fix this?
Thanks for your time reading all of that :)
EDIT:
Forgot to put the crash error:
02-10 23:42:01.723: E/AndroidRuntime(7221): Caused by:
java.lang.IllegalArgumentException: Binary XML file line #9:
Duplicate id 0x7f05000a, tag gMaps, or parent id 0x7f050009 with another
fragment for com.google.android.gms.maps.MapFragment
Well managed to solve this only by switching the position of the super call in the onDestroy() function. It seems I needed to first destroy or unassign the fragment from its parent to make it work. Heres the new onDestroy() code if anyone is still having the same problem:
#Override
public void onDestroyView() {
userMarker.remove();
Fragment f = (Fragment) getFragmentManager().findFragmentById(R.id.map);
if (f != null) {
getFragmentManager().beginTransaction().remove(f).commit();
}
super.onDestroyView();
}
After loads of search, finally I found this tutorial : Using an Android MapView inside of a Fragment
and it works awesome !!! hopefully it helps your guys !
Related
I've tried to implement PagerSlidingTabStrip to my app but it just isn't working. I did everything that is done in the sample but it isn't working. The tab indicator just isn't moving as it is supposed to and the app isn't crashing. Basically nothing is happening. I have no idea what is wrong.
MainActivity code
public class MainActivity extends FragmentActivity implements TabListener {
ActionBar aBar;
ViewPager vPager;
PagerAdapter pAdapter;
PagerSlidingTabStrip slidingTabStrip;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Action Bar
aBar = getActionBar();
aBar.setTitle("Beautiful Voice Recorder");
aBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
// Variables
slidingTabStrip = (PagerSlidingTabStrip) findViewById(R.id.slidingTabs);
vPager = (ViewPager) findViewById(R.id.pager);
pAdapter = new PagerAdapter(getSupportFragmentManager());
// Tabs
vPager.setAdapter(pAdapter);
slidingTabStrip.setViewPager(vPager);
aBar.addTab(aBar.newTab().setText("Record").setTabListener(this));
aBar.addTab(aBar.newTab().setText("Library").setTabListener(this));
vPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageSelected(int position) {
LibraryFragment listViewFragment = (LibraryFragment)pAdapter.instantiateItem(vPager, 1);
RecordFragment recordFragment = (RecordFragment)pAdapter.instantiateItem(vPager, 0);
listViewFragment.updateComponents();
// Pause mp if it's playing and tabs are switched just in case
if (listViewFragment.mp.isPlaying())
{
listViewFragment.mp.pause();
listViewFragment.playPause.setBackgroundResource(R.drawable.play_button_selector);
}
if (recordFragment.isRecording)
{
recordFragment.stopRecording();
}
aBar.setSelectedNavigationItem(position);
}
#Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
}
#Override
public void onPageScrollStateChanged(int arg0) {
}
});
}
#Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
}
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
vPager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
}
}
class PagerAdapter extends FragmentPagerAdapter{
String[] pageTitles = { "Record", "Library" };
public PagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int arg0) {
Fragment fragment = new Fragment();
if (arg0 == 0)
{
fragment = new RecordFragment();
}
if (arg0 == 1)
{
fragment = new LibraryFragment();
}
return fragment;
}
#Override
public int getCount() {
return pageTitles.length;
}
#Override
public CharSequence getPageTitle(int position) {
return pageTitles[position];
}
}
XML
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<com.astuetz.PagerSlidingTabStrip
android:id="#+id/slidingTabs"
android:layout_width="match_parent"
android:layout_height="48dip" />
<android.support.v4.view.ViewPager
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
Does anyone have any idea why my code is not working?
I think you didn't locate ViewPager even if it's RelativeLayout.
so try this code that i'm using. I hope it will be helpful for you.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.astuetz.PagerSlidingTabStrip
android:id="#+id/tabs"
android:layout_width="match_parent"
android:layout_height="48dip"
/>
<com.flitto.app.widgets.MainViewPager
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#+id/tabs"
tools:context=".MainTabActivity"/>
</RelativeLayout>
I found where the problem was lying after I took a deeper look at the sample code. The problem was the fact that I still had the previous ActionBar tabs left in the code and those were overlapping the PagerSlidingTabStrip tabs so that I didn't see them.
All I had to do was to remove every reference to ActionBar tabs and it worked!
I can't seem to update the ui in one of my fragments, I'm not sure why. I have a main activity which should send some json to the fragment and update the UI with the data from the JSON object. I'm sending the json over successfully and I can log the data in the Fragment which I have sent over. I am just not able to update the textbox value in the UI.
In my mainactivity
MainPageFragment myFragment = new MainPageFragment();
SectionsPagerAdapter mSectionsPagerAdapter;
ViewPager mViewPager;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//Create adapter that will return a fragment for each section of app
mSectionsPagerAdapter = new SectionsPagerAdapter(getFragmentManager());
mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setAdapter(mSectionsPagerAdapter);
}
#Override
public void onSuccess(JSONObject user) {
//This seems to be all I need
myFragment.grabJSON(user);
}
public class SectionsPagerAdapter extends FragmentPagerAdapter {
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public int getCount() {
return 2;
}
#Override
public CharSequence getPageTitle (int position) {
return titles[position];
}
#Override
public Fragment getItem(int position) {
if (position == 1) {
return new PreferenceFragment() {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.layout.settings_preferances);
}
};
}
else {
return myFragment;
}
}
}
In my MainFragment.java
public void grabJSON(JSONObject object){
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
TextView usernameTextView = (TextView) getView().findViewById(R.id.usernameview);
CharSequence val = usernameTextView.getText();
Log.d("value", val.toString());
usernameTextView.setText("NEW TEXT");//Set the Text
val = usernameTextView.getText();
Log.d("value", val.toString());
}
});
}
The fact that it sends the json is irrelevant, according to the log, my value of the textbox is changing but the actual UI is not changing.
I'm adding here the xml for the mainactivity
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.view.ViewPager
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" >
<android.support.v4.view.PagerTabStrip
android:id="#+id/pager_header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:textColor="#fff"/>
<FrameLayout
android:id="#+id/fragment_placeholder"
android:layout_width="fill_parent"
android:layout_height="fill_parent" ></FrameLayout>
</android.support.v4.view.ViewPager>
This has been updated with correct code, turns out I was defining the fragment twice
Thank you all,
Tom
Your fragment is getting added twice.
It's added via the layout XML file, and then you do a fragment transaction to add it aw well. Adding fragments via layout doesn't work as well as it should, so you should put in a placeholder view and then add the fragment via the fragment manager. That should clear everything up.
I'm guessing you dont add the fragment in the activity?
FragmentManager fragmentManager = getFragmentManager()
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
MainPageFragment fragment = new MainPageFragment ();
fragmentTransaction.add(R.id.fragment_container, fragment);
fragmentTransaction.commit();
So recently I needed to implement action bar tabs that would swap out the current fragment with a new fragment. Despite hours of intensive searching I was unable to find a clear solution, so I thought I would present how I solved the problem here. Two of the fragments contained list views, which turned out to be a major complicating factor.
First create an Activity to which you want to attach the fragments. In the XML file for that Activity add a linear layout like so:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".WoodenSideProject" >
<LinearLayout
android:id="#+id/fragment_placeholder"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
</LinearLayout>
Do not add anything else to the XML file. Not even the tab host that is preloaded with Eclipse.
Next create your fragments. First build the UI for your fragment how you want it using the fragment's XML file. I will show how to create a fragment with a List View:
public class Fragment1Name extends Fragment
{
public static String TAG="DirectionsFragment";
private String[] list_items = {"Put the list of Strings you want here"};
ListView lView1;
/*#Override
public void onActivityCreated(Bundle savedInstanceState)
{
super.onActivityCreated(savedInstanceState);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(getActivity(),
android.R.layout.simple_list_item_1, list_items);
setListAdapter(adapter);
}*/
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_XML_title, container, false);
createListView(view);
// Inflate the layout for this fragment
return view;
}
private void createListView(View view)
{
lView1 = (ListView) view.findViewById(R.id.ListViewID);
//Set option as Multiple Choice. So that user can able to select more the one option from list
lView1.setAdapter(new ArrayAdapter<String>(getActivity(),
android.R.layout.simple_list_item_1, list_items));
}
}
Some people suggest extending ListFragment for a fragment that uses a List View. My experience has been that is more trouble than it's worth.
Set up the Activity's java file as follows:
public class ActivityName extends FragmentActivity {
public static Context appContext;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_project);
ActionBar actionBar = getActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
setTitle("WoodenSideProject");
ActionBar.Tab tab1 = actionBar.newTab().setText("Tab1");
ActionBar.Tab tab2 = actionBar.newTab().setText("Tab2");
ActionBar.Tab tab3 = actionBar.newTab().setText("Tab3");
Fragment Fragment1Name = new Fragment1Name();
Fragment Fragment2Name = new Fragment2Name();
Fragment Fragment3Name = new Fragment3Name();
tab1.setTabListener(new MyTabsListener(Fragment1Name));
tab2.setTabListener(new MyTabsListener(Fragment2Name));
tab3.setTabListener(new MyTabsListener(Fragment3Name));
actionBar.addTab(tab1);
actionBar.addTab(tab2);
actionBar.addTab(tab3);
}
Within the same Activity create the following class:
class MyTabsListener implements ActionBar.TabListener {
public Fragment fragment;
public MyTabsListener(Fragment fragment) {
this.fragment = fragment;
}
#Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
//do what you want when tab is reselected, I do nothing
}
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
ft.replace(R.id.fragment_placeholder, fragment);
}
#Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
ft.remove(fragment);
}
}
I don't know if others have had as much trouble as I implementing action bar tabs with fragments, but if they are I hope this helps. Any suggestions for better implementations would be greatly appreciated.
Basically
I have two layouts activity_main_layout.xml as well as layout2.xml
I have created two tabs on the ActionBar using the getActionbar().newTab() method
I have a Button and a text box (EditText) in activity_main_layout.xml (first tab)
Both the button and the text box have a dynamically entered text: "Test 123"
When Tab 2 is selected, I have a statement of code that says: setContentView(R.layout.layout2) so that it shows the second layout and similarly for Tab 1: setContentView(R.layout.activity_main)
When Tab 1 is reselected, the dynamically entered text "Test 123" is gone and I am left with the text that was set in design time in the XML. So I am currently forced the save the contents of the Buttons and EditTexts before a tab is selected and restore them after it was selected.
I don't think this is the right way to do it. I am already utilizing onSaveInstanceState() and onRestoreInstanceState() with savedInstanceState.putXX and getXX etc to save the contents when the screen rotates but it doesn't seem to work with the current issue. I have been unable to find an answer so far. Does anyone have any clues please? Any responses will be appreciated.
If you have only 2 tabs, why don't you use a pageadapter? You won't lose any information until you change the position of the mobile or quit the app.
Basically is something like that (I put you a scracth of one of my codes).
NOTE: I use packet ShelockActivity to have tabsmenu for android > 2.0
MAINCLASS:
public class MainClass extends SherlockActivity implements ActionBar.TabListener {
ViewPager myPager;
AdapterClass adapter;
Context con = null;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
con = this.getBaseContext();
//Restore info in case flip mobile
final Myobject data = (Myobject) getLastNonConfigurationInstance();
Bundle extras = getIntent().getExtras();
//Tab bar
getSupportActionBar().setDisplayShowHomeEnabled(false);
getSupportActionBar().setDisplayShowTitleEnabled(false);
getSupportActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
//loop for add more
ActionBar.Tab tab = getSupportActionBar().newTab();
tab.setText("text tab");
if (data != null) {
getdatatoyourobject(data);
}
myPager = (ViewPager) findViewById(R.id.panelpager);
myPager.setAdapter(adapter);
myPager.setOnPageChangeListener(new OnPageChangeListener() {
#Override
public void onPageSelected(int index) {
getSupportActionBar().setSelectedNavigationItem(index);
}
adapter = new AdapterClass(Parameters for your adapterclass);
#Override
public void onPageScrollStateChanged(int arg0) {
// TODO Auto-generated method stub
}
#Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
// TODO Auto-generated method stub
}
});
}
}
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
// TODO Auto-generated method stub
myPager.setCurrentItem(tab.getPosition(),true);
}
#Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
// TODO Auto-generated method stub
}
#Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
// TODO Auto-generated method stub
}
#Override
public Object onRetainNonConfigurationInstance() {
final Myobject a = new Myobject();
return a;
}
public class Myobject {
Type variable = adapter.variable; //do for all variables to restore
}
public void getdatatoyourobject(Myobject a){
adapter.variable = a.variable; //do for all variables to restore
}
}
ADAPTERCLASS:
public class Adapterclass extends PagerAdapter {
public int getCount() {
return 2; //NUMBER OF PAGES
}
public Adapterclass () {
}
public View view = null; //create rest of variables to restore as public
public Object instantiateItem(View collection, int position) {
LayoutInflater inflater = (LayoutInflater) collection.getContext()
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
switch (position) {
case 0:
view = inflater.inflate(R.layout.page1, null);
//bla bla bla
break;
//do more cases (pages)
}
((ViewPager) collection).addView(view, 0);
return view;
}
#Override
public void destroyItem(View arg0, int arg1, Object arg2) {
((ViewPager) arg0).removeView((View) arg2);
}
#Override
public boolean isViewFromObject(View arg0, Object arg1) {
return arg0 == ((View) arg1);
}
#Override
public Parcelable saveState() {
return null;
}
}
MAIN.XML:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<android.support.v4.view.ViewPager
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/panelpager"/>
here is the code I have:
activity_main.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" >
<Button
android:id="#+id/btn_One"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:layout_weight="1.70"
android:text="Activity_main.xml - Design Time Text"
android:textSize="12sp"
android:onClick="btnOne_OnClick"
android:textStyle="normal" />
layout2.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" >
<Button
android:id="#+id/btn_Two"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Layout2.xml - Design Time Text"
android:textSize="12sp"
android:textStyle="normal" />
In the main code, pay attention to the comments please:
public class MainActivity extends Activity implements ActionBar.TabListener {
ActionBar.Tab Tab_1 = null, Tab_2 = null;
Button btn_One = null, btnTwo = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
///////////////////////////////////////////////////////////////////
ActionBar actionbar = (ActionBar) getActionBar();
actionbar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
Tab_1 = actionbar.newTab().setText("Tab 1");
Tab_2 = actionbar.newTab().setText("Tab 2");
Tab_1.setTag(1);
Tab_2.setTag(2);
Tab_1.setTabListener(this);
Tab_2.setTabListener(this);
actionbar.addTab(Tab_1);
actionbar.addTab(Tab_2);
///////////////////////////////////////////////////////////////////
btn_One = (Button)this.findViewById(R.id.btn_One);
}
public void btnOne_OnClick(View v) {
((Button)v).setText("Clicked");
btn_One = ((Button)v);
}
#Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {}
// Here is what the problem is:
// After you click btn_one, the text changes to "Clicked" - good! - however
// after Tab 1 gets reselected, the text off btn_One (btn_One) gets reset back to the one
// set in design time: "Activity_main.xml - Design Time Text", so the "Clicked" text disappears
// The interesting thing is, when you rotate the screen, the text gets re-initialized to "Clicked" and that's
// because of onRestoreInstanceState(). So it looks like when a tab gets reselected, the design time screen
// gets re-drawn and onRestoreInstanceState doesn't get recalled.
// My "workaround" for the above issue would be to create a global
// "Bundle" poiner and pass the address of the one from onSaveInstanceState(Bundle savedInstanceState)
// to the global Bundle pointer and then call onRestoreInstanceState(*the_global_bundle_pointer*)
// when a tab gets reselected so that it restores the state.
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
int selectedTab = (Integer) tab.getTag();
if (selectedTab == 1) this.setContentView(R.layout.activity_main);
if (selectedTab == 2) this.setContentView(R.layout.layout2);
}
#Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {}
#Override
public void onSaveInstanceState(Bundle savedInstanceState)
{
if (btn_One != null) savedInstanceState.putString("btn_One", btn_One.getText().toString());
super.onSaveInstanceState(savedInstanceState);
}
// When the instance is restored, reload all data
#Override
public void onRestoreInstanceState(Bundle savedInstanceState)
{
super.onRestoreInstanceState(savedInstanceState);
if (btn_One != null) btn_One.setText(savedInstanceState.getString("btn_One").toString());
}
}
Also, the reason I say two tabs is so that I can demonstrate the problem in its simplest way possible so people can understand what I am trying to solve. My real project uses more then two tabs.
My "workaround" for the above issue would be to create a global "Bundle" poiner and pass the address of the one from onSaveInstanceState(Bundle savedInstanceState) to the global Bundle pointer and then call onRestoreInstanceState(*the_global_bundle_pointer*) when a tab gets reselected so that it restores the state.
What do you think?
Apart from as 'Learning from masters' states, there are better ways to build this structure up (page adapter / page viewer / fragments...) it should still work fine using your Bundle saveInstanceState correctly.
Can you post your code?
edit after seeing code:
You probably need to check your Bundle savedInstanceState in onCreate() instead.
This looks a bit like
#Override
public void onCreate(Bundle savedInstanceState) {
[...]
if(savedInstanceState != null){
//restore your stuff from the Bundle
}else{
// there is nothing to restore, so (down)load your data.
}
}
A good detailed explanation you can find around https://stackoverflow.com/a/6722854/1868384
Thank you both. It turns out with Android, once a new content layout is set to an Activity, the existing UI elements such as a text box, button of the previous layout etc are no longer available so trying to access them will cause an access violation. Once you set a content layout, it looks like the UI elements are rebuilt from scratch hence for losing all of the data. Well this is what I personally noticed and it certainly seems to be a default behavior. I don't know if this behavior can be changed.
I made my own "custom solution". All I did is create a new class, with a bunch of data members in it. Each time I set a new content to an Activity such as when I apply a layout when a tab is clicked or the device is rotated (onSaveInstance), I save/restore values from this class. I used to use the Bundle putInt, putString, putParcelable etc but I decided to take a different route. With my way, I am in-control and I know exactly what is going on with the code.
I am trying to create a scrollable tabs using fragment.
Tabs are showing and scrolling also. But the problem is the tab content is not showing.
I am using fragments to show the contents. I am new in this topic : fragment. Am I missing anything in this code?
Please help me.
public class SrollableTab extends Activity
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
ActionBar bar = getActionBar();
bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
bar.setDisplayOptions(0, ActionBar.DISPLAY_SHOW_TITLE);
bar.addTab(createTab("Tab 1"));
bar.addTab(createTab("Tab 2"));
bar.addTab(createTab("Tab 3"));
bar.addTab(createTab("Tab 4"));
bar.addTab(createTab("Tab 5"));
bar.addTab(createTab("Tab 6"));
if (savedInstanceState != null) {
bar.setSelectedNavigationItem(savedInstanceState.getInt("tab", 0));
}
}
public Tab createTab(String tabTitle)
{
ActionBar bar = getActionBar();
Tab tab = bar.newTab().setText(tabTitle).setTabListener(new TabFragment());
return tab;
}
class TabFragment extends Fragment implements TabListener
{
#Override
public void onCreate(Bundle fragmentState)
{
super.onCreate(fragmentState);
}
#Override
public View onCreateView(LayoutInflater inflator, ViewGroup container, Bundle savedState)
{
View view = inflator.inflate(R.layout.tab_content, container, false);
TextView t = (TextView)view.findViewById(R.id.txtTab);
t.setText("tab content");
return view;
}
#Override
public void onActivityCreated(Bundle savedState)
{
super.onActivityCreated(savedState);
}
#Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
}
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
}
#Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
}
}
}
tab_content.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:orientation="vertical"
android:background="#ffffff" >
<TextView android:id="#+id/txtTab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="hello"
android:textColor="#ff0000"/>
</LinearLayout>
This may be old but found my own solution on this.
I've use PagerSlidingTabStrip for a while now until I start using the new material TabLayout. Both works on Activity, but not on Fragments. This are some discussion about the bug on fragments.
The fix I've come up with is, on settings viewpager's adater (usually extended with FragmentPagerAdapter) on its constructor parameter it needs FragmentManager, instead of using the activity's FragmentManager use the fragment's one instead which is getChildFragmentManager().
That fix it. Android bugs still annoys me though.
Cheers