Is there some way to test individual View components without running the UI test?
For example, can I check cases like this:
check the change of the View state. For example, when the onClick() method is called, a change in the state of the View (color changes or visibility) is called.
check that if, for example, in the RecyclerView.Adapter I give a list, then it is filled and I can, for example, check some element and check its validity relative to the passed list.
that when a method is called, an animation starts.
I am not interested in rendering in this case, only the fact of executing the methods I need with the parameters I need.
What tools and approaches are used for this? What about Robolectric? I heard not very good reviews about him, can he fulfill my requirements? And are there any alternatives?
In my opinion, you're trying to solve the wrong problem.
What is the point of testing if a view.setColor() is called if you don't care if the rest is ok? What you should be testing (and therefore using mocks if you want/can) is the logic that triggered said "set color". Who/how did you decide that certain action triggered setColor on X views?
If you say: "but that's in the activity/fragment/onresume, how do I test that?". My answer is: don't put it in the activity/fragment/onresume, put it in a proper viewModel or delegate to a component that has your business logic that you can mock and test.
When an onClick is called, an entity (viewmodel, presenter, etc. should receive the click event, make a decision, and change the "state" of the view(s) in response. NOT the click method deciding to change the view's color on its own.
Why not?
Because that logic may be wrong, may contain a bug, is hard to test as it is, etc. Whereas if it's separate in a "delegate that is tested", it's easier to find/fix/test, etc.
Related
So I am working on my first viewModel app, it needs to make a sound with something like ...
MediaPlayer.create(context, R.raw.app_start).start()
But this requires context, if I understand correctly context should not be referenced by the viewModel code to avoid memory leaks so I need my fragment to execute the code.
To trigger the sound in the fragment from the viewModel code I could define a state observer on a boolean and flip its state in the viewModel to execute the code in the fragment but this seems messy as I would have to flip it twice to make it ready for the next need for a sound.
Is there a more elegant way ?
Hmm. Well, using an observable you have just hit the classic "observe an event" problem.
Standard Google observables usage is for a value (state), and as you have noticed, you have a problem with needing to "reset" the value (publishing the same value doesn't notify the observers).
There are lots of ways around this, but depending on your need, a quick (actually a bit hacky IMHO) solution is to use a timestamp (maybe a millisecond time value) as the trigger.
Every time you push the value, it will be different so will be observed in the fragment.
In most cases like this, you don't really care about the value, it's just a trigger .. in this case to play a sound.. but it could just as easily be to exit the fragment, or something else.
I am converting my application to use the MVP pattern. There is some debate between the developers on the proper use of MVP especially in regards to the Android lifecycle and where the UI related logic goes. There is no debate that any hard logic should be done in the presenter, and that the network
In the case I need to do Anything for lifecycle functions, onresume, onPause, etc. Should I ...
Call a mPresenter.onResumeEvent(); The presenter then does calls. IE
contract.restoreState(); contract.connectToService() etc.
or
Do all the logic I need here and not involve the controller. IE
restoreState, start up loading spinners, etc.
I view it as onResume is an event. All events should be processed by the Presenter. The counter arguments is, we do not want to write code that "ping pongs," I.E. OnResume -> Presenter -> one line function that shows a spinner (or something close to that effect)
Now a bit more granule.
Lets says I start my activity, and I need to show either an error or the data depending if the data is null.
I could either do..
(presenter)
contract.setupUi(data);
then
(view)
setupUi(Object data){
if(data != null){
//show data
}
else{
//show error
}
Which has the UI controlling the state evoked from the presenter.
Or I could do
(presenter)
if(data != null){
contract.showUI(data);
}
else{
contract.showError();
}
Which has the contract looking at all the states.
Is the over all goal to have the Presenter Completely control everything about the application and treat the view as completely Dumb. Or is it just dividing up the code purely for testing purposes. Or is it both?
Recap.
How should I handle the lifecycle -- treat it as an event or let the
view just do it.
Where should the view related logic go? Let the Presenter figure out
what is null and what UI to show. Or let the view take care of it?
What should my over all focus be? Controlling the app with the
presenter, unit testing, both?
Very good questions, but, unfortunately, they do not have definitive answers.
It boils down to the fact that MVP (or any other MVx) is not a specific implementation, but rather a high level architectural pattern which is subject to interpretation.
Said that, my answers to your questions:
I'm a strong believer that UI logic doesn't belong into Activity/Fragment at all, therefore MVx views should never be aware of lifecycle events.
UI logic goes into standalone class that takes on responsibility of MVx view. Where you put null checks depend on the purpose of this check: if the result only affects UI (e.g. show/hide UI element) then perform the check in MVx view; if the result affects application's flow (e.g. show prompt dialog, change screen, etc.) then perform the check in the presenter; if both - perform checks in both presenter and view
Your overall focus should be on writing a maintainable code. Maintainable, first and foremost, means readable.
Again - the above answers are IMHO.
You might also be interested in this series of posts that I wrote: MVP and MVC Architectures in Android
I'm having a problem instantiating Fragments in my program using the Support Library implementation. Here's a brief description of the task I'm attempting to perform and some of my attempts which haven't yet borne fruit:
The UI of my application is subject to change to meet user preferences. In order to do this, I'm using a Fragment for each different layout and replacing the active Fragment in the UI at a given time as per the user's instructions. Here are some ways I've tried (and failed) to do this:
I've tried adding the Fragments as non-static inner classes in my Activity. This approach worked so long as the user did not rotate the device. As soon as the user rotated the device, the application crashed (this is true for Portrait -> Landscape rotation and for Landscape -> Portrait rotation). Upon checking the issue using the emulator, I was getting an InstantiationException. I checked SO for some help, which led me to:
Implement the Fragment as a static inner class. When the Fragment initiates, it will expand its layout, and then from later in the control flow of the Activity, I can do stuff to the Fragment's subviews (in particular, add listeners to the buttons). Unfortunately this didn't work because I couldn't refer to the Fragment's subviews using [frag_name].getView().findViewById(). Something about referencing static objects in a non-static context. Once again, I checked SO, which led me to:
Implement the Fragment as a separate class altogether from the Activity. This seems to be what the Dev docs on developer.android.com recommend. Upon doing this, everything seems to compile fine, but when I try to refer to the Fragment's subviews (once again, using [frag_name].getView().findViewById()), I get a NullPointerException. When I add System.out.println() statements across my code to find out exactly what is happening, I find that the print statement inside onCreateView in the fragment is never getting fired, which implies that onCreateView is never getting triggered.
So now, I'm stuck. What am I doing wrong? The precise implementation of this isn't as important as learning something from the experience so I can get better at Android development, so if seperate classes are better than static classes or vice-versa, I don't really care which I use.
Thanks.
Figured it out. Turns out that in order to do what I wanted, I had to register the Activity as a Listener to each of the Fragments and pass "ready to enable buttons" messages back and forth between the two. To anyone using this question for further research, the guide on how to do that is located on the Android Developer guide, here: http://developer.android.com/training/basics/fragments/communicating.html
I have put the all the binding code for UI events on OnCreate(). It has made my OnCreate() huge.
Is there pattern around implementing UI events in android ? Can I add methods in View xml file and then I can put all the handler code somewhere else.
In a nutshell , I think I am asking how can I implement MVVM pattern with android app code ?
Stuff that I do:
Keep all onClick functions in the XML. Avoids a lot of clutter in the Java code.
Initialize event listeners as members of the activity class rather than keeping them in a function. I don't like too many curly braces in my code. Confuses the hell out of me.
If my list adapters get too big I keep them in a separate class rather than as a member of the activity class and then keep all view listeners there in the adapter.
To avoid creating too many onClick functions I sometimes keep one function like onNavigatonClick and then use view.getId() to see which button was clicked. As the XML is not checked for valid function calls, it leads to runtime errors if your function name is wrong.
If a particular view needs a lot of UI interaction code, I create a custom view with a GestureDetector to handle UI interactions.
I guess this is still quite basic as I haven't had much experience with Java yet.
In 1.6 and later you can specify onClick methods in your layout XML file to trim a bit of the fat. I generally just hide it all away in a initUi() method that I have my onCreate method call. This way at least the onCreate is easier to read.
Lots of good answers to this already. :)
If you're using Android 1.6 or later you might find the new fragments API helpful for organizing and partitioning your activities into several logical units.
onCreate is usually the best place for calling setContentView and setting up listeners, but the code for handling the user interractions normally goes in onClick, onTouch, onKey etc. routines.
Maybe if you posted your code we could see what you've done?
I want as my application to be structured in 2 parts: the logic code and the UI.
I've tried to implement that using a controller class(here I keep the logic code) inside of each activity.
The activity send messages to controller and receive the answer in two ways:
the answer is returned immediately (if the action is not complex and it can be done in a verry short time)
the activity set some listeners and the controller fire this listener when the action is complete.
The problems appears when the controller have a lot of objects(each object should handle a set of actions and for each action I have to set & trigger a listener): it is hard to keep the code syncronized.
I'm asking if you know a better way to implement this mechanism.
Thank you.
Personally, I consider the Activity to be the controller. Widgets are the view. Others may disagree, and I am far from an MVC purist.
Android methodology is pretty MVC.
Start by getting good at Views, then look at extending things as you see fit.
The views connect to the controller via the UI thread, which is the main thread of the application. You can define callbacks and such in the XML and handle all button clicks and such in this thread by just using the android xml methodology.
You should consider XML to be the View, UI Thread the Controller, and Background Threads/Services/Broadcast Receivers etc to all be part of the model.
You can follow "Model View Presenter(MVP)" pattern which pretty much organises the code and keep the code segments clear.
I like the dummy view approach where all views events (like onClick, onLongClick.. ) are delegated to presenter and presenter takes care of the business logic and updates the View back.
Consider a scenario where user is adding some text to his note and In view, we have a textbox, texfield to indicate the status and add button.
User types text and clicks add button.
AddButton: "Hey Presenter! User wants to add something".
Presenter: "Give me your text, TextBox".
TextBox: gives the text typed.
Presenter: Validates the text with buisness logic.
adds item to database using Model classes and sends the status text to StatusTextView to show.
StatusTextView: updates its text which is sent by the presenter.
As you can see, Views do what Presenter says. You can have different flavours of Presenters to act differently to user interactions.
Some points to consider:
Keep presenter out of android classes so that you can unit test it
separately later.
Connect view and presenter with interfaces (contracts) so that you
can plug different views and presenters later with changing app
requirements
Use Dependency Injection frameworks like Dagger2 to even more
decouple the hard dependencies.
Google about MVP and choose your preferred way of implementation. Only con I felt in MVP is your code will become huge yet clear.
Few links:
https://medium.com/cr8resume/make-you-hand-dirty-with-mvp-model-view-presenter-eab5b5c16e42
https://www.journaldev.com/14886/android-mvp
Happy coding :)