slellis
slellis

Reputation: 3703

Controlling back button inside Fragment

I have programming experience, but not much in Android. I think, on any platform, we can not allow the user leave the screen without the data is saved. We also have to ensure that the data is correct before saving.

In Android, I could not find an effective way to implement this scenario using Fragments

Let's consider an app containing 1 Activity called A1 which controls 3 Fragments F1, F2 and F3.

F1 and F2 are accessed via NavigationDrawer.

F3 is called by F2 when the user wants to enter data in the database. F3 has several EditTexts and other views, so that would not be a good idea to leave F3 without alerting the user that he may lose everything.

In Toolbar there is a menu item that lets the user save the data and return to F2.

I would like to control the back button in order to prevent the user forget to save data or that I had a way to send a message (Toast) to the user, if you have any errors in information data.

Do this by using only Activities is possible, but is not a solution, because I'm using NavigationDrawer.

As far as I know, onBackPressed is an Activity callback and is not intercepted by the Fragment.

In short:

I would like to stay in the Fragment F3 until the user correct all the errors and save the data. In case of he/she tap the back button without save, an AlertDialog be sent to him/her.

Anybody did something like that? What is the best pratice to do data consistency in Android?

Thanks in advance for any help.

Upvotes: 1

Views: 492

Answers (3)

Dan Hulme
Dan Hulme

Reputation: 15280

Best practice is to save the data whenever the user navigates away from that screen, regardless of whether the data pass validation or not. This may mean you have to save it in a special way, as an incomplete form or record.

Then, give the user a button (such as a "done" action button) to finally confirm the form entry is complete. Validate the data at this point. If you don't do this, and you drop the incomplete data as you suggest, the user won't be able to switch to another app to look up data they may need to enter in the form.

A good example is in the Gmail application. If you are composing an email and navigate away from that screen (e.g. to look at some other data), it doesn't warn you that it's going to lose your data, it just saves your email as a draft. This happens even if your email is missing mandatory data (the to address). You can switch back and forth as many times as you like until the email is complete.

You don't need to hook the back button specifically in order to do this: you can just save the data in onPause, and probably Toast the user to reassure them you've done it. "Committing" the data (sending the email, or applying the form changes) should remove the draft data, and this is just a normal button onClick.

Since the "design" pages on the Android Developer site shifted to being about "Material Design", they don't seem to have their UX tips any more, but "Never lose my stuff" used to be one of the key principles. I also found the Gmail example in the WayBackMachine's archive of the design pages.

Upvotes: 3

PPartisan
PPartisan

Reputation: 8231

F3 is called by F2 when the user wants to enter data in the database. F3 has several EditTexts and other views, so that would not be a good idea to leave F3 without alerting the user that he may lose everything.

Have you considered backing up any data inside onPause() (or onDestroy() even) of your Fragment? You can then store any information inside your EditText (perhaps to SharedPreferences), and then restore it when your Fragment restarts if it is destroyed.

That aside, you could create an interface (i.e. BackPressObserver) and have any Fragment you want to react to back presses implement it.

public interface BackPressObserver {

    boolean isReadyToInterceptBackPress();
    void onBackPress();

}

Fragment One

public class FragmentOne extends Fragment implements BackPressObserver {

    @Override
    public boolean isReadyToInterceptBackPress() {
        return this.isVisible() && 
            //**Another condition, i.e. !editText.getText().toString().isEmpty();**
    }

    @Override
    public void onBackPress() {
        //Do whatever needs to be done on a back press. When finished, make sure isReadyToInterceptBackPress() will return false.
    }

}

Activity

public class MainActivity extends AppCompatActivity {

    @Override 
    public void onBackPressed() {

        for (Fragment fragment : getSupportFragmentManager().getFragments()) {
            if (fragment instanceof BackPressObserver) {
                BackPressObserver observer = (BackPressObserver) fragment;
                if (observer.isReadyToInterceptBackPress()) {
                    observer.onBackPress();
                    return;
                }
            }
        }

        super.onBackPressed();

    }

}

Upvotes: 2

drew
drew

Reputation: 319

You can try this. Inside your activity you can check which fragment is currently showing. If it is the one you want, do your intended action.

Inside your activity put

@Override
public void onBackPressed() {
Fragment currentFragment = getActivity().getFragmentManager().findFragmentById(R.id.fragment_container);

   if (currentFragment instanceof "NAME OF YOUR FRAGMENT CLASS") {
      //Do what you want

   return;
   }
   //Otherwise, react normally
   super.onBackPressed();
}

You could also try adding this to your Fragment. It is simply adding a keylistener

getView().setOnKeyListener( new OnKeyListener()
{
    @Override
    public boolean onKey( View v, int keyCode, KeyEvent event )
    {
        if( keyCode == KeyEvent.KEYCODE_BACK )
        {
            return true;
        }
        return false;
    }
} );

Let me know if this works!

Upvotes: 1

Related Questions