{"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=\"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=\"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_post_was_ever_published":false,"jetpack_publicize_message":"","jetpack_is_tweetstorm":false,"jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":[]},"categories":[212,205,4,180],"tags":[153,215,181],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p1TKYv-qc","jetpack_sharing_enabled":true,"jetpack-related-posts":[{"id":1658,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/1658\/","url_meta":{"origin":1624,"position":0},"title":"Crash Bang Wallop, What a Picture!","date":"19 Sep 2013","format":false,"excerpt":"The fourth and final part in the not-as-short-as-I-thought-it-would be series on building a camera app for Android using Oxygene. In this penultimate instalment we will add the capability to actually take a picture. But that won't take very long, so then we will spend a bit of time tidying up\u2026","rel":"","context":"In &quot;Android&quot;","img":{"alt_text":"Very Ugly Duckling","src":"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screenshot_2013-09-19-19-38-56-1024x640.jpg?resize=350%2C200&ssl=1","width":350,"height":200},"classes":[]},{"id":1634,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/1634\/","url_meta":{"origin":1624,"position":1},"title":"An App With View","date":"17 Sep 2013","format":false,"excerpt":"Not a Merchant Ivory production, but Part 3 in the Oxygene for Java camera app for Android series. So far we have seen that we can work directly with the Android platform manifest and layout files and how the Oxygene language is a first class citizen in the Java platform\u2026","rel":"","context":"In &quot;Android&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":1605,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/1605\/","url_meta":{"origin":1624,"position":2},"title":"Anatomy of a Camera App","date":"15 Sep 2013","format":false,"excerpt":"Part 1 in an as yet unknown number of articles using a (very) simple camera application to demonstrate building first class Android applications using \"Pascal for Java\" - i.e. Oxygene Cooper. In this first instalment we will look at the basics - the components we are going to need and\u2026","rel":"","context":"In &quot;Android&quot;","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2013-09-15-at-10.12.32-.png?resize=350%2C200&ssl=1","width":350,"height":200},"classes":[]},{"id":1503,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/1503\/","url_meta":{"origin":1624,"position":3},"title":"Sharing Code Across Platforms in Oxygene","date":"22 Aug 2013","format":false,"excerpt":"There seems to be a perception among some people that Delphi is in the unique position of allowing developers to share and re-use code across the various platforms that it's compiler can now (and will soon) target. But this is not the case. Oxygene has had this capability right from\u2026","rel":"","context":"In &quot;Cooper&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":2280,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/2280\/","url_meta":{"origin":1624,"position":4},"title":"Oxygene Constructor Magic on Cocoa","date":"30 Aug 2014","format":false,"excerpt":"Earlier this week I mentioned that I had published my TXT-2-PARK app for Android in the Google Play Store. Today I published the iOS version to the Apple App Store (still awaiting approval at this stage). As with the Android version, I implemented the iOS version using Oxygene, and things\u2026","rel":"","context":"In &quot;Android&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":1199,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/1199\/","url_meta":{"origin":1624,"position":5},"title":"Oxygene &#8220;Nougat&#8221; is Mac and iOS !","date":"06 Sep 2012","format":false,"excerpt":"Marc Hoffman has confirmed that \"Nougat\" is to Mac\/iOS as \"Cooper\" was to Java. \u00a0Some have speculated that this will be based on Mono, but Oxygene has had Mono covered for some time already, so I strongly doubt that this is the case. Far more likely is that just as\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]}],"_links":{"self":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/1624"}],"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}]}}