Saturday 24 September 2011

Responding to clicks

When writing an app you would think that something like responding to a click on a button would be straightforward and in many ways it is. Working on my own, with no one to ask, I am drawn to examples and they often use a style of code that I find messy and hard to follow. That means, of course, that it will be hard to maintain and may hide nasty bugs, so it is a very bad idea. One of the things I find annoying is the amount of code lying around in the onCreate section of the class, but much of this code is not run when the activity is created, but when some event takes place. This seems wrong to me, so I wanted to find a way to avoid this in my code.

To deal with a click of a button you have to provide an onClickListener function and link that function to your button. You might have many buttons on an activity. Some may share a function or have one each. I have discovered four ways of doing this.

First, lets look at the often used way. In the onCreate routine for the activity this is added:

        final Button button1 = (Button) findViewById(R.id.cmd1);
        button1.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                Context context = v.getContext();
                String txtid = Integer.toString(v.getId());
                CharSequence text = "Button 1 " + txtid;
                int duration = Toast.LENGTH_SHORT;

                Toast toast = Toast.makeText(context, text, duration);
                toast.show();
            }
        });

The main advantage of this method seems to be that all of the code is in one place, the function itself and the code to enable the function for a specific button is all there together.  This also seems like a disadvantage to me too. A (potentially large) chunk of code is stuck in the onCreate function of the activity, rather than a simple statement to point to function in a separate part of the source file. Notice how there is a horrible "});" stuck at the end to show the nasty embedded nature of the declaration. Most of this code does not get run when the activity is created, but when a button is clicked, so why is it in the onCreate section?

The second example is in two parts, the first is in the onCreate of the activity which finds the button and points to the onClickListener routine

        final Button button2 = (Button) findViewById(R.id.cmd2);
        button2.setOnClickListener(cmd2_clicklistener);



The second part is the listener routine itself. This can be anywhere else in the source file, probably grouped with other listener routines.

    private OnClickListener cmd2_clicklistener = new OnClickListener() {
        public void onClick(View v) {
            Context context = v.getContext(); //getApplicationContext();
            String txtid = Integer.toString(v.getId());
            CharSequence text = "Button 2 " + txtid;
            int duration = Toast.LENGTH_SHORT;

            Toast toast = Toast.makeText(context, text, duration);
            toast.show();
        }
    };



The main effect of this is to separate the listener routine from the onCreate area. It does still have a complication that there is a function declared within a function, but it is easier to read. many of these can be created separately, but also more than one button could share one listener, with the code checking which button called it if needed. Using these declarations that are separate from the allocation of the listener makes it possible to change the listener that responds to a button during the run time.

There is yet another way to deal with onClickListeners. So far we have told the activity what function to call during the run time. Another way is to define the function name at design time. To do this in the button definition xml in the layout add    

android:onClick="clickfunc".  

This will cause a call to the function named which should have the prototype

  public void clickfunc(View view). 

This seems very simple yet having defined this the listener can still be overridden by a setOnClickListener call later just like the second example. There is no clutter in the onCreate section at all. It does, however, make the layout and code less independent. The listener in my example is this


    public void cmd3_click(View v) {
        Context context = v.getContext(); //getApplicationContext();
        String txtid = Integer.toString(v.getId());
        CharSequence text = "Button 3 " + txtid;
        int duration = Toast.LENGTH_SHORT;

        Toast toast = Toast.makeText(context, text, duration);
        toast.show();
    }



The final way I have found to respond to clicks is not very flexible, but if your activity has a single button it works well, and still removes the clutter in the onCreate section. You can make your class contain an onClick function and set the listener to this. To do this you must add the extention implements onClickListener to the definition of the activity class. You can then add a handler for onClick to the class (outside of the onCreate section of course) like this


    public void onClick(View v) {
        Context context = v.getContext();
        String txtid = Integer.toString(v.getId());
        CharSequence text = "Button 4 " + txtid;
        int duration = Toast.LENGTH_SHORT;

        Toast toast = Toast.makeText(context, text, duration);
        toast.show();
    }



The declaration of how to use the handler goes in the onCreate section as before, but now it simply points to the class itself (this)


        final Button button4 = (Button) findViewById(R.id.cmd4);
        button4.setOnClickListener(this);



I am pleased to have found alternatives to stuffing code into the onCreate section. Now I need to do the same for other listeners and handlers to make things much more readable.

Tuesday 2 August 2011

Objects and lifecycles

Android uses a Java-like programming language. I like objects, though I would prefer a more powerful implementation of property getters and setters in Java.  I was a bit surprised that in the examples of Android code I've seen there hasn't been more use of objects. Now I know why. Objects are expensive on some Android implementations because the object has to be created and therefore cleaned up. On devices with very small amounts of memory, or with a lot of apps running garbage collections are needed and these can cause a pause on the user interface. On Android 3.0+ there is a concurrent garbage collector but it still takes work.

This seems like a shame to me, objects are handy and I'm sure that sometimes I will use them, but I need to moderate my natural inclination to create an object for any and every purpose. I'm sure some Android devices would handle object management without any problem, but I need to consider some smaller devices too.

Each activity (screen) has an object associated with it so creating fields in there to use seems to be the main route to storing and manipulating data. Direct access to the field is recommended, not using getters and setters to save resources, so the fields are reduced to simple variables with limited scope. Indeed it is further recommended to be careful about how intermediate variables are used, so that a method that returns an object does not create a temporary object that just needs to be cleaned up.

If the use of objects is such a problem I wonder why Java was the chosen language for Android. I think I'll have to experiment some more - so far using objects works for me both on the emulator and my Android devices, I just need to not get carried away.

I have also been looking at the life cycle of Android apps. It did feel a bit odd at first because it seemed that the programmer was not in control of the life cycle of an app. In reality it works well and is just a variant of any other event-driven UI. It is a bit odd to not have a way to end an app, but if the user closes every activity etc Dalvik cleans up. The life cycle is well documented, but it is important to do the right things in the right place - that is what bit me about changed fields not getting displayed.

Sunday 24 July 2011

Two birds ...

My last post was about a problem with returning data from one activity to another. The post before suggested that I needed to understand the sequence of events in using an activity. Understanding the sequence of events has helped by solve the problem.

onActvityResult() does indeed get the data returned from the second activity. The fact that a second activity hid the first, meant that the first activity was forced to go though its standard sequence of events to display itself, and in there I loaded the data from the database overwriting what had been returned from the second activity.

The sequence of events is well documented - I just didn't appreciate the significance. Still, I have learned some more and experimented with using an object to hold the data for an activity. More of that later.

Friday 22 July 2011

onActivityResult

If you want to launch a new activity from an activity the startActivity() works. If you want to return a result from the second activity then startActivityForResult() also works. The result is passed back in an intent which is read by overriding onActivityResult in the first activity. Once again that seems to work.

However, if I want to use the returned info to update a textview (or an editview) it does not change. I have used .invalidate() to force a redraw, but still nothing changes. I have checked the returned info by writing a log entry and by displaying a toast, both show the data has changed, but the display doesn't change. I have no ideas why. I have wasted a couple of hours on this, so I give up.

Wednesday 20 July 2011

Getting started

I've started to use Android more and more. Building my own app seemed like the next step, so I've had a go. I have decided to write a blog, partly as a record of progress, partly as a way to write down useful stuff and partly to help clear my thinking.

Developing in isolation can be hard work, especially learning a new language or a new API. The Android environment is substantial and there's plenty to learn. I've read a few books - the best of which is the Professional Android 2 Application Development by Reto Meier. The books got me started and gave me enough information to start to write stuff for myself - which is where the real learning begins.

Android development is usually done with Java; actually a Java-like implementation known as Dalvik, but very much like Java.  I followed the recommendations of more than one place and installed Eclipse (on Ubuntu). It works well enough and I am getting used to it. I have written stuff in Java before, but not extensively. It is quite funny when the advice tells me to be very careful about memory use, the first home computer I had only had 4k of memory so an Android phone is huge by comparison. The first mainframe I wrote programs for had little more memory than that and almost no available disk space, all big files were on tape. I have long grumbled about the wasteful way programs are written, so I should be at home here.

The terms and names are quite different from other environments, but that is normal. The place information is displayed or edited is an activity. This might be a form, screen, window, frame or page elsewhere. The means of communicating between activities, and more widely uses an intent. This could be a message elsewhere. Intents are flexible, with an open-ended way of attaching data to the intent. My biggest niggle with them so far is that it is not easy to pass an object with an intent.

The recommended way of creating an activity layout is to specify an XML file that defines the layout. In fact the recommended way of specifying everything is in an XML file, so text in messages and the titles of fields should be all specified in an XML file. Part of the reason for this is that there can be multiple versions of these XML files for different device sizes and different locales and languages. This seems like a great idea, but I know that translating something is not as simple as substituting translated words. Maybe it will work well.

So far the simple stuff I've written I've stored locally and backed up to a USB disk. I think I may look into using github from Eclipse. That would provide a way to share anything that is useful and provide another copy off-site.

My next task is to understand the activity life cycle a bit better. It is vital to know what happens and when because the life cycle is not in the hands of the programmer, which feels a bit odd. I also want to understand the best way to store data being used by an activity; is that an object created for the purpose, or fields of the activity, or data attached to an intent or something I haven't seen yet. In such a heavily object-biased language as Java, I'll start there.