Question

I have a inner PreferenceScreen (call it Users) inside another PreferenceScreen (call it Main).
When i tap Users a new screen opens and I can change my Preferences there (a lot of CheckBoxes).
I want to detect (fire a callback) when this screen is dismissed and when I'm back on the Main PreferenceScreen.
The only way I found is to create a new class inheriting PreferenceScreen and overloading onPrepareForRemoval

I was wondering if there is a simpler way to do that.

Was it helpful?

Solution

Very interesting question! I finally figured out.

The trick is to set DialogInterface.OnCancelListener for the PreferenceScreen submenu (Users, in our case) and you can do it in onPreferenceTreeClick (as here internal Dialog is already initialized). So void onCancel(DialogInterface dialog) is the callback you've been looking for.

Here's the xml\preferences.xml:

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:key="main">
    <EditTextPreference android:title="Your Name"
        android:key="username"
        android:summary="Please provide your username"/>
    <PreferenceScreen
        android:key="users"
        android:title="Users"
        android:summary="Click here to select users">
        <CheckBoxPreference
            android:title="User 1"
            android:defaultValue="false"
            android:key="user1CheckBox" />
        <CheckBoxPreference
            android:title="User 2"
            android:defaultValue="false"
            android:key="user2CheckBox" />
        <CheckBoxPreference
            android:title="User 3"
            android:defaultValue="false"
            android:key="user3CheckBox" />
    </PreferenceScreen>
</PreferenceScreen>

Here's the PreferenceActivity and PreferenceFragment I used:

public class MyPreferencesActivity extends PreferenceActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getFragmentManager().beginTransaction().replace(android.R.id.content, new MainPreferenceFragment()).commit();
    }

    public static class MainPreferenceFragment extends PreferenceFragment {
        @Override
        public void onCreate(final Bundle savedInstanceState)
        {
            super.onCreate(savedInstanceState);
            addPreferencesFromResource(R.xml.preferences);
        }

        @Override
        public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
            if (preference instanceof PreferenceScreen) {
                PreferenceScreen submenu = (PreferenceScreen)preference;
                submenu.getDialog().setOnCancelListener(new DialogInterface.OnCancelListener() {
                    @Override
                    public void onCancel(DialogInterface dialog) {
                        Log.d("MainPreferenceFragment", "Hi! Submenu is closing now!");
                    }
                });
            }

            return super.onPreferenceTreeClick(preferenceScreen, preference);
        }
    }
}

UPD: Solution for PreferenceFragmentCompat:

First, we need one more xml: xml\subpreference.xml (duplicate of the submenu from the main preference.xml):

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.preference.PreferenceScreen
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:key="users"
    android:title="Users"
    android:summary="Click here to select users">
    <CheckBoxPreference
        android:title="User 1"
        android:defaultValue="false"
        android:key="user1CheckBox" />
    <CheckBoxPreference
        android:title="User 2"
        android:defaultValue="false"
        android:key="user2CheckBox" />
    <CheckBoxPreference
        android:title="User 3"
        android:defaultValue="false"
        android:key="user3CheckBox" />
</android.support.v7.preference.PreferenceScreen>

Then, our hosting activity should implements PreferenceFragmentCompat.OnPreferenceStartScreenCallback. And last step - we need a new subfragment (or pass exact XML you need to inflate as a bundle's parameter):

public class MainActivity extends AppCompatActivity implements PreferenceFragmentCompat.OnPreferenceStartScreenCallback{

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        getSupportFragmentManager().beginTransaction().replace(R.id.container, new MainPreferenceFragment()).commit();
    }

    @Override
    public boolean onPreferenceStartScreen(PreferenceFragmentCompat preferenceFragmentCompat,
                                           PreferenceScreen preferenceScreen) {
        getSupportFragmentManager().beginTransaction().replace(R.id.container, new SubPreferenceFragment()).commit();
        return true;
    }

    @Override
    public void onBackPressed() {
        super.onBackPressed();
    }

    public static class MainPreferenceFragment extends PreferenceFragmentCompat {
        @Override
        public void onCreatePreferences(Bundle bundle, String s) {
            addPreferencesFromResource(R.xml.preferences);
        }
    }

    public static class SubPreferenceFragment extends PreferenceFragmentCompat {
        @Override
        public void onCreatePreferences(Bundle bundle, String s) {
            addPreferencesFromResource(R.xml.sub_preferences);
        }
    }
}

It this case, you can just listen to normal onBackPressed() of Activity

I hope, it helps

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top