I am new to fragments and have a lot of problems understanding and working with them. I will try to describe my problem step by step:
I start with a list
after selecting an item i start an activity with a dynamic url in a webview
If portrait, only the webview is showed, if landscape the list is presented next to it
In landscape when i select another item, it is showd in the webview (check the code)
Problem: When i turn back now to portrait the first selected item is showd instead of the last one.
How can i update the activity so it will keep the last opened url after orientation change?
if (fragment==null || ! fragment.isInLayout()) {
Intent intent = new Intent(this.getActivity(), DetailViewActivity.class);
intent.putExtra("link", urlforwebview);
startActivity(intent);
} else {
DetailView detailFragment =
(DetailView)
getFragmentManager().findFragmentById(R.id.detailfragment);
detailFragment.changeWebviewURL(urlforwebview);
}
FIX:
Added this to my detailfragment:
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("currentUrl", url);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (savedInstanceState != null) {
// Restore last state for checked position.
url = savedInstanceState.getString("currentUrl", "");
changeWebviewURL(url);
}
}
Have a look at : onSaveInstanceState.
http://developer.android.com/reference/android/app/Activity.html#onSaveInstanceState(android.os.Bundle)
This answer here can help you: android fragment- How to save states of views in a fragment when another fragment is pushed on top of it
Related
I am trying to use BottomNavigatioView in my MainActivity and when on clicking a tab in the bottom navigation, the new fragment replaces the previous one, which takes the previous one to the onDestroyView state.
How can we make all the fragments in the onResume state, regardless of whether they are or not visible on the FrameLayout.
You can save the state of fragment and can restore it on onCreateView()
Bundle savedState;
public onCreateView(...){
..........
if(savedState != null){
String hello = savedState.getString("hello");
}
..........
}
#Override
public void onDestroyView(){
super.onDestroyView();
savedState.putString("hello", "Say hello");
}
I'm having some problems with navigation and the up button of the activity. I have two tabs implemented with Viewpager in one activity and then another activity which is loaded from the previous one. When the user clicks the phone's back button or the activity's up button, I want to go back to the previously selected tab and fragment of the first activity.
So far I've been able to do it for the back button, with onSaveInstanceState and the following code:
#Override
protected void onSaveInstanceState(Bundle bundle) {
super.onSaveInstanceState(bundle);
bundle.putInt("currentPage", mViewPager.getCurrentItem());
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(savedInstanceState != null) {
int page = savedInstanceState.getInt("currentPage", 0);
mViewPager.setCurrentItem(page);
getSupportActionBar().setSelectedNavigationItem(page);
}
}
Why is this not working for the up button? What do I have to do?
Any help is appreciated and sorry if this is an issue easy to solve, but I'm rather new to the Android programming.
I finally found the solution at Returning from an activity using navigateUpFromSameTask(). savedInstanceState was null when the activity was recreated. To avoid so, the launch mode of the activity has to be declared as singleTop in the Android manifest.
In my application i have a FragmentPager. Now each Fragment has a next button with which i navigate to the next fragment. Via the next button i know that the user is navigation away from the view. But how do i know if the user has clicked on the tabs. Will the
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString(KEY_CONTENT, mContent);
}
function be called when a user presses a different tab ? Can i save the state and restore it on the
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if ((savedInstanceState != null)
&& savedInstanceState.containsKey(KEY_CONTENT)) {
mContent = savedInstanceState.getString(KEY_CONTENT);
}
}
will this work ? What other way can i know that the user has clicked on the different tab ?
Kind Regards
First of all, are you using ActionBarSherlock for you actionbar/tabs? I recommend that you do since you'll get a cross-version way of working with the actionbar.
In any case, you should add a listener to each tab before adding it to the actionbar. With the listener implemented you know when a tab has been selected, reselected and unselected
I'm not sure about when the onSaveInstanceState is called (try it using the debugger!), but with the listener implemented you'll get a fool-proof way of knowing what goes on with your tabs.
I implemented my layout based on this tutorial: http://android-developers.blogspot.hu/2011/02/android-30-fragments-api.html
The differences are:
I have different fragments to show, based on the choice in the left
list
The "details fragments" (those that come to the right) have different options menus
My problem is that if I have already selected something from the left and then rotate the phone to portrait, the last optionsmenu is still there and is visible.
I think the problem comes from the last active "details" fragment is recreated after the orientation change. to test it I created these two methods:
#Override
public void onStart() {
super.onStart();
setHasOptionsMenu(true);
}
#Override
public void onStop() {
super.onStop();
setHasOptionsMenu(false);
}
And I'm showing the right fragment like this:
case R.id.prefs_medicines:
if (mDualPane) {
// Check what fragment is shown, replace if needed.
View prefsFrame = getActivity().findViewById(R.id.preferences);
if (prefsFrame != null) {
// Make new fragment to show this selection.
MedicineListF prefF = new MedicineListF();
// Execute a transaction, replacing any existing
// fragment with this one inside the frame.
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.preferences, prefF);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.commit();
}
} else {
// Otherwise we need to launch a new activity to display
// the dialog fragment with selected text.
Intent intent = new Intent();
intent.setClass(getActivity(), MedicinePrefsActivity.class);
startActivity(intent);
}
break;
in one of my "details" fragment. when I debugged it, the onstart was called after the rotation.
The problem in pictures:
1: in landscape it's OK
Landscape mode http://img834.imageshack.us/img834/8918/error1d.png
2: in portrait: optionsmenu not needed
Portrait mode http://img860.imageshack.us/img860/8636/error2r.png
How can I get rid of the optionsmenu in portrait mode?
I had the same problem, and resolved it by setting setHasOptionsMenu(true) in the fragment only when savedInstanceState is null. If onCreate gets a bundle then the fragment is being restored in an orientation change to portrait, so don't display the menu.
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(savedInstanceState == null) {
setHasOptionsMenu(true);
}
}
I am trying to build a split pane based on the example code provided at the end of the Android documentation about Fragments, basically a LinearLayout containing two fragments (all the details can be found in the above link):
TitlesFragment to display a list of titles
DetailsFragment to display the details of the currently selected title
My problem is that the following unexpected behavior happens:
I start the application in Landscape orientation: the titles list is displayed on the left and the details of the currently selected title (the first one at the beginning) are displayed on the right.
I select item X from the titles list: the title becomes highlighted since the ListView is set to CHOICE_MODE_SINGLE and its items implement the Checkable interface.
I switch to Portrait orientation (by rotating the device or emulator): as expected, only the titles list is shown and no item is selected in this configuration, because the ListView gets recreated and, by default, it is set to CHOICE_MODE_NONE.
I select item Y from the titles list: as expected, an activity showing only the DetailsFragment corresponding to the selection made is shown.
I switch back to Landscape orientation (here's where the unexpected behavior happens): the DetailsFragmenton the right correctly shows the details of item Y (which was selected in portrait orientation) but the TitlesFragment still shows item X as selected (i.e. the one which was selected BEFORE the first screen rotation).
Of course, I would like that the last selection made in Portrait orientation was correctly shown also within the TitlesFragment, otherwise I end up with an inconsistent highlighting which shows item X as selected while displaying the details of item Y.
I post the relevant code where the ListView mode is changed (within 'onActivityCreated') and the selected item is set (within the 'showDetails' method):
public static class TitlesFragment extends ListFragment {
boolean mDualPane;
int mCurCheckPosition = 0;
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
// Populate list with our static array of titles.
setListAdapter(new ArrayAdapter<String>(getActivity(),
android.R.layout.simple_list_item_activated_1, Shakespeare.TITLES));
// Check to see if we have a frame in which to embed the details
// fragment directly in the containing UI.
View detailsFrame = getActivity().findViewById(R.id.details);
mDualPane = detailsFrame != null && detailsFrame.getVisibility() == View.VISIBLE;
if (savedInstanceState != null) {
// Restore last state for checked position.
mCurCheckPosition = savedInstanceState.getInt("curChoice", 0);
}
if (mDualPane) {
// In dual-pane mode, the list view highlights the selected item.
getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
// Make sure our UI is in the correct state.
showDetails(mCurCheckPosition);
}
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("curChoice", mCurCheckPosition);
}
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
showDetails(position);
}
/**
* Helper function to show the details of a selected item, either by
* displaying a fragment in-place in the current UI, or starting a
* whole new activity in which it is displayed.
*/
void showDetails(int index) {
mCurCheckPosition = index;
if (mDualPane) {
// We can display everything in-place with fragments, so update
// the list to highlight the selected item and show the data.
getListView().setItemChecked(index, true);
// Check what fragment is currently shown, replace if needed.
DetailsFragment details = (DetailsFragment)
getFragmentManager().findFragmentById(R.id.details);
if (details == null || details.getShownIndex() != index) {
// Make new fragment to show this selection.
details = DetailsFragment.newInstance(index);
// Execute a transaction, replacing any existing fragment
// with this one inside the frame.
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.details, details);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.commit();
}
} else {
// Otherwise we need to launch a new activity to display
// the dialog fragment with selected text.
Intent intent = new Intent();
intent.setClass(getActivity(), DetailsActivity.class);
intent.putExtra("index", index);
startActivity(intent);
}
}
Does anyone have an idea about how to solve such issue?
Thanks in advance.
Two years later, here I am working with the Fragment Layout sample from Android's v4 support library and I'm stuck with this exact same issue!
Here's the only fix I came up with that doesn't require using CHOICE_MODE_SINGLE all the time:
just add a call to getListView().setItemChecked(mCurCheckPosition, true); in the onResume() method of TitlesFragment. And... that's it!
Maybe you should set the value of outState BEFORE you call super.onSaveInstanceState?
#Override
public void onSaveInstanceState(Bundle outState) {
outState.putInt("curChoice", mCurCheckPosition);
super.onSaveInstanceState(outState);
}
I've encountered the same problem on that code and as workaround I call setItemChecked on the onStart method:
#Override
public void onStart() {
super.onStart();
if (mDualPane) {
getListView().setItemChecked(mCurCheckPosition, true);
}
}
Or as LearningNerd said do it in onResume()
If you place android:configChanges="orientation" in your activity tag in the manifest file, your app will ignore the rotations but still render the relevant layouts.