14

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()
    }
}
Tom
  • 717
  • 2
  • 6
  • 23
  • [See: Passing results between fragments](https://developer.android.com/guide/fragments/communicate#fragment-result) – Benny Sep 18 '22 at 16:02

2 Answers2

11

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)
Vikas Patidar
  • 42,865
  • 22
  • 93
  • 106
Saurabh Thorat
  • 18,131
  • 5
  • 53
  • 70
  • `setFragmentResultListener` is unresolved. I imagine I need to implement an interface? – Tom Nov 18 '20 at 02:41
  • 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](https://developer.android.com/reference/androidx/fragment/app/FragmentResultOwner) (new line doesn't show in comment, so I added \n where one should be) – Tom Nov 18 '20 at 03:09
  • 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. – Saurabh Thorat Nov 18 '20 at 04:47
  • 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. – Tom Nov 18 '20 at 05:30
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);