Espresso: Not able to launch inner fragment - android

I am using launchFragmentInContainer<FragmentOne>() to launch fragment and able to perform actions using EspressoMatchers, it's all working fine.
But the issue comes when I want to launch another fragment onClick Of button(this code is inside FragmentOne) but while launching getting an error for FragmentTwo
Example:
onClick {
val fragment = FragmentTwo.newInstance()
val transaction = requireActivity().supportFragmentManager.beginTransaction()
transaction.add(fragmentContainerID, fragment)
transaction.commit()
}
Above code giving error java.lang.IllegalArgumentException: No view found for id 0x4d2 (unknown) for fragment FragmentTwo{bc39d06} (6f4636b5-f441-4e38-956a-47ac91d261bc) id=0x4d2}
How to resolve this inside fragment? or I have to do something in espresso test.

This issue is coming due to fragmentContainerID which should be unique and used under the hood of launchFragmentInContainer().
So, inside the espresso framework android.R.id.content is used as a fragment Id. This same id should be used while the fragment transaction.
Code Snippet:
var fragmentContainerID = android.R.id.content // It will do the trick and fragment will be added on top of stack

Related

android two fragment in one activity update ui issues

I have an issue that I have an activity include in the initial one fragment shown in it ad works fine it receive keep receive data and update it's ui, but once I add the second fragment to the activity seems like the second one freeze the previous one from updating or receiving anything. have any one an idea about this issue ?
im using this function to add fragment ->
fun setFragment(fragment: Fragment, fragmentManager: FragmentManager, fragmentId: Int) {
val fragmentTransaction: FragmentTransaction =
fragmentManager.beginTransaction().setReorderingAllowed(true)
fragmentTransaction.replace(fragmentId, fragment).setTransition(TRANSIT_FRAGMENT_FADE)
fragmentTransaction.commit()
}

Call different Fragment function in Activity in Android

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.

Android: How do I trigger an event once a fragment is totally loaded?

I am trying to load initial data onto a fragment in my application. In the following lines of code (located at the very end of onCreate, I attempt retrieve the fragment and load data onto it:
// Display the current list of matches to the user
var eventsFragment: EventsFragment =
supportFragmentManager.findFragmentByTag("eventsFragment") as EventsFragment
eventsFragment.displaySchedule(currList)
However, I receive the following error:
Caused by: kotlin.TypeCastException: null cannot be cast to non-null
type com.example.alarmfornbamatches.ui.main.EventsFragment
My guess is that the fragment hasn't loaded at the end of onCreate. So how do I execute the displaySchedule function once the fragment is fully loaded and available to be referenced for UI updates?
You can solve the TypeCastException by using this:
// Display the current list of matches to the user
var eventsFragment: EventsFragment? = supportFragmentManager.findFragmentByTag("eventsFragment") as EventsFragment
eventsFragment?.displaySchedule(currList)
You are looking for a fragment that you haven't created, in a place you haven't put it yet. You must first create the fragment and add it to the supportFragmentManager using transactions. If you want do pass data to the fragment you should do so by add this to your fragment (if your list is not string, then it must be serializable and use putSerializable instead.
companion object{
fun newInstance(list: ArrayList<String>) = EventsFragment().apply{
arguments = Bundle().apply {
putStringArrayList(KEY, list)
}
}
}
and then pull the data out of the arguments bundle in the onCreate method in your fragment.
Now in the onCreate in your activity you will create the fragment and add it like so
eventsFragment = EventsFragment.newInstance(list)
supportFragmentManager.beginTransaction().add(R.id.frameLayoutId, eventsFragment, fragmentTag).commit()
only now, if necessary can you use the code you have to get the fragment again, and you should always do it expecting ti to possibly come back as null:
eventsFragment = supportFragmentManager.findFragmentByTag(fragmentTag) as? EventsFragment ?: EventsFragment.newInstance(list)
The problem with your code is you are trying to find a fragment which is not there that's why its null. Not sure where you made the Fragment transaction.
To fix this There can be two cases:
If you already have the data in your Activity its better you pull it inside Fragment by using getActivity() in #onViewCreated() or by a Shared ViewModel.
If you are loading data from a source(Network/IO) then you can use a Shared ViewModel or Get fragment from back stack and call its method or you can use conventional callback stuff.
I can add some sample code but i am not sure which option is best fit for you since its not clear from question that u are using MVVM or not.

Get fragment from NavController

I have one NavController (navOrdersController) with 2 fragments inside. My current fragment is OrderDetailFragment and I want access to first Fragment (OrdersFragment) to update data in MainActivity. How can I do this?
I tried findFragmentByTag and findFragmentByID but always return null.
I got access OrderDetailFragment with:
this.supportFragmentManager.fragments[position].findNavController().currentDestination
But I need previous fragment. Thank you very much
Can't say the code snippet (I've added below) is the best solution, but it worked for me to get the recent/current fragment added in NavHostFragment used in Android Navigation Component's implementations
OR
You can even override onActivityResult of the you activity with your fragment's, all you need is to get the added Fragment and call it's onActivityResult, using this code snippet:
NavHostFragment navHostFragment = (NavHostFragment) getSupportFragmentManager().findFragmentById(R.id.nav_host_fragment);
Fragment fragment = navHostFragment.getChildFragmentManager().getFragments().get(0);
fragment.onActivityResult(requestCode, resultCode, data);
If both the fragments have same parent activity, i.e. use getActivity() to get activity reference and use Activity.getSupportFragmentManager to find the fragment.
.....
Activity X -> Fragment A -> Fragment B
If fragment B is child of Fragment A, use getParentFragment. The fragment you are looking for would be this fragment.
Let me know if anything is not clear.
PS: Jetpack Navigation library does the same thing which we have been doing explicit. So, the previous logic of Activity-Fragment is still valid.
EDIT:
try out (parentFragment as NavHostFragment).childFragmentManager.findFragmentById()
I forgot last time that activity has declaration of NavHostFragment in its layout so there will always root parent fragment of type 'NavHostFrament'
EDIT:
I have found a work around for it
parentFragment.childFragmentManager.getFragment(Bundle().also { it.putInt("foobar",0) }, "foobar")

FragmentTransaction 'add' not working

I am having problems adding a fragment to a frame layout placeholder:
TestDialogFragment newFragment = new TestDialogFragment();
int id = R.id.fragment_placeholder; //id of the FrameLayout placeholder for the TestDialogFragment
getFragmentManager().beginTransaction().add(id, newFragment, "testdialogfragment").commit();
I have breakpoints in the onAttach and onCreate methods in TestDialogFragment and they don't get hit, which goes against what I read in the android fragment API Guide. Is there something I'm doing wrong with the add transaction above?
P.S. TestDialogFragment extends Fragment
I fixed this by setting & getting arguments with Bundles instead of interacting directly with the fragment via its public methods after committing the transaction. My mistake was assuming that the fragment was up and ready to use (attached, layout inflated etc) as soon as the commit() statement was finished.

Categories

Resources