Functionality of OnBackPressed inside of fragment - android

As title says, do anyone know a way how to implement OnBackPressed functionality, just like in Activity, but in Fragment View?
It does not work when I use onKey, onKeyDown or onBackPressed in Fragment - app is closing. I would like to execute specific code when back button is pressed, because in one of fragments I have ListView, which is filled with data depending on user actions.
So when back is pressed I would like to modify values of variables ("categories" and "part"), to fill ListView with specific data (so modify some values because user clicked something, and refresh this ListView), giving a feeling that user is going back (from parts, to categories and to close the app).
But as I mentioned, when I use onKey, onKeyDown or onBackPressed, app is closing... For instance when I include in my Fragment class:
public void onBackPressed() {
Toast.makeText(getActivity(), "AAAA", Toast.LENGTH_LONG).show();
}
Toast does not appear. With "onKeyDown" and "onKey" - the same situation... What am I doing wrong here, any ideas?

To answer your very first sentance:
as title says, do anyone know a way how to implement OnBackPressed
functionality, just like in Activity, but in Fragment View?
To make the back-button work with fragments you have to add them to the backstack. That should trigger the function you want.
// Create new fragment and transaction
Fragment newFragment = new ExampleFragment();
FragmentTransaction transaction = getFragmentManager().beginTransaction();
// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);
// Commit the transaction
transaction.commit();

Finally, got it.
I had to, in my "ActionBarActivity" from method "onNavigationDrawerItemSelected" move declaration of "Fragment newFragment" to outside of this method, to make it available in whole class. Then I had to include "OnBackPressed" in my "ActionBarActivity" like this:
#Override
public void onBackPressed() {
if (!newFragment.onBackPressed()) {
super.onBackPressed();
}
}
And finally, in my Fragment I included also onBackPressed:
public boolean onBackPressed() {
if (part != -1) {
part = -1;
toAdd = "" + category + "_";
updateList();
return true;
}
return false;
}
And it works just like I wanted. When I push back, and when variable "part" in my Fragment is not -1, then it is executing operations defined above, returning true to "ActionBarActivity" so the app is not closing. But when, in my Fragment, variable is -1, then onBackPressed app is going back to main view, and again when user is pushing back, app is closing. That's what I wanted!
Thank You all for the help!

#Override
public void onBackPressed() {
super.onBackPressed();
Intent register = new Intent(PollCreateCommunities_Activity.this, PollActivity.class);
startActivity(register);
finish();
}

public boolean onOptionsItemSelected(MenuItem menuItem) {
switch (menuItem.getItemId()) {
case android.R.id.home:
Intent register = new Intent(PollCreateCommunities_Activity.this, PollActivity.class);
startActivity(register);
return true;
}
return (super.onOptionsItemSelected(menuItem));
}

Related

Using the back button from a fragment in Android

I'm aiming for the following behavior.
When I am on my main activity,
If I navigate into fragment 1,
and from there, navigate into fragment 2,
then when I hit the phone's back button,
because I am on fragment 2 I am returned to the home screen, and not fragment 1.
If I had a separate button on the page, this behavior would be very easy, as I could just do:
Button.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v)
{
FragmentManager fm = getFragmentManager();
fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
});
I'm running into difficulties because I need to use the phone's own back button. I've read that the OnButtonPressed() event is only usable by an activity, not a fragment, and moving this kind of logic into the activity is proving difficult!
How can I achieve the behavior I'm after?
Just track the backstackcount and you can do whatever you want on the basis of count :
#Override
public void onBackPressed() {
manageBackStack();
}
private void manageBackStack() {
switch (getSupportFragmentManager().getBackStackEntryCount()) {
case 1:
//Do when count is 1
break;
case 2:
//Do when count is 2
break;
default:
finish();
}
}
Hope it will help :)
When you are adding the fragment you need to add the transaction to back stack. That means you want this transaction to be reversed when back button is pressed.
Please use the below code :
getSupportFragmentManager().beginTransaction()
.add(detailFragment, "detail")
// Add this transaction to the back stack
.addToBackStack()
.commit();
You can find more details in :
https://developer.android.com/training/implementing-navigation/temporal.html

How to go back to previous fragment from activity?

I've got an app with nav drawer, which is switching fragments. From inside one of those fragments, I am calling a new activity. When I click back in this activity (in toolbar), I want to go back to previous selected fragment but instead it puts me back to first fragment. I am adding my fragment to back stack so this should not be a problem.
Here is what I have already tried:
I have overriden the onBackPressed method in my 2nd activity like this:
#Override
public void onBackPressed() {
if (getFragmentManager().getBackStackEntryCount() == 0) {
this.finish();
} else {
getFragmentManager().popBackStack();
}
}
It is not working. I also saved index of current fragment inside onsaveinstancestate method and retrieve it but same result. I also tried with always putting current fragment inside variable and try to reshow it but still, it does not work. Anything else I could try?
Fun fact: if I press back inside bottom panel, it does actually goes back to previous fragment.
EDIT: Here is my code for doing this:
private void replaceFragment(Fragment fragment)
{
if (fragment != null)
{
FragmentManager manager = getSupportFragmentManager();
manager.beginTransaction()
.replace(R.id.main_content, fragment)
.addToBackStack(null)
.commit();
}
}
I add first fragment only, if savedInstanceState is null, like so:
if (savedInstanceState == null) {
// first time
mTitle = getResources().getString(R.string.home);
replaceFragment(HomeFragment.newInstance());
}
And yes, all this is done inside onCreate() method.
I had the same problem and got fixed. The only thing you need to do is to
override the method "onOptionsItemSelected" in the activity:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
finish();
return true;
}
return super.onOptionsItemSelected(item);
}
android.R.id.home is your first fragment in the menu.
What I tend to do is this
#Override
public void onBackPressed() {
if (getFragmentManager().getBackStackEntryCount() == 0) {
this.finish();
} else {
super.onBackPressed(); //replaced
}
}
This way it handles the fragment stuff on its own within, but when there's no fragments left to go back to, then it finishes the activity.
EDIT: UP navigation can recreate your previous activity even if it already exists. To prevent that from happening, redefine the Up navigation's event in onOptionsItemSelected like so:
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
Intent parentIntent = NavUtils.getParentActivityIntent(this);
if(parentIntent == null) {
finish();
return true;
} else {
parentIntent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(parentIntent);
finish();
return true;
}
}
return super.onOptionsItemSelected(item);
}
When you call an activity from other activity's fragment, then the previous activity's instance state that is the calling activity which was having fragment's instance state will be saved in stack...so all u need to do is finish the called activity and u will have the fragment from which you called your second activity.
#Override
public void onBackPressed() {
finish();
}
Try
getFragmentManager().popBackStackImmediate();
It worked for me.
Sorry, I don't have enough reputation to leave a comment. So I have to guess. I once had the same issue.
Sounds like a problem related to the activity lifecycle (http://developer.android.com/reference/android/app/Activity.html#ProcessLifecycle). Be sure to add your first fragment only once, because your activity's fragment manager is capable of the lifecycle.
Thus, the statement that adds the first fragment to your fragment manager should be surrounded by if (savedInstanceState == null) { ... }.
I see, that people are still trying to help me. This answer helped me fix my problem: Android - Navigation Up from Activity to Fragment
Override onOptionsItemSelected method in activity as follows,
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == android.R.id.home) {
finish();
}
return super.onOptionsItemSelected(item);
}
When you call new Activity from Fragment you should write :
Intent intent = new Intent(getFragment().getContext(),NewActivity.class);
getFragment().getContext().startActivity(intent);
FragmentManager fm = CurrentFragment.getActivity().getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.addToBackStack(CurrentFragment.class.getName()).commit();
fm.executePendingTransactions();
It Works for me.
getSupportFragmentManager().beginTransaction()
.setReorderingAllowed(true)
.addToBackStack("home") // should not be null
.replace(binding.fragmentContainer.getId(), new HomeFragment())
.commit();
Pass name in addToBackStack(String name) method. This function add fragment into backstack if passed name is not null. App automatically start managing backstack of fragment
Remove your override onBackPressed() method. No use of it now

Which method is called when back button is pressed from a fragment

I've had a look at this question-
Call OnResume when Back Button Pressed when using Fragments
I've done the same things, as mentioned in the answers, but neither is onResume called, nor onCreateView. It's a transaction from an activity to a fragment, all of which are a part of a single tab. How can I call a method from the first fragment when back button is pressed on the second fragment?
Code-
Bundle data = new Bundle();
data.putString("q", code);
data.putString("type", type);
data.putString("name", name);
viewPager.setCurrentItem(1);
android.support.v4.app.FragmentTransaction transaction =
getSupportFragmentManager().beginTransaction();
eq equity = new eq();
equity.setArguments(data);
transaction.replace(R.id.root_frame, equity).addToBackStack(null).commit();
The method called when you press the back button is onOptionsItemSelected
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
onBackPressed();
default:
return super.onOptionsItemSelected(item);
}
}
#Override
public void onBackPressed() {
if (yourCondition = true) {
//do something here
} else {
super.onBackPressed();
}
}
But onOptionsItemSelected is called on the parent activity.
I don't know if the back button is required, but I think it's better to implement a callback from one fragment to the other with an Interface and using a custom button not the back button.
fragment life cycle is directly effected by the host's activity life cycle so you gotta take that in consideration anyway did you try to call the method in onPuase() or in onStart() in the fragment that you are heading for after pressing back ? if that didn't work try to reach the emulator back button from if (keyCode == KeyEvent.KEYCODE_BACK) or you can finish() the previous fragment or activity so the back button will get the user no where and create your own back button to redirect the user and replace the method in it using onClick() .
hope that will work for you good luck

Android Fragment, going back without recreating/reloading Fragment

I've seen quite a few questions on SO about Fragments and I still can't seem to figure out if what I want to do is possible, and more so if my design pattern is just flawed and I need to re-work the entire process. Basically, like most questions that have been asked, I have an ActionBar with NavigationTabs (using ActionBarSherlock), then within each Tab there is a FragementActivity and then the FragmentActivities push new Fragments when a row is selected (I'm trying to re-create an iOS Project in Android and it's just a basic Navigation based app with some tabs that can drill down into specific information). When I click the back button on the phone the previous Fragment is loaded but the Fragment re-creates itself (so the WebServices are called again for each view) and this isn't needed since the information won't change in a previous view when going backwards. So basically what I want to figure out is how do I setup my Fragments so that when I push the back button on the phone, the previous Fragment is just pulled up with the previous items already created. Below is my current code :
//This is from my FragmentActivity Class that contains the ActionBar and Tab Selection Control
#Override
public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) {
// TODO Auto-generated method stub
int selectedTab = tab.getPosition();
if (selectedTab == 0) {
SalesMainScreen salesScreen = new SalesMainScreen();
ft.replace(R.id.content, salesScreen);
}
else if (selectedTab == 1) {
ClientMainScreen clientScreen = new ClientMainScreen();
ft.replace(R.id.content, clientScreen);
}.....
//This is within the ClientMainScreen Fragment Class, which handles moving to the Detail Fragment
row.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//Do something if Row is clicked
try{
String selectedClientName = clientObject.getString("ClientName");
String selectedClientID = clientObject.getString("ClientID");
String selectedValue = clientObject.getString("ClientValue");
transaction = getFragmentManager().beginTransaction();
ClientDetailScreen detailScreen = new ClientDetailScreen();
detailScreen.clientID = selectedClientID;
detailScreen.clientName = selectedClientName;
detailScreen.clientValue = selectedValue;
int currentID = ((ViewGroup)getView().getParent()).getId();
transaction.replace(currentID,detailScreen);
transaction.addToBackStack(null);
transaction.commit();
}
catch (Exception e) {
e.printStackTrace();
}
}
});....
//And then this is the Client Detail Fragment, with the method being called to Call the Web Service and create thew (since what is displayed on this screen is dependent on what is found in the Web Service
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup group, Bundle saved) {
return inflater.inflate(R.layout.clientdetailscreen, group, false);
}
#Override
public void onActivityCreated (Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
//Setup Preferences File Link
this.preferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
//initialize the table object
mainTable = (TableLayout)getActivity().findViewById(R.id.mainTable);
//setup the detail table
setupRelatedClientSection();
}
The Client Detail Screen can then drill down one more time, using the same method as the Client Main Screen but when I go back from that new screen to the Detail Screen the seuptRelatedClientSection() method is called again and so the entire Fragment is rebuilt when really I just want to pull up a saved version of that screen. Is this possible with my current setup, or did I approach this the wrong way?
Try using fragementTransaction.add instead of replace
I believe that you are looking for show() and hide().
I think you can still add them to the backstack.
transaction.hide(currentFragment);
transaction.show(detailScreen);
transaction.addToBackStack(null);
transaction.commit();
I didnt have my code to look at but i believe this is how it would go... Try it out unless someone else has a better way.
I have not tried the backstack with show() hide() but i believe that it takes the changes that are made before the transactions commit and will undo them if the back button is pressed. Please get back to me on this cause i am interested to know.
You also have to make sure that the detail fragment is created before you call this. Since it is based on the click of someitem then you should probably create the details fragment every time you click to make sure the correct details fragment is created.
I'm posting this answer for people who may refer this question in future.
Following code will demonstrate how to open FragmentB from FragmentA and going back to FragmentA from FragmentB (without refreshing FragmentA) by pressing back button.
public class FragmentA extends Fragment{
...
void openFragmentB(){
FragmentManager fragmentManager =
getActivity().getSupportFragmentManager();
FragmentB fragmentB = FragmentB.newInstance();
if (fragmentB.isAdded()) {
return;
} else {
fragmentManager.
beginTransaction().
add(R.id.mainContainer,fragmentB).
addToBackStack(FragmentB.TAG).
commit();
}
}
}
public class FragmentB extends Fragment{
public static final String TAG =
FragmentB.class.getSimpleName();
...
public static FragmentB newInstance(){
FragmentB fragmentB = new FragmentB();
return fragmentB;
}
#Override
public void onResume() {
super.onResume();
// add this piece of code in onResume method
this.getView().setFocusableInTouchMode(true);
this.getView().requestFocus();
}
}
In your MainActivity override onBackPressed()
class MainActivity extends Activity{
...
#Override
public void onBackPressed() {
if (getFragmentManager().getBackStackEntryCount() > 0) {
getFragmentManager().popBackStack();
} else {
super.onBackPressed();
}
}
}
You're right, there has been a number of previous questions / documentation on the topic ;)
The documentation on Fragments, specifically the section about Transactions and Saving State, will guide you to the answer.
http://developer.android.com/guide/components/fragments.html#Transactions
http://developer.android.com/guide/components/activities.html#SavingActivityState
Android - Fragment onActivityResult avoid reloading
Fragments can have support for onSaveInstanceState but not onRestoreInstanceState, so if you want to save a reference to the table views, save them to the Bundle and you can access the saved view in your onActivityCreated method. You could also use the Fragments back stack.
This guide/tutorial has very detailed instructions/examples on the back stack and retaining fragment state.
Good luck

Android force Fragment to rebuild View

I have a simple app that has two fragments and when in landscape mode, both fragments are shown side by side and in portrait I show Fragment A and then if they select an option, start an Activity that shows Fragment B. My problem is when I am in Portrait mode and showing Fragment B, if the user selects a menu option I want to refresh or redraw the View that is associated with Fragment B and can’t understand how to make this work. I tried the getView method and getLayoutInflater method but the screen doesn’t change because I think I am creating a new view. I also tried to get a reference to Fragment A thinking I could call its routine to build a new fragment and replace Fragment B but can’t get a reference to it because it is not being displayed. What I really need to do is just force the onCreateView method to be called again to inflate the new view but I have tried several methods to try to do this but can’t get the onCreateView to be called again. Any thoughts on how to this?
You will want to perform a FragmentTransaction and use the replace() method
This shouldn't be too hard to do, but the answer will depend on where your Menu is located (i.e. is your onOptionsItemSelected() call back inside your parent Activity or is it in either Fragment A/B?).
Suppose for simplicity's sake, your menu implementation and onOptionsItemSelected() is in the parent activity, and you want to reshape the fragments in the event that menu_option1 is chosen. It would look something like this:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle item selection
//...
switch (item.getItemId()) {
case R.id.menu_option1:
//do something
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
Fragment newFragment = new YourFragmentClass();
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(R.id.your_fragment_id, newFragment);
transaction.addToBackStack(null);
transaction.commit();
return true;
case R.id.menu_option2:
//do something else;
return true;
default:
return super.onOptionsItemSelected(item);
}
}
Alternatively, if your menu is a child of one of your Fragments (which it should be for the sake of more reusable code), then one method is to require that host Activity to implement an interface defined by the Fragment, that can be used as a call back.
And in the onOptionsItemSelected() callback inside your fragment class, you simply make a call to this callback method.
Although it sounds like a mouthful, you only really need to do a couple of things. Pretend that this is your Fragment class
public static class FragmentA extends ListFragment {
OnSelectedListener mListener;
// Container Activity must implement this interface
public interface OnSelectedListener {
public void onSelected();
}
...
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
//This is to ensure that the Activity has implemented the interface we set up above
try {
mListener = (OnSelectedListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement OnSelectedListener");
}
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle item selection
//...
switch (item.getItemId()) {
case R.id.menu_option1:
//do something
getActivity().onSelected();
return true;
case R.id.menu_option2:
//do something else;
return true;
default:
return super.onOptionsItemSelected(item);
}
}
...
}
Then in the Activity, you would see something like:
public class MainActivity extends Activity implements FragmentA.onSelectedListener{
...
public void onSelected(){
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
Fragment newFragment = new YourFragmentClass();
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(R.id.your_fragment_id, newFragment);
transaction.addToBackStack(null);
transaction.commit();
}
}
if the user selects a menu option I want to refresh or redraw the View that is associated with Fragment B and can’t understand how to make this work
In onOptionsItemSelected(), have the activity call a method on the fragment that causes it to update its widgets with the new content. Or, have the activity execute a FragmentTransaction to replace the fragment (if the fragment was originally set up via a FragmentTransaction).

Categories

Resources