How to replace setTargetFragment() now that it is deprecated
Asked Answered
J

3

15

setTargetFragment() is deprecated in Java, and I don't understand the correct replacement for it as android documentation uses it and is outdated. I believe the FragmentManager is the correct replacement for it. I am using the deprecated setTargetFragment function in my settings Preferences to create multiple preference screens. To do so, I originally followed the guide here which confusingly uses setTargetFragment in the example. Below is my code:

build.gradle (Module: app)
...
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
implementation 'androidx.preference:preference:1.1.1'
...
MainActivity.kt

class MainActivity : AppCompatActivity() {
    private lateinit var settingsButton: ImageButton

    override fun onCreate(savedInstanceState: Bundle?) {
        ...
        settingsButton = findViewById(R.id.settingsButtonMain)
        settingsButton.setOnClickListener {
            settingsClicked()
        }
        ...
    }

    private fun settingsClicked() {
        val settingsIntent = Intent(this, SettingsActivity::class.java)
        startActivity(settingsIntent)
    }
}
SettingsActivity.kt

class SettingsActivity : AppCompatActivity(), PreferenceFragmentCompat.OnPreferenceStartFragmentCallback {
    override fun onCreate(savedInstanceState: Bundle?) {
        ...
        supportFragmentManager.beginTransaction().replace(R.id.settings, SettingsFragment(this)).commit()
        supportFragmentManager.addOnBackStackChangedListener {
            if(supportFragmentManager.backStackEntryCount == 0) {
                title = "App Settings"
            }
        }
        supportActionBar?.setDisplayHomeAsUpEnabled(true)
        ...
    }

    class SettingsFragment(cont: Context) : PreferenceFragmentCompat() {
        private var context1: Context = cont

        override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
            setPreferencesFromResource(R.xml.root_preferences, rootKey)
        }
    }

    class Screen2PreferencesFragment : PreferenceFragmentCompat() {
        override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
            setPreferencesFromResource(R.xml.screen2_preferences, null)
        }
    }

    override fun onPreferenceStartFragment(caller: PreferenceFragmentCompat?, pref: Preference): Boolean {
        val args: Bundle = pref.extras
        val fragment: Fragment = supportFragmentManager.fragmentFactory.instantiate(classLoader, pref.fragment)
        fragment.arguments = args
        fragment.setTargetFragment(caller, 0) //TROUBLE AREA. WHAT IS THE CORRECT REPLACEMENT HERE?
        supportFragmentManager.beginTransaction().replace(R.id.settings, fragment).addToBackStack(null).commit()
        return true
    }

    override fun onSupportNavigateUp(): Boolean {
        if(supportFragmentManager.popBackStackImmediate()) {
            return true
        }
        return super.onSupportNavigateUp()
    }
}
Jersey answered 17/11, 2020 at 4:48 Comment(1)
See: Passing results between fragmentsEncyclopedist
I
12

Include this dependency:

implementation 'androidx.fragment:fragment-ktx:1.3.0-beta01'

Use setFragmentResultListener instead of setTargetFragment():

override fun onPreferenceStartFragment(caller: PreferenceFragmentCompat?, pref: Preference): Boolean {
    val args: Bundle = pref.extras
    val fragment: Fragment = supportFragmentManager.fragmentFactory.instantiate(classLoader, pref.fragment)
    fragment.arguments = args
    supportFragmentManager.beginTransaction().replace(R.id.settings, fragment).addToBackStack(null).commit()
    
    supportFragmentManager.setFragmentResultListener("requestKey") { key, bundle ->
        if (key == "requestKey") {
            // Get result from bundle
        }
    }
    
    return true
}

And in your fragment that returns a result:

// Insert result in a bundle
setFragmentResult("requestKey", bundle)
Isaiah answered 17/11, 2020 at 5:19 Comment(4)
setFragmentResultListener is unresolved. I imagine I need to implement an interface?Jersey
I think I figured it out. Correct me if I am wrong. setFragmentResultListener should actually look like this val result = "result" \n setFragmentResult("requestKey", bundleOf("bundleKey" to result)) \n FragmentResultOwner needs to be implemented and override the classes here (new line doesn't show in comment, so I added \n where one should be)Jersey
If it's unresolved, add import androidx.fragment.app.setFragmentResultListener. Create a bundle using bundleOf("bundleKey" to result) and add it as a param to setFragmentResult() like it's shown in the answer.Isaiah
From my testing, this definitely needs 'FragmentResultOwner' implemented. It does not work without or with just the suggested import (which appears to be invalid). I appreciate the help.Jersey
Z
0

For the unresolved issue when trying to use setFragmentResult referring to the answer above, you could try using the fragmentManager as follows.

This is for Xamarin:

ParentFragmentManager.SetFragmentResult("requestKey", bundle);
Zaratite answered 17/9, 2021 at 8:41 Comment(0)
A
0

JANUARY 2024

I replaced setTargetFragment with setFragmentResultListener in two DialogFragments (parent and child) and code below is based on that. I think for the ordinary fragments it works the same way.

Gradle:

implementation 'androidx.fragment:fragment-ktx:1.6.2'

onCreateDialog in parent DialogFragment:

Set FragmentResultListener for parentFragmentManager. Remember to launch child fragment using the same fragment manager!

...
parentFragmentManager.setFragmentResultListener("requestKey", this) { key, bundle ->
    val result = bundle.getString("myKey")
    //result is a string passed by child fragment
}

binding.someButton.setOnClickListener {
    val dialog = ChildDialogFragment()
    dialog.show(parentFragmentManager, "someTag")
}
...

Child DialogFragment:

I will pass String value to parent fragment on button click.

binding.someOtherButton.setOnClickListener {
    val stringToPass = "blablabla"
    val bundle = Bundle().apply {
        putString("myKey", result)
    }
    parentFragmentManager.setFragmentResult("requestKey", bundle)
}

Enjoy!

Adventuresome answered 26/1 at 8:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.