I have some flows where a fragment opens another fragment to do staff in a dedicated screen. Every time I open the new fragment Roboletric is not able to "see" the stuff in the new fragment. Sometimes adding inRoot{ isDialog } solves the problem, other times it doesn't.
Any idea on how to work on this? Using espresso + actual device everything works correctly but I would want to move the tests to roboletric to use JVM instead of a real device.
To test fragments that are opened after a button is pressed, you can use the Robolectric framework, which allows you to perform unit testing on Android app code. Here are the general steps you can follow:
Create a test class that extends the RobolectricTestRunner class.
In the test class, create a method that simulates the button press and opens the fragment.
Use the startFragment method provided by Robolectric to start the fragment and add it to the activity.
Use the getSupportFragmentManager method to get the fragment manager and use the findFragmentById method to find the fragment that is currently displayed.
Use assertNotNull to check that the fragment is not null, indicating that it has been successfully opened.
Perform any additional tests on the fragment's views or behavior as needed.
Here is an example of what the test method might look like:
#Test
public void testFragmentOpensAfterButtonPress() {
// Simulate button press
button.performClick();
// Start the fragment
startFragment(new MyFragment());
// Find the fragment
MyFragment fragment = (MyFragment) getSupportFragmentManager().findFragmentById(R.id.fragment_container);
// Assert that the fragment is not null
assertNotNull(fragment);
// Perform additional tests on the fragment's views or behavior
...
}
Related
how to make button to open another fragment. being within a fragment. kotlin
I'm starting in kotlin and I'm having a hard time trying to open a fragment with a button, how do I?
You need to use FragmentManager and FragmentTransaction to add your fragment on the fly. you can call a function similar to this in your button's onClick method. But it is recommended for the parent activity to handle each fragment's lifecycle and the fragments
are not supposed to interact each other. The following is taken from the developer docs, that can be found here.
"Often you will want one Fragment to communicate with another, for example to change the content based on a user event. All Fragment-to-Fragment communication is done either through a shared ViewModel or through the associated Activity. Two Fragments should never communicate directly."
fun createFragmentonTheFly(){
var mFragmentTransaction: FragmentTransaction = getSupportFragmentManager().beginTransaction()
mFragmentTransaction.add(R.id.fr_container,new ProductListFragment())
mFragmentTransaction.commit()
}
The best way to do it would be to add an interface let say onFragmentDetachedLisetner and add one method replaceFragment() or something and make your Activity implement this interaface and had it replace as soon as the fragment is detached and make your fragment that contains your button finish itself when user clicks the button, then your activity will replace it with the one you wanted to start. And also consider reusing fragments, as that is the main purpose of fragments at the first place.
When I navigate to an activity using ShowViewModel, it is nicely animated. But when the target is a Fragment it won't. Is there a way to add this as well?
I saw that in native android you would add it to the FragmentTransaction, but since MvvmCross Handles that for us, I assume there is another place to handle that.
The code that handles the fragment transaction is the Show method from the activity implementing IMvxFragmentHost that's responsible for handling the specific Fragment being show. In order to change the animation, you need to use the SetCustomAnimations method when displaying the fragment.
What I usually do is creating a BaseFragmentView class that has enter and leave animations exposed as properties. When displaying the fragments, I can simply use those properties like this:
var transaction = SupportFragmentManager
.BeginTransaction()
.SetCustomAnimations(fragmentView.EnterAnimation, fragmentView.ExitAnimation)
.Replace(targetId, fragmentView)
.Commit();
When using the MvxChachingFragmentView, you can simply override the OnBeforeFragmentChanging method and use the second parameter to add the custom animations you want.
You can see how to implement the IMvxFragmentHost interface by checking the MvxCachingFragmentView class and, if you don't know how to use the new Fragments from MvvmCross 4, refer to this answer
Just a general question about working with Fragments and Activitys for android development: where does the business end of the functional code go for Fragments loaded into an Activity dynamically? (i.e. a fragment's OnClickListeners, OnCheckedChangedListeners, button logic methods...)
Do they go in the Fragment class, or the Activity class?
All the GUI logic for views attached to a fragment should be contained inside the fragment itself.
Thus a fragment should be as self contained as possible.
You can, though, if necessary do callbacks to your activity based on fragment GUI interaction. This can easily be done like this inside the fragment:
#Override
public void onAttach(Activity activity) {
if (!(activity instanceof SherlockFragmentActivity)) {
throw new IllegalStateException(getClass().getSimpleName()
+ " must be attached to a SherlockFragmentActivity.");
}
mActivity = (SherlockFragmentActivity) activity;
super.onAttach(activity);
}
In this specific case the reason for gaining a reference to SherlockFragmentActivity is to gain access to the support menu inflater mActivity.getSupportMenuInflater(), hence the construction can of course also serve to gain information from the underlying activity.
This probably depends on how much the Fragment's functionalities have in common, and how many, let's say Buttons, have to be handled.
I personally (and it's probably most common practice) handle onClick(...) events separately for each Fragment, meaning that I let each Fragment implement it's own OnClickListener.
Furthermore, when handling everything through the Activity, probably not all the components that react to click-events are in memory at all times and can be reached via findViewById(...), depending on which Fragment is currently displayed and how your user-interface is built up in general.
they always in fragment class because fragment is one type of component in android which we can reuse it. if we put onclick and oncheckchanged in activity then what meaning of reusing that component??
for more information about please go through following step:
Link 1 for basic level of information about fragment and how to handle them
Link 2 for dealing with multi pane fragment
Standard site for fragment
It depends:
If fragment can handle logic which is self sufficient(complete) then that code can be handled by fragment. e.g. on click call phone number.
If fragment have UI whose action is activity specific, then you want to add listener in activity.
e.g. master detail view like email client, on tablet user click on title fragment1 which have list of email titles, then handler on click in activity can show detail fragment2 in activity.
In all you want to keep fragment reusable.
I have an app setup that uses fragments in various place, in one case a fragment exists and upon pressing a button another replaces it using replace() all normal so far, however when the user presses the android back button and the new fragment is removed/popped (whatever the system uses) and the app returns to the first fragment there is no event being fired that i can override to perform an action.
is this normal?, the docs seem to suggest that onResume should be fired in this instance, other sites don't, and my app doesn't, if anyone has any clue if this is normal behaviour or not that be great and if it is what event can i hook into?
Edit: i forgot that all of this is occuring as nested fragments, the first fragment is the child of another so is added using a child fragment manager the second replaces the first using its regular fragment manager, besides the issue im describing this is working great
how the first fragment is originally put in place
Menu_Fragment menufragment = new Menu_Fragment();
getChildFragmentManager().beginTransaction().replace(R.id.menu_container, menufragment, "_menu_fragment").commit();
How the second fragment is "added"
Google_Map_Container_Fragment mapcontainerfrag = new Google_Map_Container_Fragment();
getFragmentManager().beginTransaction().replace(R.id.menu_container, mapcontainerfrag, "addedmap").addToBackStack(null).commit();
On the iPhone I use a Navigation Controller to push and pop Views from. Very handy.
Is there an equivalent in Android?
This is an old question, but I believe the answer has changed. It is now possible to imitate the Nav stack in iOS in android using Fragments.
http://developer.android.com/reference/android/app/Fragment.html
Basically instead of jumping from Activity to Activity you instead stay in one Activity that controls the display, organization, and animation of Fragments which each contain their own behavior much like the NavController / UIViewController model in iOS.
It is also backwards compatible as a static library so you can implement it on pre-Honeycomb devices.
Strategies for Honeycomb & backward compatibility
Typically in android, each view is displayed in its own Activity. You can read about activities in the application fundamentals documentation. To move to a new Activity, or view, you use an intent.
If you haven't done so yet, I'd highly recommend reading through those introductary android docs. They aren't too long, and do a good job of explaning the basic program structure.
I made a Framework (github) to provide a hierarchical navigation pattern, with animations to provide sense of navigation, rather than launching new Activities every time.
Here's how to use it:
Add the framework to your project as a Module
Add a new Java class in your project ("File - New - Java Class").
Note: If you are editing the Activity.java file that provides you the template, delete all its implementations and leave it empty.
Make it extend NavigationActivity
Implement all the NavigationActivity abstract methods
(in Android Studio if you click Alt + insert and select implement - methods all the function definitions are automatically generated).
public class NavigationTest extends NavigationActivity{
#Override
public Fragment firstFragment() {
//return the first fragment that will be shown
}
#Override
public Boolean showBackButtonInFirstFragment() {
//show back button already in the first Fragment
//set to True if this activity is called by another Activity
//the back button will then pop back to the previous Activity
}
#Override
public Boolean showMasterDetailLayoutInTablets() {
//set to false if you don't want a master-detail layout in tablets
}
}
Presenting a new Fragment
You can present a new fragment (with a nice animation) by calling the pushFragment method from NavigationActivity.
public void pushFragment(Fragment newFragment, animationType animation, boolean showAsDetailFragmentIfPossible)
newFragment (Fragment): New Fragment that will be presented
animation (animationType): Animation type enum: RIGHT_TO_LEFT, BOTTOM_TO_TOP, FLIP
showAsDetailFragmentIfPossible (boolean): If set as True, the user is in a Tablet, and you are using a master-detail layout, the Fragment will be shown in the detail Fragment (the panel in the right)!
Since you can access the activity from any Fragment with the getActivity() method, you can show a new Fragment from the currently displaying Fragment.
For example you can put this code within a button click listener:
NextFragment f = new NextFragment();
NavigationActivity nav =((NavigationActivity)getActivity());
nav.pushFragment(f,NavigationActivity.animationType.RIGHT_TO_LEFT,false);
You don't have to worry about implementing the back button behaviour. This is handled automatically by the NavigationActivity class.
There are thee basic types in Android to show UI in Android:
View
Fragment
Activity
Google IO 2018 introduced Navigation component which should make life easier. It is a wrapper under a standard mechanisms.
Here you can find NavGraph which looks like storyboard and NavController which help to navigate to destination