best practices for handling UI events - android

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?

Related

UI testing without running a test on a real device

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.

Why does this make my app crash and what's the appropriate solution?

I have a button that I want to change its value often, so my Activity has a private variable :
private Button p1_button = (Button)findViewById(R.id.firstbut);
This simple line makes my app crash. If I put inside the onCreate it works and I can interact with the button (change text etc).
EDIT : I think I found the reason. I should initialize AFTER setcontentview ?
EDIT: Thank you for the constructive answers. I have now a different problem I removed the initialization and I did it on onCreate and it works (But I keeped the p1_button declaration as a private field). But when I tried to modify the button in a different method of my activity (just changing the text), it crashes again. So the return value of findViewById is "local" to the method where it is called and I should setcontentview in every method that access UI elements ?
Do not call findViewById() until after you call setContentView(). Otherwise, the widget will not exist.
More generally, do not call inherited methods on Activity until after super.onCreate(), unless specifically advised to do so.
It depends where you are calling this line.
http://i.stack.imgur.com/6EQaU.png
The onCreate() method contains a call to setContentView() and before this is called, Android has no idea what to do with your button as it hasn't been inflated yet!
Therefore as a really easy rule of thumb, always make sure setContentView (or if you're dealing with fragments onCreateView()) have been called and completed. Only then will findViewById() work.
If you would like further guidance, please post some code in which the crash occurs.
edit: I tried to add the image properly but don't have enough rep.
To understand this you need to know the Activity lifecycle. You are trying to look a view which has not yet been created by Android.
As per the android lifecycle explained here "http://developer.android.com/training/basics/activity-lifecycle/starting.html". In onCreate() method the activity is created and you can access different views of the activity. If you will try to look for view before onCreate() the app will crash as it does not know whether that view exists or not.

Fragment not instantiating correctly

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

Android Interfaces and onCreate()

This is a double question about using interfaces - namely onclickListener (and related) within an Activity.
onCreate should be short - so says the documentation - but if I have lots and lots of views all of which have onClickListeners it can get quite long. I'm worried this will cause the UI thread to timeout. Is this a problem?
Is there a best way to use onClickListener? By which I mean, is it better for the Activity to implement onCLickListener and then have a very long onClick() method? Or do the following:
mView.setOnClickListener(new OnClickListener(){
...
});
for each View? Does it really make any difference?
They mean "short" in that don't do anything that takes a long time to process in onCreate(). Anything like math computations, networks or database access, extremely large bitmaps inflations should be done in a thread. The only overhead that setting an onClickListener to a view is calling a method, setting a reference, and usually creating an object. If object creation does any of the aforementioned things, then it would be best to pre-load the object before creating it.
There's no real difference. What you choose depends entirely on your implentation and coding stye. Using an anonymous object like you showed is kind of like a "set-and-forget" style way of doing it. It's suitable if the action is unique to the button. Creating a whole new class that that implements onClickListener() would be required if there needs to be a state that persists with each click. That way, you create the object once and set all the necessary views to the single object. It may also be useful to do it in that fashion if many views do the same action when clicked.
It shouldn't bother with the loading of your activity because the code inside onClick listener is executed only when a click is made on its view.
Besides, its not a good idea to execute heavy stuff (network, database, drawable manipulation, etc.) in onCreate. In case if you really need to do such processing then off-load it to an AsyncTask which runs your code in a separate thread causing your UI (main) thread to be free.
1) I agree with Deev's answer.
2) Please note that if you choose to use the anonymous inner class solution
mView.setOnClickListener(new OnClickListener(){
...
});
You create an object for each assignment.
Conversely if you implement OnClickListener in your activity you won't create any other object. This doesn't make so much difference for a small number of object but could save some memory (and save you from GC) for larger number (and you said to have a lots and lots) of objects. Avoid unuseless object creation is suggested in Designing for Performance

Where to insert code for application startup?

Android newbee here, I have some code that I want to run when my android app first starts up. It checks the version of the local database and downloads a new version if the current version is out of date. I have been sticking it in the oncreate of my first activity, pretty sure there has to be a better place to put this. Any recommendations of somewhere I can put it where it will get called once on startup?
You can write a custom Application class (extend from android.app.Application). Override onCreate to specify what happens when the application is started:
public class MyApplication extends Application {
#Override
public void onCreate() {
super.onCreate();
// Do something here.
}
}
You'll then need to register your custom class in the manifest file:
<application ... android:name="fully.qualified.MyApplication">
Edit:
In response to David Cesarino, I disagree with the purpose of the Application class. If you rely on the Activity's onCreate, then what's to stop it from becoming the same huge class of miscellaneous purposes... if you need something to happen when the application starts, you have to write that code somewhere; and the Activity would probably become more cluttered because you have to perform Activity specific logic in it as well. If you're worried about clutter, then separate the logic into other classes and call them from the Application. Using the SharedPreferences to determine whether or not the logic should execute seems like more of a work-around to a problem that's already been solved.
Dianne Hackborn seems to be referring to data, not logic, in which I totally agree. Static variables are much better than Application level variables... better scoping and type safety make maintainability/readability much easier.
First, look at the Activity lifecycle.
Answering your question, you could put code in any of those "start-up" methods, depending on what you want to do and, mostly important, when you want to trigger that. For what you asked, onCreate is the reasonable place.
I have been sticking it in the oncreate of my first activity, pretty sure there has to be a better place to put this.
And why is that? Any code has an entry point, right? In Android Activities it just happens to be onCreate (again, see above link for the full details). Besides event handling, which are responses to events happening outside the main sequence of calls, you put stuff in onCreate.
If you're concerned about the method becoming huge, then that's another problem. Abstract your code better, I say. For checking preliminary stuff, people generally provide a "Loading" activity, before starting the main activity of the app.
edited:
This is a follow up to what drumboog proposed, since my comment started to grow in complexity to be "just a comment".
Personally, I'd avoid extending the Application class for the sole reason of executing code early on, more so a code that is not that sensible in priority (versioning databases). The Application class is mostly used as an easy way to persist state between Activity'ies, not as a way to "do everything". In short, I feel the Application class is commonly abused.
For what you want, you could perfectly achieve that calling code in Activity onCreate. That reduces complexity, because I've seen people stuffing Application until it becomes a huge class of miscellaneous code purposes. And that's a no-no for maintenance, with logic problems of its own.
Besides, if you truly want another solution, completely disassociated with the UI, you should think about implementing a Service instead (but I don't think it's necessary for just that).
Both of those concerns were previously addressed by Dianne Hackborn (or what I got from her message).

Categories

Resources