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...
Related
I have a dilemma how to implement a particular functionality. I need to display a list of pages, where each page has its own list of sections.
The way how it is now implemented, i have an Activity and a Fragment that have reference to the same ViewModel. From the NavigationDrawer when i select a concrete page, i change the list of sections that is displayed in the Fragment. The LiveData attributes are shown in the snippet.
public LiveData<List<Page>> pages;
public MutableLiveData<Page> selectedPage = new MutableLiveData<>(new Page(1));
public LiveData<List<Section>> sections = Transformations.switchMap(this.selectedPage, (Page page) ->
this.pageRepository.getSectionsForPage(page.id)
);
Now, besides the NavigationDrawer, i wanted to add swipe possibility of changing pages, and that led me to using ViewPager. But because that leads to using multiple Fragments of the same type, i'm wondering if using a shared ViewModel for every instance is a good option? In that way, every fragment shows totally the same data. The other way would be to make a new specific ViewModel for every instance, which i'm not sure if it is a good idea, because i can probably have as many as 50 pages.
A lot of pages possibility is maybe also not a use case for a ViewPager, but i'm not sure about that, because my Android experience is low.
Any tip with an explanation why is really appreciated.
If you are using sharedViewModel then it will be attached to activity ........ if you are using separate viewModel then it is attached with the lifeCycle of Fragment
So I am trying to integrate Google Maps into my application, I came across a concept that I don't entirely understand. I have seen that adding google maps into an app and it seems the most common way to do so is with an activity.
I found some websites and a SO question showing how to put Google Maps in a fragment, but would that be an issue if the user is constantly clicking on profiles and going back? Causing the map to be recreated or resumed constantly. Would that performance be better if the map was an activity instead?
Basically, Im not sure the best way to transition from an activity GUI to a fragment? I've had an app that only used 1 activity, I just used multiple different fragments changing them with this code
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
Fragment fragment = getFragmentManager().findFragmentById(R.id.framecontainer);
if (fragment == null) {
ft.add(R.id.framecontainer, frag, tag);
} else {
ft.replace(R.id.framecontainer, frag, tag);
}
ft.addToBackStack(null);
ft.commit();
I am confused because when I created my main activity, I called
setContentView(R.layout.baselayout);
This layout contained only a frame container, I would then add in a HomeScreenFragment right away and when I needed to change, I would use the FragmentTransaction code above.
However, if my new MapActivity used setContentView(R.layout.maplayout); how would I best change screens? If R.id.maplayout does not contain a framelayout, is it best to start a new activity that uses many fragments like the one I mentioned before? I remember hearing that calling setContentView more than once or outside onCreate() is bad practice.
It seems I am missing something because so far it seems like there is 2 ways of using activities with different layouts
Starting a new activity every time and just trying to minimize the amount of activities.
Make an activity with a FrameLayout and just swap fragments everytime
To address my actual problem
I want my users to click another user marked on the map which will bring them to a profilelayout and view that user's profile, should I use one of the 2 methods above or how should I go about doing so?
Do you guys have any input to point me in the best direction? Thanks!
If your current application is already fragment heavy, have you considered using MapFragment? I think if you're cleaning up your objects/resources appropriately it shouldn't really be a performance issue.
Also according to the documentation it says the following about the MapFragment:
It's a wrapper around a view of a map to automatically handle the necessary life cycle needs.
I think it's also good to note that it's possible for you to do layout manipulation by adding/removing views using the LayoutInflater.
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 interested in the best way to have a single activity that switches between two fragments.
I've read probably 15 Stack Overflow posts and 5 blogs posts on how to do this, and, while I think I cobbled together a solution, I'm not convinced it's the best one. So, I want to hear people's opinions on the right way to handle this, especially with regards to the lifecycle of the parent activity and the fragments.
Here is the situation in detail:
A parent activity that can display one of two possible fragments.
The two fragments have state that I would like to persist across a session, but does not necessarily need to be persisted between sessions.
A number of other activities, such that the parent activity and the fragments could get buried in the back stack and destroyed due to low memory.
I want the ability to use the back button to move between the fragments (So as I understand it, I can't use setRetainInstance).
In addition to general architecture advice, I have the following outstanding questions:
If the parent activity is destroyed due to low memory, how do I guarantee that the states of both fragments will be retained, as per this post: When a Fragment is replaced and put in the back stack (or removed) does it stay in memory?. Do I just need a pointer to each fragment in the parent activity?
What is the best way for the parent activity to keep track of which fragment it is currently displaying?
Thanks in advance!
I ended up adding both of the fragments using the support fragment manager and then using detach/attach to switch between them. I was able to use commitAllowingStateLoss() because I retain the state of the view elsewhere, and manually set the correct fragment in onResume().
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.add(R.id.my_layout, new AFragment(), TAG_A);
fragmentTransaction.add(R.id.my_layout, new BFragment(), TAG_B);
fragmentTransaction.commit();
}
public void onResume() {
super.onResume();
if (this.shouldShowA) {
switchToA();
} else {
switchToB();
}
}
private void switchToA() {
AFragment fragA = (AFragment) getSupportFragmentManager().findFragmentByTag(TAG_A);
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.detach(getSupportFragmentManager().findFragmentByTag(TAG_B));
fragmentTransaction.attach(fragA);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commitAllowingStateLoss();
getSupportFragmentManager().executePendingTransactions();
}
You might want to consider using a ViewPager in your parent Activity so you can switch between the Fragments.
So you would be able to swipe through them.
if you want to persist their state during a session even if the parent activity is destroyed, you need to make them Parcelable, so you can save the state even if the class isn't instantiated at that time. You also need to do this if your rotating your device and want to keep the current situation/data on the Screen.
You should write them to a Parcelable in their onPause methods and recreate them from it in the onResume one. This way it doesn't matter if they are destroyed or have to be recreated due to changes in the devices orientation.
if you want to be able to switch between those fragments with the Backbutton, you can catch the buttonClick for onBackPressed and handle it accordingly.
If you need to figure out what Fragment your displaying at a given time you ask your ViewPager what Fragment he is displaying at that time, so you don't have to keep track, you can just ask someone who knows, if you need to know it.
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