I am trying to do some UI testing in isolation on some fragments that uses a shared Bottom navigation view from MainActivity, basically used to navigate and to scroll up and down, but my tests fails with nullpointerException basically because the buttons inside the bottom navigation view are not found in the fragment layout.
My question is how to pass these layouts belonging to mainactivity to the fragmentTest class.
FragmentScenario is the wrong approach, because a Fragment should not even depend on the parent Activity (and if it does, always check with instanceof or is, which one Activity it actually had been attached to). Better instrument the parent Activity with an ActivityTestRule instead, because a FragmentScenario uses it's own mock Activity and so you'll never get a handle to the expected one parent Activity (that's intentional, in order to rule out rigid dependencies to the parent Activity). Just set a break-point inside your current test's code, in order to see that there is no BottomNavigationView present, because it hasn't been inflated.
There's also a new ActivityScenario (which is currently still in beta stage).
Related
I tried to link the activity with the fragments but I had problems when making the observers.
(labels are completed )
My goal is to be able to have all fragments linked without the need to create a fragment for the activity_main.
Example
I was looking into converting my app to single activity as per google's guidelines. (Using Kotlin)
Let's say i have FragmentContainerView1 in my activity with no toolbar or anything else.
This view is used to navigate between login screen,sign up and display the main fragment.
Inside the main fragment, I have another FragmentContainerView2 which should display according to a BottomNavigation view inside main fragment.
But then i have some elements inside the fragments in FragmentContainerView2, that need to perform actions in FragmentContainerView1.
How do i achieve this?
Picture :
Here mainFragment contains the BottomNavigation,of which mainMenuFragment is a destination,which has to perform actions in FragmentContainerView1. How can I get a reference of the inner nav controller of the BottomNavigation?
Edit 1: navController=Navigation.findNavController(view.findViewById(R.id.fragmentContainer)) doesn't work, still returns same outer nav controller.
Not a Complete Solution, But the answer I found was to keep one of the containers as a <fragment/> and the other as FragmentContainerView.
And to get the inner nav controller use:
innerNavController= (activity as AppCompatActivity).findNavController(R.id.innerFragmentContainer)
Only works with that specific command and one of the containers being <fragment/>.
Also after getting the innerNavController, Any type of call with findNavController() gives the inner nav controller.
To get the outerNavController use:
outerNavController = (activity as AppCompatActivity).findNavController(R.id.outerFragmentContainer)
I'm working on a simple Android App as a self-learning Project. I've got a lot of it functioning, and I have a main Activity which has a FrameLayout and some RecyclerView and FloatingActionButton stuff going on inside of it.
However, I want to make one of my buttons in my NavigationDrawer open a different view in the FrameLayout using Fragments. Is there a way to do this, sort of making a new Fragment for the RecyclerView and the other stuff and putting the RecyclerView and FloatingActionButton in there?
I tried doing something like this (when the appropriate NavigationDrawer button was clicked):
statsFragment = new StatsFragment();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.rootLayout, statsFragment);
transaction.addToBackStack(null);
transaction.commit();
But this caused my app to crash. Any pointers?
Is your R.id.rootLayout a Layout or a Fragment component?
If your main Activity has a hard coded Fragment (by hard coded i mean declared in your XML), then no, you can't change a hard-coded fragment content with FragmentTransaction.
More information on this question's answer.
Finally, you can't put your components from one Activity inside a new Fragment/Activity since each component belongs to one and only one Context.
See, Activity extends Context. When you get a reference to a component declared in your XML by using Activity.findViewById(int), you are actually making a pointer to a determined View from this Activity's layout, defined in your onCreatemethod with setContentView(id). You can't take this pointer and throw it to another Fragment or Activity within your application without expecting any problems. (Well, maybe you can, but it's totally against the best practices of Android Programming).
Support4Demos feature Fragment stacks... but conveniently place the pop/push CountingFragment controls outside of the stack (all takes place in one layout, but the push/pop buttons are below, still in the Fragment that holds the whole layout.
How can the controls be made to work from the top fragment?
[EDIT]
Another way to look at it:
I want to make Fragments on a stack behave like Activities, each can pop itself, or launch another.
How would you alter the "FragmentStack" example from Support4Demos so that the "Go home"/"Add new"/"Pop top" buttons are in the CountingFragments, rather than in FragmentStackSupport which holds the FragmentManager?
A reasonable design - consider "CountingFragments" containing clickable ListViews?
How to do that? Ideally, each stack Fragment would hold a reference to the "stack holder' Fragment, or its (Child)FragmentManager. Those, however, are not Parcelable, and Fragment constructors must not be used (though everything else works great when I do it). Holding a reference to that is also bad, since the "stack holder' Fragment, too, can be destroyed and recreated.
[EDIT2]
All right, here are some ideas I came up with.
For "go home" and "pop top", I suppose I could add those (invisible) buttons to the hosting Fragment, and then access them in the hosted Fragments via getWindow().getDecorView().findViewById or somesuch.
That's ugly enough. But pushing new ones? Only related thing I can think of is adding a custom View class into the hosting layout, that holds a reference to the FragmentManager, to be grabbed by the hosted Fragments.
holding references to the FragmentManager(s) in a static map somewhere
register a BroadcastReceiver in the hosting Fragment, send broadcasts with data from the hosted ones, telling it what to do. But the host Fragment shouldn't have to babysit its children.
Have each stacked Fragment itself be host to either its true content, or the next stacked Fragment. That way, there is always a FragmentManager at hand (except for popping), but 2 fragments are needed per page, not to mention the weirdness of it all.
Please tell me there is a cleaner way.
How do you implement a fixed view through various activities in Android 2.1 upwards? By fixed I mean that the view should retain its state when the activity changes.
In particular, I'd like to have an Admob AdView on top of every activity without reloading the ad every time the app starts a new activity.
I don't think it is possible using different activities. But you could use only one activity and split your screens through multiple fragments inside this activity and adding/removing them while keeping your fixed view untouched.
This is not possible. The Activity is the basis of the app's user interface, and every View must live within the Activity's parent ViewGroup. Since every Activity must be created when it is initially launched, every View that lives inside the Activity must be inflated and attached to the Activitys layout.
What you could do instead is pass the information required to instantiate the specific admob View to the next Activity with an Intent.