I have the following problem.
I am implementing a sliding menu from jfeinstein10 and for each menu option, I give a call to a different fragment class. In my menu options, I have a choice called profile in which when clicked, I want a new fragment with preferences to be displayed. Normally, I can do this by using PreferenceFragment, but that does not work with the sliding menu as it expects a class of type Fragment.
Here is my COde on Item click.
#Override
public void onListItemClick(ListView lv, View v, int position, long id) {
Fragment newContent = null;
Class<?> cls = null;
switch (position) {
case 0: /*this is the one that I want to edit*/
newContent = new profileFragment();
break;
}
if (newContent != null)
switchFragment(newContent);
}
How can I show the preferences in a Fragment?
Normally I would do this:
public class profileFragment extends PreferenceFragment{
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
}
}
But that doesnt work as it extends PreferenceFragment and not Fragment
Any ideas?
Related
I understand that this is quite a common issue, and I have referred to many different other questions but I still can't get this to work.
My activity implements a view pager with two tabs and in each tab is a listview. I have a adapter for my view pager which links the two fragments and in each fragment, a adapter to link the data to the listview.
In my activity menu, I have a menu which creates an edittext in an alertdialog for me to input new fields into one of the listview in one of the fragment.
My activity (contains a viewpager)
protected void onCreate(Bundle savedInstanceState)
{
...
subAdapter = new SubAdapter(getSupportFragmentManager(), data);
((ViewPager) findViewById(R.id.viewPager)).setAdapter(subGroupAdapter);
}
My viewpager adapter
public class SubAdapter extends FragmentPagerAdapter
{
public SubGroupAdapter(FragmentManager fm, data data)
{
super(fm);
}
#Override
public Fragment getItem(int position)
{
Bundle bundle = new Bundle();
bundle.putString("data", data);
switch (position)
{
case 0:
Fragment1 frag1 = new Fragment1();
frag1.setArguments(bundle);
return frag1;
case 1:
Fragment2 frag2 = new Fragment2();
frag2.setArguments(bundle);
return frag2;
}
return null;
}//some other methods below
Fragment1 / Fragment2 (both fragments have a listview)
public void onActivityCreated(Bundle savedInstanceState)
{
super.onActivityCreated(savedInstanceState);
frag1Adapter = new frag1Adapter(this, data);
((ListView) getView().findViewById(R.id.listView)).setAdapter(frag1Adapter);
}
Custom listview adapter for both listviews in both fragments
public class ExpenseAdapter extends BaseAdapter implements OnClickListener
{ ... }
As I mentioned earlier, I can input a new entry into either listview from the activity action bar button. However, the listview does not get updated and I can't reference the listview adapter to call notifydatasetchanged() from the activity.
What is the best way I can proceed from here onwards? thank you so much!
I have tried exploring using interfaces, tags but can't get it to work currently.
What you should do is create a public method for your Fragment1 and Fragment2 like so:
define in your Activity:
Fragment1 frag1;
Fragment2 frag2;
then your ViewPager:
public class SubAdapter extends FragmentPagerAdapter
{
public SubGroupAdapter(FragmentManager fm, data data)
{
super(fm);
}
#Override
public Fragment getItem(int position)
{
Bundle bundle = new Bundle();
bundle.putString("data", data);
switch (position)
{
case 0:
frag1 = new Fragment1();
frag1.setArguments(bundle);
return frag1;
case 1:
frag2 = new Fragment2();
frag2.setArguments(bundle);
return frag2;
}
return null;
}
}
Put this method in Fragment1.java :
public void updateFragment1ListView(){
if(adapter != null){
adapter.notifyDataSetChanged();
}
}
and from your activity call:
if(frag1 != null){
frag1.updateFragment1ListView();
}
obviously change the names for your adapter if its not called adapter...
Just do the same for Fragment2.java as well
I would recommend creating an interface. Here's an Example:
public interface UpdateListFragmentInterface {
void updateList();
}
Then in the Activity, add the delegate as a property:
UpdateListFragmentInterface yourDelegate;
Wherever you create the Fragment within the Activity, assign the Fragment as the delegate:
// Set up and create your fragment.
(if yourFragment instanceof UpdateListFragmentInterface) {
yourDelegate = yourFragment;
}
Then in the Fragment, implement the interface:
public class YourListFragment extends android.support.v4.app.ListFragment implements UpdateListFragmentInterface {
// Constructors and other methods for the ListFragment up here.
// Override the interface method
public void updateList() {
//Update the list here.
}
}
Then finally, from within your Activity, when you need to update the list, simply call the delegate:
yourDelegate.updateList();
EDIT:
Sorry, I think you actually need to create a public method in your activity that is something like:
public void setUpdateListFragmentDelegate(UpdateListFragmentDelegate delegate) {
this.delegate = delegate
}
Then in the on attach of the List Fragment you will assign it there:
if (context instance of YourActivity) {
((YourActivity)context.setUpdateListFragmentDelegate(this);
}
I have a drawer activity and a method that calls several fragments, when I select an option shows me a listview with buttons. Clicking a button sends me to a new activity that has a back button. I want to return to the previous screen, return to the option you select in the drawer activity.
public class DrawerOpcionesActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.drawer_menu);
....
drawerList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
mostrarFragment(position);
adapterOpciones.setPositionCheked(position);
}
});
if(savedInstanceState == null){
mostrarFragment(0);
}
...
}
private void mostrarFragment(int position){
Fragment fragment = null;
System.out.println("opcion: " + position);
switch (position) {
case 1:
fragment = new LineasTransporteFragment();
break;
....
}
In the other activity...
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.xxxxx);
actionBar = getActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
... //new Intent.. I dont Know who call the save option from activity drawerOptions
return true;
default:
return super.onOptionsItemSelected(item);
}
}
I need to save the selected option, when I call a new Intent show me the selected option. I show the fragment of default position 0
You may use SharedPrefrence of android to save the state and access back the state. Please have a look for sharedPrefrence
I have two fragments SearchFragment and CreateFragment in a view pager inside a activity called TicketManagementActivity. Now when the user presses the search button in SearchFragment, I want SearchFragment to be replaced with SearchResultFragment. I should then be able to swipe between SeachResultFragment and CreateFragment in the ViewPager. Also when I press back from SearchResultFragment I should go back to SearchFragment.
Right now, when I press the button I get a blank screen instead of the layout of SearchResultFragment. When I press back I get to SearchFragment but now I have to click the button twice for the blank screen to come. Now after the blank screen comes after the double click, whenever I swipe to CreateFragment tab I get a blank screen instead of CreateFragment layout.
I looked at quite a number of questions on SO but none of them seem to be working for me. Most useful seems to be the first two answers in this question, but the first answer doesn't handle the back press, nor am I able to implement it. The second answer seems very implementable but I get errors which I have mentioned below.
My main TicketManagemementActivity:
public class TicketManagementActivity extends FragmentActivity implements
ActionBar.TabListener {
ViewPager viewPager;
TabsPagerAdapter adapter;
ActionBar actionBar;
String[] tabs={"Search", "Create"};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_ticket_management);
viewPager=(ViewPager)findViewById(R.id.pager);
actionBar=getActionBar();
adapter=new TabsPagerAdapter(getSupportFragmentManager());
viewPager.setAdapter(adapter);
actionBar.setHomeButtonEnabled(false);
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
for(String tab_name : tabs){
actionBar.addTab(actionBar.newTab().setText(tab_name).setTabListener(this));
}
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) {
}
});
}
//removed methods for menu creation and filling and placeholder fragment for brevity on SO
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
viewPager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
}
#Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
}
}
My activity_ticket_management.xml which is layout set in onCreate of ticket management activity, just contains the viewpager
<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.support.v4.view.ViewPager>
My TabsPagerAdapter class extending FragmentPagerAdapter:
public class TabsPagerAdapter extends FragmentPagerAdapter {
public TabsPagerAdapter(android.support.v4.app.FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int index) {
switch (index) {
case 0:
// Top Rated fragment activity
return new SearchFragment();
case 1:
// Games fragment activity
return new CreateFragment();
}
return null;
}
#Override
public int getCount() {
// get item count - equal to number of tabs
return 2;
}
}
Relevant part of my SearchFragment:
public class SearchFragment extends Fragment implements View.OnClickListener {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_search, container, false);
.
.//some widget initializations
.
return rootView;
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.ticket_search_btn: searchSigmaTickets();
break;
}
}
public void searchSigmaTickets(){
.
.
.
.//some operations
.
new SearchAsyncTask().execute();
}
}
private class SearchAsyncTask extends AsyncTask<Void, Void, Void>{
protected Void doInBackground(Void... params){
.
.//some more operation
.
}
protected void onPostExecute(Void param){
Fragment newFragment = new SearchResultFragment();
//Here I use getFragmentManager and not getChildFragmentManager
FragmentTransaction transaction = getFragmentManager().beginTransaction();
//HERE I try to replace the fragment. I'm not sure what id to pass, I pass the id of the main veiwpager in ticketmanagement activity
transaction.replace(R.id.pager, newFragment);
transaction.addToBackStack(null);
transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
transaction.commit();
}
}
}
If I use getChildFragmentManager instead of getFragmentManager as mentioned in the second answer I get
06-25 06:55:32.045: E/AndroidRuntime(2797): java.lang.IllegalArgumentException: No view found for id 0x7f06003c (com.amberroad.sigmaticket:id/pager) for fragment SearchResultFragment{b2fed358 #0 id=0x7f06003c}
Sorry for the lengthy question, how should I solve this?
Kartik, get ready for a lengthy answer to your lenghty question. Replacing fragments in a viewpager is quite involved but is very possible and can look super slick. First, you need to let the viewpager itself handle the removing and adding of the fragments. What is happening is when you replace the fragment inside of SearchFragment, your viewpager retains its fragment views. So you end up with a blank page because the SearchFragment gets removed when you try to replace it.
The solution is to create a listener inside of your viewpager that will handle changes made outside of it so first add this code to the bottom of your adapter.
public interface nextFragmentListener {
public void fragment0Changed(String newFragmentIdentification);
}
Then you need to create a private class in your viewpager that becomes a listener for when you want to change your fragment. For example you could add something like this. Notice that it implements the interface that was just created. So whenever you call this method, it will run the code inside of the class below.
private final class fragmentChangeListener implements nextFragmentListener {
#Override
public void fragment0Changed(String fragment) {
//I will explain the purpose of fragment0 in a moment
fragment0 = fragment;
manager.beginTransaction().remove(fragAt0).commit();
switch (fragment){
case "searchFragment":
fragAt0 = SearchFragment.newInstance(listener);
break;
case "searchResultFragment":
fragAt0 = Fragment_Table.newInstance(listener);
break;
}
notifyDataSetChanged();
}
There are two main things to point out here: 1)fragAt0 is a "flexible" fragment. It can take on whatever fragment type you give it. This allows it to become your best friend in changing the fragment at position 0 to the fragment you desire. 2) Notice the listeners that are placed in the 'newInstance(listener)constructor. These are how you will callfragment0Changed(String newFragmentIdentification)`. The following code shows how you create the listener inside of your fragment.
static nextFragmentListener listenerSearch;
public static Fragment_Journals newInstance(nextFragmentListener listener){
listenerSearch = listener;
return new Fragment_Journals();
}
You could then call the change inside of your onPostExecute
private class SearchAsyncTask extends AsyncTask<Void, Void, Void>{
protected Void doInBackground(Void... params){
.
.//some more operation
.
}
protected void onPostExecute(Void param){
listenerSearch.fragment0Changed("searchResultFragment");
}
}
This would trigger the code inside of your viewpager to switch your fragment at position zero fragAt0 to become a new searchResultFragment. There are two more small pieces you would need to add to the viewpager before it became functional.
One would be in the getItem override method of the viewpager.
#Override
public Fragment getItem(int index) {
switch (index) {
case 0:
//this is where it will "remember" which fragment you have just selected. the key is to set a static String fragment at the top of your page that will hold the position that you had just selected.
if(fragAt0 == null){
switch(fragment0){
case "searchFragment":
fragAt0 = FragmentSearch.newInstance(listener);
break;
case "searchResultsFragment":
fragAt0 = FragmentSearchResults.newInstance(listener);
break;
}
}
return fragAt0;
case 1:
// Games fragment activity
return new CreateFragment();
}
Now without this final piece you would still get a blank page. Kind of lame, but it is an essential part of the viewPager. You must override the getItemPosition method of the viewpager. Ordinarily this method will return POSITION_UNCHANGED which tells the viewpager to keep everything the same and so getItem will never get called to place the new fragment on the page. Here's an example of something you could do
public int getItemPosition(Object object)
{
//object is the current fragment displayed at position 0.
if(object instanceof SearchFragment && fragAt0 instanceof SearchResultFragment){
return POSITION_NONE;
//this condition is for when you press back
}else if{(object instanceof SearchResultFragment && fragAt0 instanceof SearchFragment){
return POSITION_NONE;
}
return POSITION_UNCHANGED
}
Like I said, the code gets very involved, but you basically have to create a custom adapter for your situation. The things I mentioned will make it possible to change the fragment. It will likely take a long time to soak everything in so I would be patient, but it will all make sense. It is totally worth taking the time because it can make a really slick looking application.
Here's the nugget for handling the back button. You put this inside your MainActivity
public void onBackPressed() {
if(mViewPager.getCurrentItem() == 0) {
if(pagerAdapter.getItem(0) instanceof FragmentSearchResults){
((FragmentSearchResults) pagerAdapter.getItem(0)).backPressed();
}else if (pagerAdapter.getItem(0) instanceof FragmentSearch) {
finish();
}
}
}
You will need to create a method called backPressed() inside of FragmentSearchResults that calls fragment0changed. This in tandem with the code I showed before will handle pressing the back button. Good luck with your code to change the viewpager. It takes a lot of work, and as far as I have found, there aren't any quick adaptations. Like I said, you are basically creating a custom viewpager adapter, and letting it handle all of the necessary changes using listeners
Here is the code all together for the TabsPagerAdapter.
public class TabsPagerAdapter extends FragmentPagerAdapter{
Fragment fragAt0;
fragmentChangeListener listener = new fragmentChangeListener();
FragmentManager manager;
static String fragment0 = "SearchFragment";
//when you declare the viewpager in your adapter, pass it the fragment manager.
public viewPager(FragmentManager fm) {
super(fm);
manager = fm;
}
private final class fragmentChangeListener implements nextFragmentListener {
#Override
public void fragment0Changed(String fragment) {
//I will explain the purpose of fragment0 in a moment
fragment0 = fragment;
manager.beginTransaction().remove(fragAt0).commit();
switch (fragment){
case "searchFragment":
fragAt0 = SearchFragment.newInstance(listener);
break;
case "searchResultFragment":
fragAt0 = Fragment_Table.newInstance(listener);
break;
}
notifyDataSetChanged();
}
}
#Override
public Fragment getItem(int index) {
switch (index) {
case 0:
//this is where it will "remember" which fragment you have just selected. the key is to set a static String fragment at the top of your page that will hold the position that you had just selected.
if(fragAt0 == null){
switch(fragment0){
case "searchFragment":
fragAt0 = FragmentSearch.newInstance(listener);
break;
case "searchResultsFragment":
fragAt0 = FragmentSearchResults.newInstance(listener);
break;
}
}
return fragAt0;
case 1:
// Games fragment activity
return new CreateFragment();
}
#Override
public int getCount() {
// Show 3 total pages.
return 3;
}
#Override
public CharSequence getPageTitle(int position) {
Locale l = Locale.getDefault();
String[] tab = {"Journals", "Charts", "Website"};
switch (position) {
case 0:
return tab[0].toUpperCase(l);
case 1:
return tab[1].toUpperCase(l);
case 2:
return tab[2].toUpperCase(l);
}
return null;
}
public int getItemPosition(Object object)
{
//object is the current fragment displayed at position 0.
if(object instanceof SearchFragment && fragAt0 instanceof SearchResultFragment){
return POSITION_NONE;
//this condition is for when you press back
}else if{(object instanceof SearchResultFragment && fragAt0 instanceof SearchFragment){
return POSITION_NONE;
}
return POSITION_UNCHANGED
}
public interface nextFragmentListener {
public void fragment0Changed(String fragment);
}
I have my main activity actionbaractivity One where you can screenslide through some fragmets, on each fragment you have an imageView and a ListView where you can click any item and the image will change. Also in the menu options you have a button where you change to an almost exact activity: actiobbaractivity Two which also have this button to change to activity One
What I'm able to do is to keep the image when sliding the fragments, but unable to keep the fragments state's through the change of activities.
For example
I'm in activity One on fragment 3 with the image: "something". I click on the button to change to activity Two, I do things here and then, I click on the button to change to activity One and I want to see my fragment 3 with the image: "something" and not the default fragment 1 and default image
Im using ActionBarActivity, FragmentStatePagerAdapter and Fragment for each activity
Thanks for the help
According to the Activity and Fragment lifecycles (http://developer.android.com/reference/android/app/Activity.html#ActivityLifecycle and http://developer.android.com/guide/components/fragments.html#Lifecycle), the most reliable way of persisting states between activity/fragment changes is to use the default API for saving and restoring states:
When the activity/fragment is being dismissed (either because of a configuration change such as screen rotation or because the user requested to go to another activity/fragment), you can save its state in a Bundle object. When it is being created, you can restore its saved state, thus recreating a new instance exactly like the one the user left - so the user feels nothing has changed. This does not depend on the specific subclass of activity/fragment you are using.
I have implemented something like what you want: in my case, a fragment containing a menu with buttons that would each lead the user to another fragment containing a submenu with a "back" button. So if the user went from menu to submenu 1, then back to menu, then to submenu 2, then back to menu and finally again to submenu 1, I wanted that submenu 1 to appear just like the user has left it in the first time.
For that I have created:
1) an interface defining my submenu types, implemented by my activities so they could change between my submenus
2) a master generic class, which all my submenus would extend, that had a Bundle object to store their state
3) in my activities, I had an array of Bundle capable of storing one instance of each of my submenus (because I am only interested in restoring the last state, so I don't need more than one)
The interface (item 1):
public interface SubmenusManager {
public static enum Submenus {
ROOTMENU,
SUBMENU1,
SUBMENU2;
private static final int size = Submenus.values().length;
public static int size() {
return size;
}
public static int getId(Submenus test) {
switch(test) {
case SUBMENU1:
return 1;
case SUBMENU2:
return 2;
case ROOTMENU:
default:
return 0;
}
}
}
public void cloneCurrentSubmenuState(Parcelable toOverwrite);
public Bundle getLastStoredSubmenuState(Submenus submenu);
public void setCurrentSubmenuTo(Submenus submenu);
}
The generic class (item 2):
public class MenuFragment extends Fragment {
private Bundle menuData = new Bundle();
public static String RESTORE_MAIN_OBJECT = "restore_main";
public Bundle getMenuData() {
return menuData;
}
public Bundle cloneMenuData() {
return new Bundle(menuData);
}
public void setMenuData(Bundle menuData) {
this.menuData = menuData;
}
}
One of the activities (item 3):
public class ExampleAct extends FragmentActivity implements SubmenusManager {
/**
* instance variables
*/
private MenuFragment mMenu;
private Bundle [] menuData; // the Array of Bundles!
private static final String CONTAINER = "parcelable_container";
private static final String SUBMENU = "saved_submenu";
private Submenus curSubmenu = Submenus.ROOTMENU; // the default state is the ROOTMENU
private boolean restoreLastSavedState = false;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState == null) { // first time creating this activity
menuData = new Bundle[Submenus.size()];
} else { // this activity has a saved state from before
// restore all the data from all the submenus
menuData = (Bundle[]) savedInstanceState.getParcelableArray(CONTAINER);
// restore the info about which is the current active submenu
curSubmenu = (Submenus) savedInstanceState.getSerializable(SUBMENU);
}
buildMenuFragment(true);
//(...) stuff
}
private void buildMenuFragment(boolean restoreState) {
// (re)builds fragment inside menu.
// restoreState flags whether activity should look for
// saved state data and restore it
restoreLastSavedState = restoreState;
switch(curSubmenu) {
// Eclipse warns you about which are the constants in your enum
case ROOTMENU:
mMenu = new FragmentRootMenu();
break;
case SUBMENU1:
mMenu = new FragmentSubmenu1();
break;
case SUBMENU2:
mMenu = new FragmentSubmenu2();
break;
}
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.menu_frame, mMenu)
.commit();
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putSerializable(SUBMENU, curSubmenu);
cloneCurrentSubmenuState(mMenu.getMenuData().
getParcelable(MenuFragment.RESTORE_MAIN_OBJECT));
outState.putParcelableArray(CONTAINER, menuData);
// (...) stuff
}
#Override
public void cloneCurrentSubmenuState(Parcelable toOverwrite) {
if (menuData == null) menuData = new Bundle[Submenus.size()];
if (toOverwrite != null)
mMenu.getMenuData().putParcelable(MenuFragment.RESTORE_MAIN_OBJECT, toOverwrite);
menuData[Submenus.getId(curSubmenu)] = mMenu.cloneMenuData();
}
#Override
public Bundle getLastStoredSubmenuState(Submenus forThisSubmenu) {
return
(menuData == null || !restoreLastSavedState) ? new Bundle() : menuData[Submenus.getId(forThisSubmenu)];
}
#Override
public void setCurrentSubmenuTo(Submenus toThisSubmenu) {
if (mMenu != null) {
cloneCurrentSubmenuState(mMenu.getMenuData().
getParcelable(MenuFragment.RESTORE_MAIN_OBJECT));
}
curSubmenu = toThisSubmenu;
buildMenuFragment(true);
}
One of the submenus (extension of item 2):
public class FragmentSubmenu1 extends MenuFragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_submenu1, null);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
init();
}
public void init() {
// (...) stuff
MyParcelableObject tmp = null; // MyParcelableObject is a class
// that implements Parcelable and stores
// relevant info to rebuild this menu
// from a saved state
SubmenusManager m = (SubmenusManager) getActivity(); // remember activity implements SubmenusManager
Bundle bnd = m.getLastStoredSubmenuState(SubmenusManager.Submenus.SUBMENU1);
if (bnd != null) tmp = bnd.getParcelable(MenuFragment.RESTORE_MAIN_OBJECT);
if (tmp == null) {
tmp = new MyParcelableObject();
tmp.buildFromScratch(); // initializes with default data
}
// back button
Button backToMainMenu = (Button) getView().findViewById(R.id.submenu1_back);
backToMainMenu.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
((SubmenusManager) getActivity()).
setCurrentSubmenuTo(SubmenusManager.Submenus.ROOTMENU);
}
});
// (...) stuff
}
}
The Root menu (extension of item 2):
public class FragmentRootMenu extends MenuFragment {
View myView;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
myView = inflater.inflate(R.layout.fragment_rootmenu, null);
return myView;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
init();
}
public void init() {
Button btnSubmenu1 = (Button) myView.findViewById(R.id.btn_call_submenu1);
btnSubmenu1.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
((SubmenusManager) getActivity()).
setCurrentSubmenuTo(SubmenusManager.Submenus.SUBMENU1);
}
});
Button btnSubmenu2 = (Button) myView.findViewById(R.id.btn_call_submenu2);
btnSubmenu2.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
((SubmenusManager) getActivity()).
setCurrentSubmenuTo(SubmenusManager.Submenus.SUBMENU2);
}
});
}
}
For that to work between activities, all you need to do is pass that object that stores the last state of all fragments (in my case, that would be Bundle [] menuData) to the activity that is being called through its Intent; you would recover it the same way as my ExampleAct did in its onCreate(). You could also wrap that Bundle [] inside a custom Parcelable object (very similar to my example MyParcelableObject; inside that one I had stuff like HashMap) if using an array is a problem.
Here how to pass a Parcelable between activities:
How to send an object from one Android Activity to another using Intents?
I have a MainActivity. It's layout contains a fragmentContainer and an actionBar. Then I have 2 different fragments containing various EditTexts.All of them have Ids. I populate the fragmentContainer with the fragments when user clicks a button in actionBar. Everything works perfectly.
Now...the app, is supposed to collect the contents of all EditTexts from both fragments when I push a button (in the menu of the actionBar). But it does not work. It crashes when I try to access the EditTexts directly from the activity. I understand that I should create a public method inside the code of the fragments that will return the values I am interested in. But I seem to be doing something wrong because the method is not accessible from the main (TabActivity)
Here is my code:
public class TabActivity extends Activity {
ActionBar.Tab tab_alocare, tab_merc;
Fragment fragmentTab1 = new aloc_fragment();
Fragment fragmentTab2 = new merc_fragment();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tab); // this layout contains the fragmentContainer
...// here I do some actionBar stuff
}
...
}
An example of one of the fragments is bellow:
public class aloc_fragment extends Fragment {
EditText mEditText;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_aloc, container, false);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mEditText = (EditText) getView().findViewById(R.id.edaloc);
}
public String getMyText() {
String rez = "";
if (mEditText.getText()!=null) {
rez = mEditText.getText().toString();
}
return rez;
}
}
Now... if inside the Activity code I want to access the edaloc EditText using findViewById, it crashes the app with nullException. So I then tried to access the public method of the fragment so that it would return me the value that I need. But "getMyText" method is not accessible from the TabActivity.
So, this code does not work:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.save:
Fragment alocfragment = (Fragment) getFragmentManager().findFragmentByTag("aloc");
String s = alocfragment.getMyText(); // this is not compiling at all
I am clearly doing something wrong.
Please advise.
Thank you
There are lots of mistakes in your code, You have neither declared nor initialize the fragments at proper place. Also, you are trying to create another instance of fragment in onOptionsItemSelected which is wrong, you need to use same instance of fragment there to access your functions with values. I hope you know how to add and inflate fragment. See my comments and code changes.
Try with this -
public class TabActivity extends Activity {
ActionBar.Tab tab_alocare, tab_merc;
//Declare fragments here
Fragment fragmentTab1;
Fragment fragmentTab2;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tab); // this layout contains the fragmentContainer
//Initialize here
fragmentTab1 = new aloc_fragment();
fragmentTab2 = new merc_fragment();
//inflate/add fragments here to the activity
...// here do your actionBar stuff
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.save:
//Now, use same instance of fragment to access your function
String s = fragmentTab1.getMyText();
}
}
public class aloc_fragment extends Fragment {
EditText mEditText;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_aloc,
container, false);
//hold edittext here in the variable
mEditText = (EditText) view.findViewById(R.id.edaloc);
return view;
}
public String getMyText() {
String rez = "";
if (mEditText.getText()!=null) {
rez = mEditText.getText().toString();
}
return rez;
}
}
Also, must to go through Fragment tutorial on Android Developer Fragment Link Link 2, Using Fragments