Pass data/bundle using navigateUp in Android Navigation Component

前端 未结 6 1113
予麋鹿
予麋鹿 2020-12-14 09:51

I found the question but does not have solution in code

I want to have data when backpress/manual back happens. I am using navigateUp() to go back. How

相关标签:
6条回答
  • 2020-12-14 10:13

    You should use static variables/companion objects, because it is better than shared viewmodel as it is not simple/nice architecture. As it it not straightforward, I think it is the best way.

    To navigateUp From FragmentB to FragmentA

    FragmentB:

    isBackpressed = true
    findNavController().navigateUp() 
    

    FragmentA:

    onViewCreated() {
        // todo
        if(isBackpressed) {
             isBackpressed = false
             // do whatever you want
        }
    }
    
    0 讨论(0)
  • 2020-12-14 10:17

    According to developer.android.com, you can use common for fragments where you want to share data ViewModel using their activity scope.

    Here are steps:

    1. Create view model which will keep the data:
    class SharedViewModel : ViewModel() {
        val dataToShare = MutableLiveData<String>()
    
        fun updateData(data: String) {
            dataToShare.value = data
        }
    }
    
    1. Observe data changes in Fragment1:
    class Fragment1 : Fragment() {
    
        private lateinit var viewModel: SharedViewModel
    
        override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
            super.onViewCreated(view, savedInstanceState)
            viewModel = ViewModelProviders.of(activity!!).get(SharedViewModel::class.java)
            viewModel.dataToShare.observe(this, Observer<String> { dataFromFragment2 ->
                // do something with data
            })
        }
    }
    
    1. Update data in Fragment2 and if you're handling navigation properly, now, you should be able to receive data changes on Fragment1:
    class Fragment2 : Fragment() {
    
        private lateinit var viewModel: SharedViewModel
    
        override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
            super.onViewCreated(view, savedInstanceState)
            viewModel = ViewModelProviders.of(activity!!).get(SharedViewModel::class.java)
    
            updateDataButton.setOnClickListener { v ->
                viewModel.updateData("New data for fragment1")
            }
        }
    }
    

    I hope answer helps.

    0 讨论(0)
  • 2020-12-14 10:17

    You can use NavigationResult library. Basically it's startActivityForResult but for Fragments in Navigation component.

    0 讨论(0)
  • 2020-12-14 10:22

    You can just call

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

    where args is your bundle. In fragment1, fetch the data from the arguments

    0 讨论(0)
  • 2020-12-14 10:27

    You can use the following simple implementation to pass data after popBackStack() with Android Navigation Component. This approach is based on official Google documentation

    You just need to extend your fragments with BaseFragment and use the following methods:

    //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. Add SharedViewModel class

      class SharedViewModel : ViewModel() {
          val sharedData = MutableLiveData<Any>()
      
          fun share(obj: Any) {
              sharedData.value = obj
          }
      }
      
    2. Add BaseFragment class

      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. Add Fragment1

      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. Add Fragment2

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

    Cheers ;)

    0 讨论(0)
  • 2020-12-14 10:28

    To pop destinations when navigating from one destination to another, add an app:popUpTo attribute to the associated <action> element. To navigate from fargment2 to Fragment1 with arguments, specify in the navigation graph the action of the caller fragment and the arguments of the destination fragment :

    <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>
    

    In your Fragment2 class, you call your action and pass your argument:

       val action = Fragment2Directions.action2To1("MY_STRING_ARGUMENT")
            findNavController().navigate(action)
    
    0 讨论(0)
提交回复
热议问题