0

I have a dialog to select more than one days of a week as follows:

class DialogSettingsEnabledDays : DialogFragment() {
    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {

        return activity.let {

            val selectedDaysValue = BooleanArray(7) { _ -> false }
            val selectedDaysIndex = ArrayList<Int>()

            val daysToIndexMap = mutableMapOf<String, Int>()
            val indexToDaysMap = mutableMapOf<Int, String>()
            val daysArray = resources.getStringArray(R.array.days_medium)
            for (i in 0..6) {
                daysToIndexMap[daysArray[i]] = i
                indexToDaysMap[i] = daysArray[i]
            }

            val prefs = it!!.getSharedPreferences(getString(R.string.shared_prefs_settings), Context.MODE_PRIVATE)
            val selectedDaysString = prefs.getString("enabled_days", getString(R.string.default_enabled_days))
            val selectedDays = selectedDaysString!!.split(", ")

            for (day in selectedDays) {
                selectedDaysValue[daysToIndexMap.getValue(day)] = true
                selectedDaysIndex.add(daysToIndexMap.getValue(day))
            }

            val enabledDaysBuilder = AlertDialog.Builder(it)
            enabledDaysBuilder
                .setTitle(R.string.settings_enabled_days)
                .setMultiChoiceItems(R.array.days_long, selectedDaysValue) { _, which, isChecked ->
                    if (isChecked)
                        selectedDaysIndex.add(which)
                    else if (selectedDaysIndex.contains(which))
                        selectedDaysIndex.remove(Integer.valueOf(which))
                }
                .setPositiveButton(R.string.dialog_ok) { _, _ ->
                    if (selectedDaysIndex.isEmpty()) {
                        Toast.makeText(it, "Select atleast one day !!", Toast.LENGTH_SHORT).show()
                    } else {
                        selectedDaysIndex.sort()
                        val selectedDaysList = mutableListOf<String>()
                        for (i in selectedDaysIndex) {
                            selectedDaysList.add(indexToDaysMap.getValue(i))
                        }
                        val editor = prefs.edit()
                        editor
                            .putString("enabled_days", selectedDaysList.joinToString())
                            .apply()
                        val enabledDays = it.findViewById<LinearLayout>(R.id.settings_enabled_days)
                        enabledDays.findViewById<TextView>(R.id.secondary_text).text = selectedDaysList.joinToString()
                    }
                }
                .setNegativeButton(R.string.dialog_cancel) { _, _ -> /* do nothing */ }

            enabledDaysBuilder.create()
        }
    }
}

And I am calling this dialog in this way from my activity:

findViewById<LinearLayout>(R.id.settings_enabled_days)
    .setOnClickListener {
        DialogSettingsEnabledDays().show(this.supportFragmentManager, null)
}

My problem is that my selection of days resets to default on rotation. By default I mean the selection stored in SharedPreferences, that is selectedDaysValue in .setMultiChoiceItems. Suppose, these are the selected days when the dialog pops up:

Mon, Tue, Wed, Thu, Fri

Now, I change the selection as:

Mon, Tue

But, when I rotate the phone, the selection sets back to default:

Mon, Tue, Wed, Thu, Fri

How can I retain my selection on orientation change? Because in some apps I have seen, the Dialog selection remains same on rotation.

Akshdeep Singh
  • 1,301
  • 1
  • 19
  • 34

2 Answers2

1

Android system will automatically restore your fragment state, while the state changed fragment is not actually getting destroyed but only its view is recreated, so what ever value is inside your fragment variables will be kept as it is, all you have to do is reassign that variables value to your view, here's the reference link https://inthecheesefactory.com/blog/fragment-state-saving-best-practices/en

SSB
  • 996
  • 8
  • 9
  • Why in the Activity and not in the DialogFragment? – lelloman Jun 15 '19 at 08:55
  • can you give some more details on usage of `parcel`? – Akshdeep Singh Jun 15 '19 at 09:02
  • Refer this link for details on parcelable https://developer.android.com/reference/android/os/Parcelable – SSB Jun 15 '19 at 09:07
  • @lelloman as the question description clearly states that DialogFragment is visible and bound to the activity, so at this point activity will manage the state of the fragment so I gave solution based on activity only – SSB Jun 15 '19 at 09:20
  • What I mean is that DialogFragment has onSaveInstanceState method and the saved instance is passed to onCreateDialog, why is Activity needed here? – lelloman Jun 15 '19 at 09:30
  • why are you calling the superclass `super.onCreate(savedInstanceState)`, the code is working without it. You can see my answer. – Akshdeep Singh Jun 15 '19 at 09:49
  • @lelloman thanks for your inputs, I have edited my original answer and given the simplest solution I found, kindly look into it – SSB Jun 15 '19 at 10:55
  • @AkshdeepSingh You don't have to override onSaveInstanceState() it can be done easily without it also, I have edited my answer kindly look into it – SSB Jun 15 '19 at 10:57
  • Using onSaveInstanceState is correct, just not the one in the Activity but the one in DialogFragment, then the savedState is delivered to the DialogFragment in onCreateDialog. No need to override Activity's method, just the DialogFragment's one – lelloman Jun 15 '19 at 12:41
  • Yeah I know that's correct and I got your point but this is also other way around, both ways will work but I found way which I shared is easy to implement, anyway many thanks for your inputs – SSB Jun 15 '19 at 12:43
0

Well, this is the final solution I have made by making changes in the DialogFragment code only:

Changing the scope of data to be stored:

override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
    return activity.let {
        val selectedDaysValue = BooleanArray(7) { _ -> false }
        val selectedDaysIndex = ArrayList<Int>()

to:

private var selectedDaysValue = BooleanArray(7) { _ -> false }
private var selectedDaysIndex = ArrayList<Int>()

override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
    return activity.let {

Storing the data:

override fun onSaveInstanceState(outState: Bundle) {
    outState.putBooleanArray("selected_days_value", this.selectedDaysValue)
    outState.putIntegerArrayList("selected_days_index", this.selectedDaysIndex)
}

And where I read the data as:

val prefs = it!!.getSharedPreferences(getString(R.string.shared_prefs_settings), Context.MODE_PRIVATE)
val selectedDaysString = prefs.getString("enabled_days", getString(R.string.default_enabled_days))
val selectedDays = selectedDaysString!!.split(", ")

for (day in selectedDays) {
    selectedDaysValue[daysToIndexMap.getValue(day)] = true
    selectedDaysIndex.add(daysToIndexMap.getValue(day))
}

to read from saved state as:

val prefs = activity!!.getSharedPreferences(getString(R.string.shared_prefs_settings), Context.MODE_PRIVATE)
if (savedInstanceState == null) {
    val selectedDaysString = prefs.getString("enabled_days", getString(R.string.default_enabled_days))
    val selectedDays = selectedDaysString!!.split(", ")

    for (day in selectedDays) {
        selectedDaysValue[daysToIndexMap.getValue(day)] = true
        selectedDaysIndex.add(daysToIndexMap.getValue(day))
    }
} else {
    with(savedInstanceState) {
        selectedDaysValue = getBooleanArray("selected_days_value")!!
        selectedDaysIndex = getIntegerArrayList("selected_days_index")!!
    }
}
Akshdeep Singh
  • 1,301
  • 1
  • 19
  • 34