I am trying to pass data from dialog destination to fragment. But it is not getting called If I try the same consecutively. For single try it works fine.
Below is my code that is in my dialog fragment:
val navBackStackEntry = findNavController().getBackStackEntry(R.id.fragment_name)
onClick of button I am doing this
navBackStackEntry.savedStateHandle.set(ConstantUtils.SAVED_DATE, "")
dismiss()
In fragment's onResume I am observing the data like below:
val savedStateHandle = findNavController().currentBackStackEntry?.savedStateHandle
savedStateHandle?.getLiveData<String>(ConstantUtils.SAVED_DATE)?.observe(viewLifecycleOwner,
Observer { date ->
//Code goes here
savedStateHandle.remove<String>(ConstantUtils.SAVED_DATE)
})
When I click the button from dialog it comes to onResume of fragment, If I again go to the dialog and click on button it does not return to onResume of fragment.
Pleas let me know what mistake am I making here.
If you want to pass argument to fragment and receive one, you can use setFragmentResult() function can pass and receive bundle between fragments.
This is source link for more study
https://developer.android.com/guide/fragments/communicate#fragment-result
Related
Im using Navigation Component which navigates between fragments using findNavController().navigate(). I want to retrieve the currently displayed fragment in FragmentContainerView from MainActivity as I want to modify the "Edit" button setOnClickListener function to perform "Save" function (I already know how to change the text from Edit to Save) where it checks currently displayed fragment and change the setOnClickListener function accordingly. So in that particular fragment, it will perform "Save" function. But how do I get the currently displayed fragment from MainActivity?
I saw alot other solution but they are all using FragmentTransaction or they just show the code which get the current Fragment but they didn't show in which part of MainActivity will initiate the code which gets the current Fragment. Any help? Im using Kotlin.
You could add a OnDestinationChangedListener to the NavController inside you MainActivity
navController.addOnDestinationChangedListener { _, destination, _ ->
if(destination.id == R.id.your_savable_fragment) {
button.text = "Save"
//....
}
if(destination.id == R.id.your_editable_fragment) {
button.text = "Edit"
//....
}
}
I am searching for postSticky() method replacement. It is being used for simple passing value to previous Fragment, but thing is that I am using BackStackUtil for navigation so instance() method is being called when returning only if stack gets cleared somehow before getting back.Previous Fragment is holding List of items, when next Fragment can modify picked item and yet another one can do something else so it is chain of sticky events when each of these is being passed to previous Fragment. App structure won't let me to apply Coordinator pattern at current stage and also I don't want to attach Bundle to Fragments kept on stack. I was looking for solutions but I couldn't find any. I also don't want to store values in some static fields or SharedPreferences/Data storage.I was thinking about shared ViewModel but I don't really like this idea to be honest, so I would appreciate any ideas or just confirmation if shared VM is the only/best way.
Do you have any other ideas?
In your A fragment, before navigating to B fragment, listen to savedStateHandle:
findNavController()
.currentBackStackEntry
?.savedStateHandle?.getLiveData<Bundle>("DATA_KEY")
?.observe(viewLifecycleOwner) { result ->
// Result from fragment B
}
In your B fragment, before navigating back, set the data to pass to A fragment:
findNavController()
.previousBackStackEntry
?.savedStateHandle
?.set("DATA_KEY", result)
You can remove the observer using:
findNavController()
.currentBackStackEntry
?.savedStateHandle?.remove<Bundle>
Note that here the passed type is Bundle (the type in getLiveData<Bundle>) but you can use any type you want.
When I change the fragment and return to the one that was at the beginning, running a line I get the error Fragment not attached to an activity. It is strange because before I get to this line, I use requireAcitivity() and it works fine. The error appears after calling an ArrayAdapter custom
When I call the arrayadapter, the requiredActivity method still works:
val adapter = ListUserGameInfoAdapter(requireContext(), gameViewModel!!)
gameInfoListUsers.adapter = adapter
Each row of the list created by the arrayAdapter has a button.
icon.setOnClickListener {
gameViewModel.userToDeleteFromGamePositionLiveData.value = position
}
The button changes the value of a LiveData of the viewModel. By using an observer I pick up this new value of the LiveData. Inside the code of the observer, if I call requiredActivity(), the following error appears
val userToDeleteObserver = Observer<Int> {
if (it != null) {
//If I call requiredActivity here, I get the error Fragment not attached to an activity
showDialog(it)
}
}
gameViewModel!!.userToDeleteFromGamePositionLiveData.observe(
requireActivity(),
userToDeleteObserver
)
The strange thing is that the first time I enter this fragment the error does not appear, only when I go to another one and come back to this one.
You're adding an observer in your fragment, but tying it to the lifecycle of your activity. Therefore it will keep observing for changes even when the fragment has been destroyed, which is why you're getting a crash when calling requireActivity() in your observer.
If you do some debugging, you'll probably notice that the observer is actually triggering twice, once for the old fragment (no longer attached to an activity) and once for the new fragment.
You should be using Fragment.getViewLifecycleOwner() instead.
The code is in the Android Studio template.
Android Studio - Create new project - Navigation Drawer Activity
There are an Activity and three Fragments (HomeFragment, GalleryFragment, SlideshowFragment) in the template project. I use an AppBarConfiguration object to manage three Fragment. Now I create a function in each Fragment.
My title may be a bit vague. My problem is how to execute the method in the current fragment by clicking the button in Activity.
Now my solution is as follows.
In each fragment. Get the activity object and find the button. Then set the click method. Here is my Kotlin code.
activity?.findViewById<FloatingActionButton>(R.id.fab)?.setOnClickListener { view ->
myFunction()
}
It works fine. But I think this is not elegant enough. And there are some problems with this. If I only set the click event of one fragment, when I switch to another fragment, the click event just now will be executed after I click the button.
I guess the reason for the above problem is that the click event of the activity is bound by the fragment.
My other solution is as follows.
Create an ActivityViewModel and set a LiveData value. Change value after clicking the button. Get ActivityViewModel in fragment and observe the value in each fragment. Then execute the method when the value is changed
My third solution is as follows.
Get each fragment object and determine whether it is visible. Then perform the function of the visible fragment. Here is my Kotlin code.
val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment)
var fragment1 = navHostFragment!!.childFragmentManager.fragments[0] as HomeFragment
var fragment2 = navHostFragment!!.childFragmentManager.fragments[1] as GalleryFragment
var fragment3 = navHostFragment!!.childFragmentManager.fragments[2] as SlideshowFragment
if(fragment1.isVisiable){
fragment1.myFunction()
}else if(fragment2.isVisiable){
fragment2.myFunction()
}else if(fragment3.isVisiable){
fragment3.myFunction()
}
But I still think the methods above are not elegant enough.
Can I use the interface to achieve the above functions? And how to achieve it?
I am not a native English speaker. Sorry for my bad English.
Thanks.
I have two fragments in app. When user launch the app, in main layout fragment container shows first fragment, when user click on the button, second fragment replaces first fragment.
I want to do this: when app launch, in second fragment loading some text from the GET url request. And when user click on button to show seecond fragment, all text has already been loaded.
How can I do this ?
Maybe, make function "loadContent" in second fragment and when app launches call this function..
Is anybody have any ideas/info about this, please provide me^)
Make the GET call in Activity's onCreate method. Define your own interface which has an abstract getter. Implement the interface on Activity, and override the getter to return GET response.
In fragment onAttach(Activity) initialize interface like :
Interface callback = new Interface(activity);
now get the data, anywhere in fragment lifecycle after onAttach, from callback object like :
callback.getterFunction();