I am trying out using fragments with my tabhost for the first time and I am pretty impressed. That said, one of my tabs uses two fragments, first the user sees Fragment A and then if they hit a button in Fragment A it gets swapped with fragment B, and puts fragment A on the backstack. This all seems to work fine, except it does something funny on a change in orientation:
If the user is on Fragment B and there is an orientation change, it still shows fragment B. However if after the orientation change, they switch to a different tab and then switch back to the original tab, it goes back to showing Fragment A.
This does not happen without the orientation change. IE... if you are just on Fragment B, switch tabs, and then switch back, you still see Fragment B. Is there any way to preserve this across an orientation change?
Thanks in advance!
try to add this code to your manifest, for your activity:
android:configChanges="orientation|keyboardHidden"
______EDIT______
As ErstwhileIII mentioned, this is not real fix, and this will force Android to don't recreate Activity when device rotated. However, as you can see, I have answered to this question on October 14, 2011, and if you are looking for better answer, just try to find newer answers.
Related
I have one big and long question
I have one activity with 4 fragments using viewPager.
the first fragment also has 4 fragments using viewPager
the second fragment has 6 fragments using general fragment way (replace or add on framelayout)
Here are my question and problem
For example, I am in the first tab and in the second fragments, then hit homebutton and then bring my app upfront. after that suddenly all functionalities are not working. the back button is not working. the button in the fragment is not working. (error log said the fragment is not attatched)
it happens only on pixel3.
I have 5 different android phones but working fine on those phones.
I thought it could be the memory issue, so I turned on "profiler" from Android Studio, and I saw the weird thing. only pixel3 when I pressed the home button the activity is destroyed. I tested all other phones with "Profiler" the activity's state is saved not destroyed.
Does anyone have the idea of why it happened and fixed the problem?
Are the embedded fragments problem? or is it OS10 problem?
I found the issue. there is one option in developer mode named "Don't keep activities". that was on, that is why my app is working differently on pixel3.
I have the following issue and I'm no quite sure whether it is a bug or misunderstanding by me.
I have a single activity, Fragment A (attached to activity's onCreate Method) and Fragment B (not attached to activity during its creation). On button click, Fragment A is replaced with Fragment B with transition. So far so good.
On Fragment B there is button which invokes fragmentManager.popBackStackImmediate(). If I press this button and turn the screen off at the same time (during fragment transition) then, when the screen is back on, the two fragments are visible (fragment B should have been destroyed, but it is not).
This problem starts with support lib 27.1.0+. Prior to that, the fragments were replaced correctly during Back stack navigation. Have in mind that I'm using fragments from support library.
I read behavior changes but I could not manage to link some of it to my issue.
Does anybody knows some work around or has more information about it?
Thanks in advance!
UPDATE:
Problem exists only on devices up to Android 6. On Android 7+ everything is alright.
fragmentManager.beginTrasaction().replace().addToBackStack() - do it for FragmentA in onCreate and do it on click for FragmentB. And try popBackStack(). I think you forgot addToBackStack FragmentA.
Application has two fragments: the first one contains a small representation of pager with photos, and the second one contains full screen pager. The second fragment replaces the first and passes a page number to the previous every time it changes. I made connection between my fragments just like Android Developers says.
Everything works till device orientation doesn't change. The first fragment is not recreated until it is not on top of stack, that is why all page number changes after that are missed for first fragment.
I do not really what to disable views destroy on orientation change, but looks like it is the only way.
What is the best solution?
In your manifest file in your parent activity in which fragments are write following line :
android:configChanges="keyboardHidden|screenSize|orientation"
Let me know if that works for you. Best of luck :)
When you change the orientation, the activity gets rebuild, thus essentially destroying the fragment that was built before the change in orientation.
Perhaps you would wish to refer to this https://developer.android.com/guide/topics/resources/runtime-changes.html on retaining the state during a change in configuration.
I have an activity that starts a fragment IF A CERTAIN BUTTON IS PRESSED (not in onCreate()).
currently, after the fragment is started, if the screen is rotated, the fragment is automatically recreated.
Side question: Does this behavior sound normal? In the other posts I've seen relating to this, people seem to have to put in code to recreate the fragment.
I want override this functionality and manually re-create the fragment my self. Is there a way to do this?
This is normal, although its a pain in the neck. You can override it by putting a configChange in your mainfest. In that case, onConfigChanged in your Activity will be called when your device is rotated. However if you're changing between different layouts for landscape and portrait you will then have to do that by hand.
I'm trying to work out the best way to implement the 'ancestral' and 'temporal' navigation (utilising the up button and back buttons), for a music player I'm working on.
Currently, the user is presented with a viewpager, and can page between three main fragments (ArtistMain, AlbumMain and SongMain). Upon choosing an item inside that view, a fragment transaction occurs, and the viewpager goes out of view, replaced by a new fragment (AlbumSub, Songsub or player, depending on where the user came from). The user can then navigate deeper, until a song is chosen, and then they are taken to the 'player' screen.
I guess the question is: How do I implement all of this conditional navigation?
I'm fairly new to android and programming in general, and I just can't seem to come up with an efficient way to achieve this. At the moment, as each fragment is brought into view, the app is checking to see where the user just came from, and then determines where the user should be taken if back or home is called. This means I have a booleans like "fromArtistMain", "fromAlbumSub", and I'm checking for things like "fromSongSub && fromPlayer".. it's all turning into a bit of a mess.
I've drawn a diagram (in paint, sorry!!), to depict the navigation I'm trying to achieve. The yellow represents the 'up' button press, the red is the 'back' button press, and blue is just normal navigation. The green arrows are meant to represent the view paging:
Any advice is welcome. It might take something really simple that I've just overlooked.
Thanks for your time.
Edit:
I have been adding fragments to the backstack, and using popBackStack() calls, the problem is that popping the backstack is not necessarily the correct option in each case.
I've currently got a whole mess of code trying to determine whether a transaction should be added to the backstack in the first place.
Consider the following:
User chooses a song straight from 'SongMain', and is taken to 'Player'. Now using the home button should (in my mind), take the user to SongSub (the list of songs from the album that the chosen song belongs to). Now if the user navigates up again, they will be taken to 'AlbumSub', the list of Albums by that artist. This is a fragment transaction, but adding to the backstack would mean the user would be taken down a level on back press (which I think would be unexpected). So in this case I don't add that particular transaction to the backstack - seems fine, but there are quite a few different cases, and combined with a viewpager at the top which needs to come in and out of visibility, the code gets really messy.
All of this means a whole bunch of conditionals determining where the user came from and which path they took to get there..
Would it be wise to have a bunch of booleans in the host activity which get set depending on where the user has navigated, and then checking those booleans to see if a transaction should be added tot he backstack? This is kind of what I already have, but it seems really inefficient.
What you're looking into is called the Back stack. You can read more about it here at developer.android.com.
If you use a single Activity to host each of these Fragments then you can modify your code to explicity add your Fragments to the Fragment Back stack using code like so:
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.container, fragment);
transaction.addToBackStack("NameOfFragment");
transaction.commit();
So, if you do the above code with Fragments like so:
Fragment1 -> Fragment2 -> Fragment3 -> Fragment4
Then from Fragment4 if you call this method:
getSupportFragmentManager().popBackStackImmediate();
Then Fragment4 will be finished and Fragment3 will restart. Simple. You can have this line called from a button click or you can override the behaviour of the back button to call it.
Please note in the examples I've used the function getSupportFragmentManager() which is a method name in the Compatibility Package. If you're not using the Compatibility Package then you can instead call getFragmentManager().
EDIT
The problem with the navigation you envisage is that breaking out of the backstack paradigm half way through means that your app will "Act Differently" than the rest of the OS. This is by and large discouraged by Google. But then again, saying that, I do exactly the same in my app for very similar reasons :).
When you navigate "up", along one of your yellow lines, you are following a discrete link (so, startActivity(new Intent(this, SongSub)); or whatever) and you want this to "break" the backstack.
It's at this stage you can make a decision about how you want to go forward:
You can start a Task (backstack) using SongSub as 0th item. This is from memory what the Google Music app does and you're right, it's annoying. When you press back it should technically exit the app. Yuk. IMO if you're in an obvious page hierarchy, back should always navigate down the hierarchy over exiting the app.
You can start a new Task using ArtistMain as the 0th element and layer fragments discretely ontop before commiting your transaction, in effect creating a new backstack each time you go "up" rather than "back" (your backstack would now be ArtistMain->ArtistSub->SongSub). This is what I think your trying to ask here. It's possible but it's messy.
You can create a more linear structure (probably the best idea if possible). Ignore the backstack paradigm, make "back" and "up" always go up a level no matter where you came from (Player always goes to SongSub, SongSub always goes to AlbumSub). This will give the user the least confusing and most transparent (as well as easiest to implement) experience - the user will learn quickly how to navigate (and how many "backs" to press) to get to where they want to be.