[Estimated Reading Time: 3 minutes]

Part 2 in a short series demonstrating the development of a simple camera app for Android using Oxygene. In the previous instalment we looked at the basic framework of our app. For this instalment I was going to show how to implement the camera preview or viewfinder for this instalment, but instead have decided to focus on listeners.

A Deep-Dive Into Listener Assignment

So far in my simple camera app, we have only one real piece of code to speak of, and it doesn’t do very much. I’m talking about the code that sets up the method for handling a Click on the Capture button:

    btnCapture := Button(findViewById(R.id.button_capture));
    btnCapture.OnClickListener := new interface View.OnClickListener(onClick := @CaptureClick);

The first thing to mention is that this is only one way of assigning a listener. This code was originally created for us as part of the project template, but you can assign listeners declaratively if you prefer. We could remove this code entirely and instead add an attribute to the Button element in the layout for our activity:

 <Button
  android:id="@+id/button_capture"
  android:text="Capture"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:layout_gravity="center"
  android:onClick="CaptureClick"
  />

The onClick attribute can be assigned the name of an appropriate method in our activity class, in this case the CaptureClick method. This quite effectively demonstrates how an Oxygene class is – in the case of Oxygene for Java – nothing more nor less than a Java class, participating fully and directly in the Android “world”, like any other Java class would.

This is also evident from the fact that our MainActivity class directly sub-classes the Android SDK Activity class, without the need for any bridging or wrapping.

Yet More Ways to Skin This Cat

Whether we choose to assign our listener in code or using a layout assignment doesn’t make much difference in this simple case. So let’s look a bit more closely at the code once again:

    btnCapture := Button(findViewById(R.id.button_capture));
    btnCapture.OnClickListener := new interface View.OnClickListener(onClick := @CaptureClick);

This looks a bit more complicated than an event handler assignment we might be familiar with from Delphi, for example. That’s because the listener in this case is a reference to an object that implement a specific interface, rather than being simply a reference to a specific method.

We can demonstrate this by making two small changes.

The required interface in this case is View.OnClickListener and since our MainActivity class already contains a suitable method that satisfies this interface, albeit with the wrong name – CaptureClick – we could just declare support for that interface on the class. We would of course have to rename the method to satisfy that interface:

    MainActivity = public class(Activity, View.OnClickListener)
    public
      method onCreate(savedInstanceState: Bundle); override;
      method onClick(v: View);
    end;

Then, to assign the listener to the button we could simply supply a reference to the MainActivity class instance itself:

    btnCapture := Button(findViewById(R.id.button_capture));
    btnCapture.OnClickListener := self;

Again, this is perfectly fine in this simple app, but would quickly become messy if we were to use our MainActivity object as the “onClick” handler for multiple controls since our onClick method would have to cope with all the different source of possible onClick events, testing the View parameter sent with each event (equivalent in this case to the Sender parameter to a Delphi TNotifyEvent).

Far better to create separate methods to respond to different controls, which also means we can name those methods more appropriately. And of course, this is what the original code allowed us to do. It is an example of two advanced language features:

  • Anonymous objects
  • Extended constructor calls

We can identify these features by dissecting the right hand side of the listener assignment. First:

  new interface View.OnClickListener

This code instantiates an anonymous Object via a parameterless constructor, specifying that the object implements the View.OnClickListener interface. You might be questioning why I said that a parameterless constructor is invoked, given that the call appears to specify a parameter:

    new interface View.OnClickListener(onClick := @CaptureClick);

This is a demonstration of an Extended Constructor Call, which is an Oxygene language feature. This allows fields and properties of a newly created object to be initialised by appending the assignments directly in the constructor call, after any normal constructor parameters.

Since there are no parameters to the constructor involved here, we see only the assignment to the onClick property. You can think of this combination of anonymous objects and extended constructors as being equivalent to:

  type
    var obj := new interface View.OnClickListener();
    obj.onClick := @CaptureClick; 

    btnCapture.onClick := obj;

Note however that in the case of anonymous, interfaced objects it is not actually quite as straight-forward as this. This “long-hand” form of the code is not actually valid. This is an example of an area where Oxygene doesn’t simply map Pascal onto Java, but provides a cleaner, Pascal-like syntax as an (imho) improvement over the equivalent Java.

For those interested, that Java code would have been:

  btnCapture.setOnClickListener(new OnClickListener() {
 			@Override
			public void onClick(View arg0) {
                          // TODO: take picture with the camera
			}};

Time to Take a Deep Breath

WHEW! That was a lot to take in for just one, simple button event assignment! But as you can see, this innocuous, modest looking little statement demonstrates some of the power of Oxygene imho.

Next time I really will show how to implement a camera preview to use as a viewfinder.

5 thoughts on “Exploring Listeners With Oxygene”

  1. When it’s all done are you going to compare the code to Delphi’s toy camera app they’ve been showing off? 🙂

    1. That wasn’t the intention, no. I haven’t seen the “toy camera” you refer to, and I’m not sure what sort of comparisons could meaningfully be drawn. But it might be interesting, just out of curiosity. Do you have a link ? 🙂

Comments are closed.