Передайте данные / пакет, используя navigateUp в Android Navigation Component

Я нашел вопрос, но не нашел решения в коде

Я хочу получить данные, когда происходит обратное нажатие / ручное возвращение. я использую navigateUp() идти обратно. Как я могу передать данные в предыдущий фрагмент? navigateUp() не имеет возможности передавать данные в предыдущий фрагмент. Даже я не нашел решения с помощью Safe Args. Это передача данных вперед. Я хочу иметь в обратном Frad B -> Frag A.

Мой код, чтобы вернуться к предыдущему фрагменту

Navigation.findNavController(view).navigateUp()

У меня вопрос, как я могу получить данные в предыдущем фрагменте. Я могу перейти к Frag A из Frag B, используя

7 ответов

Согласно developer.android.com, вы можете использовать общие для фрагментов, где вы хотите поделиться данными ViewModel, используя их область действия.

Вот шаги:

  1. Создайте модель представления, которая будет хранить данные:
class SharedViewModel : ViewModel() {
    val dataToShare = MutableLiveData<String>()

    fun updateData(data: String) {
        dataToShare.value = data
    }
}
  1. Наблюдайте за изменениями данных в Fragment1:
class Fragment1 : Fragment() {

    private lateinit var viewModel: SharedViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        viewModel = ViewModelProviders.of(activity!!).get(SharedViewModel::class.java)
        model.dataToShare.observe(this, Observer<String> { dataFromFragment2 ->
            // do something with data
        })
    }
}
  1. Обновить данные в Fragment2 и если вы обрабатываете навигацию правильно, теперь вы сможете получать изменения данных на Fragment1:
class Fragment2 : Fragment() {

    private lateinit var viewModel: SharedViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        viewModel = ViewModelProviders.of(activity!!).get(SharedViewModel::class.java)

        updateDataButton.setOnClickListener { v ->
            viewModel.updateData("New data for fragment1")
        }
    }
}

Надеюсь, ответ поможет.

Вы можете использовать методы setFragmentResultListener () и setFragmentResult() из androidx:

      implementation "androidx.fragment:fragment-ktx:1.3.3"

Ваше здоровье ;)

Вы можете использовать библиотеку NavigationResult. В основном этоstartActivityForResult но для компонента "Фрагменты в навигации".

Чтобы показывать пункты назначения при переходе от одного пункта назначения к другому, добавьте app:popUpTo атрибут связанного <action>элемент. Чтобы перейти от fargment2 к Fragment1 с аргументами, укажите в графе навигации action фрагмента вызывающего абонента и arguments целевого фрагмента:

<fragment
    android:id="@+id/fragment2"
    android:name="com.example.myapplication.Fragment2"
    android:label="fragment_2"
    tools:layout="@layout/fragment_2">

    <action
        android:id="@+id/action_2_to_1"
        app:destination="@id/fragment1"
        app:popUpTo="@+id/fragment1"/>
</fragment>
<fragment
    android:id="@+id/fragment1"
    android:name="com.example.myapplication.Fragment1"
    android:label="fragment_1"
    tools:layout="@layout/fragment_1">

        <argument
            android:name="someArgument"
            app:argType="string"
            app:nullable="false"
            android:defaultValue="Hello Word"/>
</fragment>

В вашем классе Fragment2 вы вызываете свое действие и передаете свой аргумент:

   val action = Fragment2Directions.action2To1("MY_STRING_ARGUMENT")
        findNavController().navigate(action)

Вы должны использовать статические переменные / сопутствующие объекты, потому что это лучше, чем общая модель просмотра, поскольку это не простая / красивая архитектура. Поскольку это непросто, я думаю, что это лучший способ.

Переход от фрагмента B к фрагменту A

Фрагмент B:

isBackpressed = true
findNavController().navigateUp() 

Фрагмент A:

onViewCreated() {
    // todo
    if(isBackpressed) {
         isBackpressed = false
         // do whatever you want
    }
}

Вы можете просто позвонить

findNavController().navigate(R.id.fragment1, args)

где args - ваш пакет. Во фрагменте 1 выберите данные из аргументов

Вы можете использовать следующую простую реализацию для передачи данных после popBackStack() с помощью компонента навигации Android. Этот подход основан на официальной документации Google.

Вам просто нужно расширить свои фрагменты с помощью BaseFragment и использовать следующие методы:

//to start Fragment2 for result
startFragmentForResult(actionId: Int)

//to perform pop back stack in Fragment2
popBackStackWithResult(result: Any)

//to observe your result in Fragment1
onFragmentResult(result: Any)
  1. Добавить класс SharedViewModel

    class SharedViewModel : ViewModel() {
        val sharedData = MutableLiveData<Any>()
    
        fun share(obj: Any) {
            sharedData.value = obj
        }
    }
    
  2. Добавить класс BaseFragment

    import androidx.fragment.app.Fragment
    
    abstract class BaseFragment : Fragment() {
    
    protected var rootView: View? = null
    
    private var sharedViewModel: SharedViewModel? = null
    
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        if (rootView == null) {
            rootView = inflater.inflate(getLayoutId(), container, false)
            initSharedViewModel()
        }
        return rootView
    }
    
    abstract fun getLayoutId()
    
    open fun onFragmentResult(result: Any){
        //TODO implement in descendants
    }
    
    protected fun startFragmentForResult(actionId: Int){
        findNavController().navigate(actionId)
    }
    
    protected fun popBackStackWithResult(result: Any){
        findNavController().popBackStack()
        sharedViewModel?.share(result)
    }
    
    private fun initSharedViewModel() {
        sharedViewModel = ViewModelProvider(activity!!).get(SharedViewModel::class.java)
    
        sharedViewModel?.sharedData?.observe(activity!!, object : Observer<Any> {
            override fun onChanged(params: Any) {
                onFragmentResult(params)
            }
        })
    }    
    }
    
  3. Добавить фрагмент1

    class Fragment1 : BaseFragment(){
        override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
            super.onViewCreated(view, savedInstanceState)
    
            some_btn.setOnClickListener{
                startFragmentForResult(R.id.action_fragment1_to_fragment2)
            }
        }
    
        override fun onFragmentResult(result: Any) {
            if(result is AnyYourClass){
                //PERFECT! DO SOMETHING WITH YOUR RESULT
            }
        }
    }
    
  4. Добавить фрагмент 2

    class Fragment2 : BaseFragment(){
        override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
            super.onViewCreated(view, savedInstanceState)
    
            some_btn.setOnClickListener{
                popBackStackWithResult(AnyYourClass())
            }
        }            
    }
    

Ура;)

Другие вопросы по тегам