Espresso - Check for specific item in specific fragment of Viewpager - android

I have a ViewPager which contains 3 fragment and each fragment contains a recyclerview.
When page launched -> FragmentA is selected by default and I check for a specific id inside FragmentA and the test is success.
Now i used swifeLeft() to navigate to FragmentB. It worked.
Now I am checking for a specific item in Fragment B. But It throws error as NoMatchingViewException. In View Hierarchy log, i'm seeing the view hierarchy of FragmentA only. Somehow after swipe the View Hierarchy is not updating.
Did someone faced the same issue?

Have you tried to add a sleep just after your swipe ? I can help.
Espresso is not able to detect asynchronous work so it might fail because your data is not yet loaded (because of slow network/database etc) when it check the view you want to interact with. So the best solution is to implement IdlingResource in order to make espresso aware of them.
You can take a look at this sample:
https://github.com/googlesamples/android-testing/tree/master/ui/espresso/IdlingResourceSample

Related

Android espresso test multiple fragments consecutively, inside the same activity

I have a fragment initially inside my activity, this fragment contains a button that's when it's clicked it open the second fragment, and the second fragment contains a button that's when it's clicked it open the third fragment, and so on ...
Now I want to test the launch of the third fragment after passing by the 2 old fragment (not testing the fragment in isolation), I tried to preform a click in the button inside each fragment but it seems espresso doesn't wait for the 2 fragment to launch, before clicking the button inside it, is there any solution for this ?
Without seeing the code its hard to tell what the best way to handle this would be.
However this seems like an issue with the IdlingResource. Espresso should wait until 2nd fragment has finished launching before moving forward.
You can handle it by adding a SystemClock.sleep(int milliseconds) . That is not an ideal solution however and sleeps should be avoided at all costs.
No it's not a timing issue I have an Activity with 3 fragments all of which are visible concurrently. Android Espresso will only do tests in the top fragment and refuses to acknowledge the presence of all the rest of the fragments.

Android View Pager: onCreateView getting called for both fragments

I am trying to implement swipe views with 2 tabs. For that, I am using view pager with 2 fragments. Now, the problem is that as soon as the main activity is opened (that contains those two tabs), onCreateView function is called for both the fragments. Please help me as how can I avoid calling of onCreateView of second fragment when one is in use.
Thanks,
Arpit
ViewPager retains the fragment to the left and to the right of the current view by default. This is to reduce a choppy user experience - that way you can begin swiping left or right and immediately see what is there without delay.
It is possible to disable (or increase the number of fragments to be retained) with setOffscreenPageLimit(0), but seriously consider if this is the right approach.

In ViewPager, Fragment (n+1) depends on user input in Fragment (n). How to create Fragment (n+1)?

The ViewPager object is implemented such that the next screen is already created in memory before the user swipes to it. ViewPager has a method setOffscreenPageLimit(n) in which you can set the number of ViewPager fragments that are created in advance, but n=0 is not allowed. The reason behind that is to garantee a 'smooth user experience'. In my case however then content of page n+1 is determined by what the user has done on page n. For instance if the user has clicked on a checkbox on page n, it can happen that some widget should not be shown on page n+1. My question is: how can I ensure that page n+1 is recreated? If that goes at the cost of a 'smooth user experience' so be it. I am able to intercept the swipe event in:
pager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener()
In that method I can call a refresh() method of the current fragment. The problem is: what do I do in that refresh() method or is this the wrong approach? The user interface I want to recreate is in the onCreate method, a callback method. Or can't this work and do I need to replace the Fragment (n+1) in memory with a new one and if so, how do I do that?
Any help would be appreciated.
Trying to replace the fragment associated with a page in a ViewPager is going to be the responsibility of your fragment-based PagerAdapter. I am not aware of an easy way to accomplish that with FragmentPagerAdapter or FragmentStatePagerAdapter. My ArrayPagerAdapter can handle it better, though I don't offer a direct replace() operation.
In your case, the better solution is to adjust the fragment that you have, rather than to replace the fragment outright. In theory, this should be possible for just about any degree of change. In practice, there is probably a level of complexity after which trying to replace the fragment would be simpler than trying to have a mashup of all possible fragments.
Note that nested fragments might be another option, where the N+1th page was a placeholder and ran a FragmentTransaction to populate itself when shown. Nested fragments are tricky and quirky.
With regards to the "holes", View.INVISIBLE indicates that you want the widget to continue taking up space (e.g., so stuff after it in a LinearLayout does not move), but do not draw the pixels. View.GONE means that the View is totally ignored for layout purposes, though it is still in the hierarchy and so can be easily toggled back to View.VISIBLE if needed. Another possibility would be to remove the View entirely from the parent container, though this should have no visible change when compared with View.GONE.

Handling fragment transaction in android.

Hi I am developing android application in which I am using one activity and two fragments. Consider same example which google explain like one list view and detail view. on click of list item we are rendering respective detail fragment.
So I learn how to do fragment transaction and i come up with two solutions. One which is standard way which google explain that make one interface and implement that interface into main activity. And do fragment transaction there inside main activity.
I tried with another way. when I click on list item inside click listener instead of calling interface I change fragment inside my list fragment only and its working fine.
So i want to know what is difference between those to methods. changing fragment from main activity and changing it from fragment only.
What kind of problem i will face if i implement with second method.i.e. changing from fragment only.
Need Help. Thank you.
What kind of problem i will face if i implement with second
method.i.e. changing from fragment only.
There isn't an actual problem, it's more of a design discussion. Using the second approach means you're making a very specific fragment, one that on a click on one of its rows will make a transaction with a specific fragment on a specific place of the holder activity. This would be a problem if you plan on reusing this fragment.
Suppose you have this ListFragment and you decided that it should be used in five other activities(with different data). Because it has a very precise action when clicking one of its rows, this fragment will always require the holder activity to have a specific container(where the transaction will be done) along the specific detail fragment with which it was initially used. The problem is that in each of those five activities you may want to use a different fragment when clicking a row of the ListFragment, this would require making changes to the class of the ListFragment.
Now suppose you have the same behavior with the interface approach. As the ListFragment doesn't know or care who handles that click event(as it passes it to whoever registers as the listener) you can simply put the ListFragment in the five activities with no problem(so no changes to it at all). In the interface method of the activity you could then implement the desired behavior with whatever fragment you want and in whatever container setup you want.

Why is my fragment onCreate being called extensively whenever I page through my applications viewPager?

I'm not quite understanding this fragment lifecycle business.
I have a pretty standard 3 page horizontal slider view Pager layout for a "view details" section of my app. I start my app on the middle page of the three. My FragmentActivity sets the page to page 1.
mPager.setCurrentItem(1); //default to center page, current data view fragment
I've been using the FragmentStatePagerAdapter because using the FragmentPagerAdapter crashed my app at times, when coming back from a suspended state for example, and this was the quickest way to work around that for now. Seems to work but I suspect the State aspect is what might be the cause of my problem here, maybe.
So at first I thought that I would have each fragment do the work of getting data from a rest service and then showing it in a list, but I'm not so sure any more.
I tried running a unique async task to fetch data in each of the fragments onCreateView events.
Then after reading more on the fragment lifecycle I switched to onCreate, having noticed that the onCreateView was being called quite heavily, which in turn made for a greedy app that too often requested data over the wire.
Switching to onCreate hasn't changed anything. OnCreate is still geting called just as much as onCreateView for the 2 adjacent fragments.
The odd thing is that the fragment that I set to be the first one to display in Fragment Activity only gets the onCreate called the one time.
Something doesn't feel right here.
Right now I'm thinking that I should have the parent fragment activity declare and call all the async tasks to fetch the data that I need to display in the fragments.
Set the results of the async calls in an object owned by the parent fragment activity and then have the fragments use the object contained by the parent to create the list view etc.
But what if the async tasks started by the parent activity don't finish before each fragments onCreateView is called and the object contained by the parent isn't ready yet.....
signed, confused and frustrated
ViewPager is quite zealous in shutting down things it isn't currently using, and this is exactly what is happening here. The default behaviour is for ViewPager to "keep around" one page either side of the page being viewed, and destroy the rest. Hence in your 3-page view, page 3 gets destroyed when selecting page 1, then when page 2 is reselected page 3 is recreated. As you've noticed, page 2 only has onCreate(..) called once because it is always adjacent to, or is, the currently selected page.
To solve this, simply set ViewPager.setOffscreenPageLimit(2). Then the ViewPager will keep all your Fragments. Obviously this isn't a good idea for a large number of Fragments, but for your case it should be fine.
#Espiandev's solution will work for your current case, but you're right that your state is the issue. You should use the setArgument and/or onSaveInstanceState methods to save your Fragment's state (which shouldn't be too hard, since e.g., a response from the server can usually be represented as a String), and then use getArgument and/or the Bundle passed in onCreate to restore it.
Alternatively, you could have your Activity do the server fetches, and then call setArgument for each of your fragments, and check the arguments inside your Fragment to determine if your data has arrived yet (and if not, potentially display a loading state of some kind).
If you care at all about screen orientation change, this related question will also be useful to you.

Categories

Resources