I have the default Android project layout in Eclipse. The current one, that comes with a "dummyText" and a switcher on top. (I selected that one during the wizard.)
I want to use the top select bar to switch screens. Between Main, and Settings, and Result.
How do I detect the current activity?
Because.. if I have a switch, like:
switch (getArguments().getInt(ARG_SECTION_NUMBER)) { ... }
It will get into an infinite loop if the current screen is the selected one on the top.
(E.g.: Value 1 = Main screen. And you open the application, and it's value 1. And it's on main screen. It will indefinitely open up the main screen again and again. If you select an other value, like 2, it will go to the proper screen, and it won't loop.)
How am I supposed to fix this?
(I'm opening the other Activity with a new Intent, and then I call startActivityForResult(...).
Update #1:
The switch went into the "DummySectionFragment", which gets created at the onNavigationItemSelected.
Which looks like this:
Fragment fragment = new DummySectionFragment();
Bundle args = new Bundle();
args.putInt(DummySectionFragment.ARG_SECTION_NUMBER, position + 1);
fragment.setArguments(args);
getSupportFragmentManager().beginTransaction()
.replace(R.id.container, fragment).commit();
So basically that looks right... to me. The switch is activated, the corresponding value gets sent to Dummy, and a switch could just work to launch the proper Activity. I just need to write an if statement, that IF the current Activity matches the "to-be-invoked" one, the app should do nothing.
How am I supposed to implement this?
(I know the code is a little messy, blame Google for it's sample.)
In case you are not familiar with the Google example/code I used, here it is:
https://gist.github.com/anonymous/4edaefa42dd1be96e6e4
It's the "Blank Activity" -> "Dropdown" one.
I think you'r not using the sample as intended. One way would be to put the switch in the onNavigationItemSelected and within it launch the correct fragment (instead of DummySectionFragment) according to the selected item.
So this sample is built on Fragments, you should use them for the different sections, instead of launching a new activity.
The other way would be to have the DummySectionFragment use the ARG_SECTION_NUMBER to decide which layout to inflate, and inflate different layouts for different sections. In any case launching a new activity per section is not the way this sample is supposed to work.
Edit: Here are good guides for working with fragments:
http://developer.android.com/training/basics/fragments/index.html
http://developer.android.com/guide/components/fragments.html
Related
I am doing an Android application with several tabs, let say that
have 2 tabs. One tab is an "android.support.v4.app.Fragment" that
contains a few textfields and a button, and the other one is an
"android.app.Fragment" that at the same time is a MapFragment.
The thing is that the first tap calls another
"android.support.v4.app.Fragment" with cardview (also support) and
they can be navigate between them with some hierarchy.
Now if first a click in the map tap, later on click the other tab and
finally I click the button to go to the frame that contains
cardviews, I can see these them but in the background I see also the
MapFragment.
I don't know how to solve this. I have tried to use replace, remove,
add, popBackStack, ... In addition I had tried to delete from the
rootview the frame of the fragment, but nothing happened.
The fact is I am going to throw your laptop out the window.
Thanks in advance!
If you are using .addToBackStack("") than remove this. and for calling fragment every time user .replace(); method for all your fragment.
Well I found out what happened. It is due to work with two different fragment managers (FragmentManager and SupportFragmentManager).
Depend on the fragment type (support or normal) you want to remove or replace you have to use one or another fragment manager.
I have created an enum to know what kind of fragment is active (in order to remove) and what kind of fragment is going to start (in order to replace).
More or less I made a function like this:
private void manageFragment (FragmentEnum nextFragment) {
switch (activedFragment) {
case SUPPORT:
getSupportFragmentManager().beginTransaction().remove(fragmentSupport).commit();
break;
case NORMAL:
getFragmentManager().beginTransaction().remove(fragmentNormal).commit();
break;
}
activedFragment = nextFragment;
switch (nextFragment) {
case SUPPORT:
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, fragmentSupport).commit();
break;
case NORMAL:
getFragmentManager().beginTransaction().replace(R.id.fragment_container, fragmentNormal).commit();
break;
}
}
I am working on an app that has a tab bar navigation pattern. Each tab represents a feature of the application that is backed by a ready-only database that is updated daily. If the data for a feature is not present in the database, I have an AlertDialog that prompts the user to update their database from the updates screen. The UpdatesFragment is a sub screen to the SettingsFragment which is a top-level option on the tab bar.
What is the best way to show the UpdatesFragment directly from the dialog but still show the settings tab as selected and allow the user to navigate back through settings when they press back? Should I go through the SettingsFragment and pass an argument for it to directly replace itself with the UpdatesFragment?
Home | FeatureA | FeatureB | ... | Settings
|
Updates
I'd argue that you should let the user update from any place, or at least, trigger the update from the AlertDialog itself.
Regardless of that, you want to construct your backstack the same way it would have been constructed if the user tapped all the way to the final destination.
Android provides a TaskStackBuilder for the matter, which you can find in the official Android documentation, located here.
UPDATE AFTER YOUR COMMENT:
Hmmm I see what you mean. Well then you'd have to create fragment transactions and/or use Bundle values to tell the "next" fragment that it needs to open the next and so forth. To be honest, when "shortcuts" like these are needed, there's a possible architecture flaw (no offense) that should rather be addressed before the code starts getting more and more spaghetti.
However, since I don't know your code and your app, I won't judge you :)
What I would do if I were facing this situation, is try to go this route:
Fire an intent to the same activity (so your activity receives onNewIntent()) and pass a bundle with the required information for your activity to resolve the intent and fire the correct fragment transactions?
If UpdatesFragment should replace settings fragment, then your activity should do either of these upon receiving that intent:
1) Create a Fragment Transaction to replace the current fragment with SettingsFragment.
2) Pass a Bundle to SettingsFragment telling it to open UpdateFragment (and whatever other information is required).
3) Add that to the Backstack.
4) SettingsFragment should check (upon startup) if the args bundle contains such value and should immediately proceed to create another FragmentTransaction to replace itself with UpdatesFragment (and also pass any args in a Bundle that the former may require to perform its actions).
or…
maybe you can try to do all in one step (I'm not sure if this will work, it depends upon your architecture, but it's easy to try).
PseudoCode (assumes you already have your Fragments instances and such)
fragmentTransaction
.replace(your_container, settingsFragment)
.addToBackStack(null)
.replace(your_container, updateFragment)
.addToBackStack(null)
.commit();
I have recently started to take a look at developing apps for my android device. What started this interest for me is I was playing around with a few arduinos had the great idea to make them communicate with my phone, as say an interface for whatever values I am measuring on the arduino itself. Now I could take the easy way out and use a public source to accomplish this but there isn't as much to learn that way, and I would like it the way I want it.
Now I suppose the first question I need to ask is, would multiple fragments/single activity be the best way for me to accomplish this? Basically, I want 1 connection to the arduino, pull all the values, but depending on the "tab" I have selected I want certain values displayed certain ways. I decided to make each tab a different fragment and just display the values different ways. Like I said, I am just beginning android development experience so don't have much to base this choice off of.
So being fixated on this multiple fragment idea I have:
Created multiple Fragment.xml files
Defined a class for each separate view
Created a List to display available Fragments
Instantiated and displayed fragment when selected
So essentially my onMenuItemSelect looked like this.
FragmentTransaction FT = getFragmentManager.beginTransaction();
switch(position){
case 1:
FT.replace(R.id.fragment_container, new MyFragment()).commit();
break;
case 2:
FT.replace(R.id.fragment_container, new MySecondFragment()).commit();
break;
}
The above code worked, it did what I wanted it to without any issues. I don't really like this though, because for each and every Fragment I wanted to add I would need to add a new case to the switch. Also this instantiates a new fragment every time, even if one was already created. Is that a problem?
The biggest problem I had with it is that it isn't the easiest to scale. For 2-3 fragments this isn't the worst way to handle it (in my eyes). I want to be able to have as many fragments I want without an individual case for each one in the switch. So what I did was created a fragmentList to hold a single instance of each of my fragment.
List<Fragment> fragmentList;
private void populateFragmentList();{
fragmentList = new ArrayList<Fragment>();
fragmentList.add(new HomeFrag());
fragmentList.add(new BluetoothFragment());
fragmentList.add(new USBFragment());
fragmentList.add(new RCInfoFragment());
fragmentList.add(new ControllerFragment());
fragmentList.add(new FingerCordsFrag());
}
public void onMenuItemSelect(int position, int curPosition){
if(fragmentList.get(position).isAdded()){
getFragmentManager().beginTransaction().show(fragmentList.get(postition))
.hide(fragmentList.get(curPosition)).commit();
}
else
getFragmentManager().beginTransaction().add(R.id.fragment_container, fragmentList.get(position)).show(fragmentList.get(position)).hide(fragmentList.get(curPosition)).commit();
}
And this method also worked. I could get it to display all of my fragments, without have to re-instantiate each fragment each time. I believe this does what I am wanting it to do, it scales fairly well(better than a switch/case IMO). The problem that I have now is that it all goes crazy when I change orientation. Up until now I was only testing portrait mode, I am not able to view any of my fragments when I select them in other orientation. I can start it in either orientation, and it works, but when I change it during run-time, I am only able to see the one fragment I had open when I changed orientation.
Now, each fragments "onCreateView" is being called, it is just that the display isn't being shown. I believe I have it narrowed down to it isn't being attach to the new activity created from the orientation change. Is There anyway I can reattach fragments that are already created to a new activity.
In summary, the questions I have are:
Is this model even a good way for my application?
Is there a decent way to handle Fragments that scales well? Can't
seem to find any examples.
Is using a ''new MyFragment()'' each time I open a different tab a
reasonable way to achieve this?
Is my way of storing my Fragments in a list a reasonable way to
handle them?
How do I reattach a fragment to the new Activity after an
orientation change?
Thank you for your time.
*Had to type all this code on the fly because I, for some reason, couldn't get my C/P'd code to format correctly.
I believe it a good choice to use fragments and start with this example...
You should definitely override some "Adapter" to handle all the transactions more easily...
Check here for the orientation problem...
Is there some way I get already created currently displayed same instance of fragment in my activity. I DON'T to use
findFragmentById(int id), simply I never created that
findFragmentByTag(String tag), because I am not adding tag in every fragment .offcourse due to some requirement.
getFragment(Bundle bundle, String key), because I never am putting in bundle.
Although I may look like fool to mention that, but I want something like this. Is activity keep some fragment instance somewhere.??
What can be the best approach I can take to achieve this requirement.
UPDATE
Okay, so let me tell you why I can't use above methods. If I am adding various fragment in one activity, where I always want to come back to one fragment when back is clicked. (As we have in navigation drawer, u know). And unless there are inner fragment. so for that I don't want to add in the back stack.
Now even if I have the tag associated with my fragments, I cant say for 8 fragment if- else-if-else for getting the tag. That I know is not correct. So first two ways goes out of my option. Now third one. I exactly don't know where to keep it. And even if I keep it where will I get the bundle and key every time I just want my fragment.
You can get from fragment Manager
List<Fragment> fragList=fManager.getFragments();
for(Fragment fr: fragList){
String fragClassName = fr.getClass().getName();
if(fragClassName.equals(Abc.class.getName())){
Log.i("Fragment:","Abc");
}else if (fragClassName.equals(Xyz.class.getName())) {
Log.i("Fragment:","Xyz");
}
}
I'm looking for some advice on the best way to handle fragments which launch other fragments.
I'm converting an app which I started writing using a more Activity based approach and have since begun moving it over to using Fragments. I have some Fragments which used to launch a new Activity and I want to move them over to launching other Fragments in the same view that the current Fragment is residing.
For example - I have an Activity which has a WebView which uses a WebViewClient to handle internal js->java interactions. My WebViewClient can launch other Activities, which I used to do with :
i = new Intent(context, GoogleMapActivity.class);
startActivity(i);
This webview activity can either be fullscreen or in a view with a menu on the side, but I want the webview to respect the layout - so if the menu is present, it should stay present when launching new Fragments - I just don't know the best approach to writing the code which launches the Fragments.
So...is there a way, within a Fragment, of essentially telling a new Fragment to load in to the same space as the current Fragment or does there need to be some interaction with the Activity?
** EDIT **
Given that there are a few different layouts which could be used, I don't always know which id I should be targeting to put the fragment in - hence I need to know if there's a way to do this without knowing the id (as in the replace method for example).
getFragmentManager().beginTransaction()
.replace(((ViewGroup) getView().getParent()).getId(), fragment)
.addToBackStack(null)
.commit();
This should replace parent container with desired fragment.
That should be doable via FragementManager.replace(). Have a look at the documentation for Fragment and especially the longer example in the "Layout" section there.
If you want to add Fragment rather replace it, use:
getFragmentManager().beginTransaction().add(R.id.fragment_container, new Fragment()).commit();