{"id":1624,"date":"2013-09-16T19:35:13","date_gmt":"2013-09-16T07:35:13","guid":{"rendered":"https:\/\/www.deltics.co.nz\/blog\/?p=1624"},"modified":"2013-09-16T19:36:07","modified_gmt":"2013-09-16T07:36:07","slug":"exploring-listeners-with-oxygene","status":"publish","type":"post","link":"https:\/\/www.deltics.co.nz\/blog\/posts\/1624\/","title":{"rendered":"Exploring Listeners With Oxygene"},"content":{"rendered":"<span class=\"span-reading-time rt-reading-time\" style=\"display: block;\"><span class=\"rt-label rt-prefix\">[Estimated Reading Time: <\/span> <span class=\"rt-time\"> 3<\/span> <span class=\"rt-label rt-postfix\">minutes]<\/span><\/span><p><strong>Part 2<\/strong> in a short series demonstrating the development of a simple camera app for Android using Oxygene.  <a href=\"https:\/\/www.deltics.co.nz\/blog\/?p=1605\">In the previous instalment<\/a> 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.<\/p>\n<p><!--more--><\/p>\n<h3>A Deep-Dive Into Listener Assignment<\/h3>\n<p>So far in my simple camera app, we have only one real piece of code to speak of, and it doesn&#8217;t do very much.  I&#8217;m talking about the code that sets up the method for handling a <strong>Click<\/strong> on the <strong>Capture<\/strong> button:<\/p>\n<pre class=\"brush: oxygene; title: ; notranslate\" title=\"\">\r\n    btnCapture := Button(findViewById(R.id.button_capture));\r\n    btnCapture.OnClickListener := new interface View.OnClickListener(onClick := @CaptureClick);\r\n<\/pre>\n<p>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 <strong>Button<\/strong> element in the layout for our activity:<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\n &lt;Button\r\n  android:id=&quot;@+id\/button_capture&quot;\r\n  android:text=&quot;Capture&quot;\r\n  android:layout_width=&quot;wrap_content&quot;\r\n  android:layout_height=&quot;wrap_content&quot;\r\n  android:layout_gravity=&quot;center&quot;\r\n  android:onClick=&quot;CaptureClick&quot;\r\n  \/&gt;\r\n<\/pre>\n<p>The <strong>onClick<\/strong> attribute can be assigned the name of an appropriate method in our activity class, in this case the <strong>CaptureClick<\/strong> method.  This quite effectively demonstrates how an <strong>Oxygene<\/strong> class is &#8211; in the case of <strong>Oxygene for Java<\/strong> &#8211; nothing more nor less than a <strong>Java<\/strong> class, participating fully and directly in the <strong>Android<\/strong> &#8220;world&#8221;, like any other <strong>Java<\/strong> class would.<\/p>\n<p>This is also evident from the fact that our <strong>MainActivity<\/strong> class directly sub-classes the Android SDK <strong>Activity<\/strong> class, without the need for any bridging or wrapping.<\/p>\n<h3>Yet More Ways to Skin This Cat<\/h3>\n<p>Whether we choose to assign our listener in code or using a layout assignment doesn&#8217;t make much difference in this simple case.  So let&#8217;s look a bit more closely at the code once again:<\/p>\n<pre class=\"brush: oxygene; title: ; notranslate\" title=\"\">\r\n    btnCapture := Button(findViewById(R.id.button_capture));\r\n    btnCapture.OnClickListener := new interface View.OnClickListener(onClick := @CaptureClick);\r\n<\/pre>\n<p>This looks a bit more complicated than an event handler assignment we might be familiar with from Delphi, for example.  That&#8217;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.<\/p>\n<p>We can demonstrate this by making two small changes.<\/p>\n<p>The required interface in this case is <strong>View.OnClickListener<\/strong> and since our <strong>MainActivity<\/strong> class already contains a suitable method that satisfies this interface, albeit with the wrong name &#8211; <strong>CaptureClick<\/strong> &#8211; we could just declare support for that interface on the class.  We would of course have to rename the method to satisfy that interface:<\/p>\n<pre class=\"brush: oxygene; title: ; notranslate\" title=\"\">\r\n    MainActivity = public class(Activity, View.OnClickListener)\r\n    public\r\n      method onCreate(savedInstanceState: Bundle); override;\r\n      method onClick(v: View);\r\n    end;\r\n<\/pre>\n<p>Then, to assign the listener to the button we could simply supply a reference to the <strong>MainActivity<\/strong> class instance itself:<\/p>\n<pre class=\"brush: oxygene; title: ; notranslate\" title=\"\">\r\n    btnCapture := Button(findViewById(R.id.button_capture));\r\n    btnCapture.OnClickListener := self;\r\n<\/pre>\n<p>Again, this is perfectly fine in this simple app, but would quickly become messy if we were to use our <strong>MainActivity<\/strong> object as the &#8220;onClick&#8221; handler for multiple controls since our <strong>onClick<\/strong> method would have to cope with all the different source of possible <strong>onClick<\/strong> events, testing the <strong>View<\/strong> parameter sent with each event (equivalent in this case to the <strong>Sender<\/strong> parameter to a Delphi <strong>TNotifyEvent<\/strong>).<\/p>\n<p>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:<\/p>\n<ul>\n<li>Anonymous objects<\/li>\n<li>Extended constructor calls<\/li>\n<\/ul>\n<p>We can identify these features by dissecting the right hand side of the listener assignment.  First:<\/p>\n<pre class=\"brush: oxygene; title: ; notranslate\" title=\"\">\r\n  new interface View.OnClickListener\r\n<\/pre>\n<p>This code instantiates an anonymous <strong>Object<\/strong> via a parameterless constructor, specifying that the object implements the <strong>View.OnClickListener<\/strong> interface.  You might be questioning why I said that a parameterless constructor is invoked, given that the call appears to specify a parameter:<\/p>\n<pre class=\"brush: oxygene; title: ; notranslate\" title=\"\">\r\n    new interface View.OnClickListener(onClick := @CaptureClick);\r\n<\/pre>\n<p>This is a demonstration of an <strong>Extended Constructor Call<\/strong>, which is an <strong>Oxygene<\/strong> language feature.  This allows fields and properties of a newly created object to be initialised by appending the assignments directly in the constructor call, <em>after<\/em> any normal constructor parameters.<\/p>\n<p>Since there are no parameters to the constructor involved here, we see only the assignment to the <strong>onClick<\/strong> property.  You can think of this combination of anonymous objects and extended constructors as being equivalent to:<\/p>\n<pre class=\"brush: oxygene; title: ; notranslate\" title=\"\">\r\n  type\r\n    var obj := new interface View.OnClickListener();\r\n    obj.onClick := @CaptureClick; \r\n\r\n    btnCapture.onClick := obj;\r\n<\/pre>\n<p>Note however that in the case of anonymous, interfaced objects it is not actually quite as straight-forward as this.  This &#8220;long-hand&#8221; form of the code is not actually valid.  This is an example of an area where <strong>Oxygene<\/strong> doesn&#8217;t simply map <strong>Pascal<\/strong> onto <strong>Java<\/strong>, but provides a cleaner, <strong>Pascal<\/strong>-like syntax as an (imho) improvement over the equivalent <strong>Java<\/strong>.<\/p>\n<p>For those interested, that <strong>Java<\/strong> code would have been:<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\n  btnCapture.setOnClickListener(new OnClickListener() {\r\n \t\t\t@Override\r\n\t\t\tpublic void onClick(View arg0) {\r\n                          \/\/ TODO: take picture with the camera\r\n\t\t\t}};\r\n<\/pre>\n<h3>Time to Take a Deep Breath<\/h3>\n<p><strong>WHEW!<\/strong>  That was a <em>lot<\/em> 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 <strong>Oxygene<\/strong> imho.<\/p>\n<p>Next time I really will show how to implement a camera preview to use as a viewfinder.<\/p>\n","protected":false},"excerpt":{"rendered":"<p><span class=\"span-reading-time rt-reading-time\" style=\"display: block;\"><span class=\"rt-label rt-prefix\">[Estimated Reading Time: <\/span> <span class=\"rt-time\"> 3<\/span> <span class=\"rt-label rt-postfix\">minutes]<\/span><\/span>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 [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_feature_clip_id":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2},"jetpack_post_was_ever_published":false},"categories":[212,205,4,180],"tags":[153,215,181],"class_list":["post-1624","post","type-post","status-publish","format-standard","hentry","category-android-2","category-cooper","category-delphi","category-oxygene","tag-android","tag-cooper-2","tag-oxygene-2"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p1TKYv-qc","jetpack_sharing_enabled":true,"jetpack-related-posts":[],"_links":{"self":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/1624","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/comments?post=1624"}],"version-history":[{"count":9,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/1624\/revisions"}],"predecessor-version":[{"id":1633,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/1624\/revisions\/1633"}],"wp:attachment":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/media?parent=1624"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/categories?post=1624"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/tags?post=1624"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}