{"id":2240,"date":"2014-08-11T21:57:26","date_gmt":"2014-08-11T09:57:26","guid":{"rendered":"https:\/\/www.deltics.co.nz\/blog\/?p=2240"},"modified":"2014-08-12T14:13:11","modified_gmt":"2014-08-12T02:13:11","slug":"delayed-post-response","status":"publish","type":"post","link":"https:\/\/www.deltics.co.nz\/blog\/posts\/2240\/","title":{"rendered":"Delayed POST Response"},"content":{"rendered":"<span class=\"rt-reading-time\" style=\"display: block;\"><span class=\"rt-label rt-prefix\">[Estimated Reading Time: <\/span> <span class=\"rt-time\">10<\/span> <span class=\"rt-label rt-postfix\">minutes]<\/span><\/span><p>Way back in September last year, Mason Wheeler blogged about <a href=\"http:\/\/tech.turbu-rpg.com\/528\/first-look-at-oxygene\">his first experiences with developing for Android using Oxygene.<\/a>  I said at the time that I would look into reproducing his efforts and respond.<\/p>\n<p><!--more--><\/p>\n<p>I didn&#8217;t get around to that right away and, as I think I have mentioned previously, then got rather busy and honestly, I completely forgot about it.  My bad.  \ud83d\ude41<\/p>\n<p>But Mason mentioned this post again the RemObjects Talk forums recently and appears to be under the impression that he has found some fundamentally broken aspect of Android.  I think he is mistaken and ironically simply needs to take his own advice.<\/p>\n<p>The entirety of his post can be summed up in one sentence that is actually found within the post itself:<\/p>\n<blockquote><p>If you don\u2019t know anything about it, it might take a bit of time to research it. But once you do know about it, this only takes a few minutes to write, and it works.<\/p><\/blockquote>\n<p>When made in the original post this statement refers to the obscurity of the Indy-based mechanism class dealing with multipart forms.  The irony being that almost every criticism he then goes on to level at the &#8220;Android&#8221; approach to his simple problem can be dismissed with exactly the same response.<\/p>\n<h2>Threading<\/h2>\n<p>First of all there is the complaint that you are not permitted to perform network calls in the UI thread on Android.  <\/p>\n<p>But surely anybody that has done any serious network coding &#8211; even in Delphi &#8211; knows that this is just good sense.  And the same applies with Indy.  &#8220;<em>Why is my UI locking up when I make a HTTP request ?<\/em>&#8221; is a common refrain among Indy &#8220;newbies&#8221; (and not so newbies).  So I see this being enforced as no bad thing.  Start as you mean to go on and all that.<\/p>\n<p>Really, it&#8217;s not that difficult, and better to learn the right approach at the start, rather than getting into all sorts of bad habits that you are then forced to deal with only later when you have to unlearn those habits and potentially re-write a whole heap of code that you didn&#8217;t realise was going to cause you grief (so gosh-darned easy was it to write).<\/p>\n<p>But I digress.<\/p>\n<p>It is stated that <strong>AsyncTask<\/strong> is &#8220;<em>how you run something in a background thread on an Android device<\/em>&#8220;.<\/p>\n<p>Which is not quite accurate.<\/p>\n<p><strong>AsyncTask<\/strong> is only <em>one<\/em> way to achieve this, and not always the most appropriate or straightforward.  In fact, I haven&#8217;t yet felt the need to use <strong>AsyncTask<\/strong> so can&#8217;t speak to whether it is truly a &#8220;mess&#8221; or if perhaps instead simply not enough time was spent researching it for the purposes of his blog post case.<\/p>\n<p>What I can say is that one alternative that I have used, and used on this occasion &#8211; using a subclassed <strong>Thread<\/strong> &#8211; is simplicity itself and that the Android equivalent of &#8220;Synchronize()&#8221; for then performing UI updates on the UI thread is similarly straightforward, involving a simple, inline, anonymous subclass of a <strong>Runnable<\/strong> with an overridden <strong>run()<\/strong> method containing your UI code, which you then pass to the appropriate <strong>Activity.runOnUiThread()<\/strong>.<\/p>\n<p>Having said that, <strong><em>if you don\u2019t know anything about it, it might take a bit of time to research it. But once you do know about it, this only takes a few minutes to write, and it works<\/em><\/strong>.<\/p>\n<p>Here is the thread subclass:<\/p>\n<pre class=\"brush: oxygene; title: ; notranslate\" title=\"\">\r\n  POSTThread = public class(Thread)\r\n  public\r\n    method run; override;\r\n  end;\r\n<\/pre>\n<p>And here is the code in a button click listener for starting this thread:<\/p>\n<pre class=\"brush: oxygene; title: ; notranslate\" title=\"\">\r\n    new POSTThread().start;\r\n<\/pre>\n<p>I didn&#8217;t even really need an explicit class.  I could have used an anonymous, inline class for this as well, but it helped on this occasion I think to make the <strong>Thread<\/strong> more obviously explicit, for illustrative purposes.  But I&#8217;ll demonstrate anonymous inline classes when I come to show the implementation of the <strong>run()<\/strong> method at the end of this post (which will also then show how to easily perform code on the UI thread).<\/p>\n<p>Meanwhile, moving on to Mason&#8217;s next problem&#8230;<\/p>\n<h2>URLEncoded or MultipartForm ?<\/h2>\n<h3>Make up your Mind<\/h3>\n<p>Irritation is then expressed at the hassle involved in setting up a multipart form request.<\/p>\n<p>The mistake that I think was made here was that the research tool used was code completion suggestions and guesswork.  Things were identified that looked like they corresponded to the way that Indy worked, and assumptions then made about how they work.<\/p>\n<p>It certainly seems that there was no attempt to initially research how multi-part form content is best formed on Android.  For, had this been done, the Apache <strong>MultipartEntityBuilder<\/strong> class would quickly have been discovered.<\/p>\n<p>Certainly this is not part of the Android framework.  But it is an open source library that is easily added to an Oxygene project.  Simply download and unzip the jars and add two references to the solution (httpcore-4.3.2 and httpmime-4.3.5).  Yes, these are Java libraries, but Oxygene speaks Java like a native, so this is not a problem.  At all.<\/p>\n<p>Curiously, when Mason posted his <a href=\"http:\/\/stackoverflow.com\/questions\/17152713\/why-is-my-androidhttpclient-not-sending-params-when-i-call-execute\">problem on StackOverflow<\/a>, he then accepted an answer which did not actually meet his needs !<\/p>\n<p>The answer he accepted yields a <strong>x-www-form-urlencoded<\/strong> entity in his request, not a multi-part form.  It is also <em>unnecessarily complex<\/em>.<\/p>\n<p>Here&#8217;s the code for actually setting up a multi-part form request, as specified in his original Delphi\/Indy code:<\/p>\n<pre class=\"brush: oxygene; title: ; notranslate\" title=\"\">\r\n  var\r\n    req: HttpPost;\r\n    mpe: MultipartEntityBuilder;\r\n  begin\r\n    req   := new HttpPost('http:\/\/posttestserver.com\/post.php');\r\n\r\n    mpe := MultipartEntityBuilder.create;\r\n    mpe.addTextBody('Username', 'test');\r\n    mpe.addTextBody('Password', 'password');\r\n    mpe.addTextBody('cmd',      'Login');\r\n\r\n    req.Entity := mpe.build;\r\n  end;\r\n<\/pre>\n<p>Once you get there, this is hardly a million miles away from the Indy approach, is it ?  Different, yes.  Of course.  But we&#8217;re not talking <strong>Chalk vs Cheese<\/strong>.  More like <strong>Brie vs Camembert<\/strong>.  \ud83d\ude42<\/p>\n<p>Yes, it&#8217;s different when compared to Indy and <strong><em>if you don\u2019t know anything about it, it might take a bit of time to research it. But once you do know about it, this only takes a few minutes to write, and it works<\/em><\/strong>.<\/p>\n<p>You can see from this code that my test is going to make use of a generously provided <a href=\"http:\/\/www.posttestserver.com\/\">public web server specifically for testing POST requests<\/a>.  It&#8217;s not exactly complicated.  Now, this server won&#8217;t enable me to test another of Mason&#8217;s complaints (the response to a 302 redirect) but we&#8217;ll deal with that when we get to it.<\/p>\n<p>Meanwhile, worth noting is that this in fact is the bulk of the code in my entire working example.<\/p>\n<h2>It&#8217;s the Same !!<\/h2>\n<p>Mason got into such a habit of complaining about Android that he manages to accuse it of behaving in exactly the same way as Indy and turn this into a criticism.<\/p>\n<p>It is observed that the <strong>HttpPost<\/strong> class (or instance thereof) doesn&#8217;t do anything and that you have to use an <strong>HttpClient<\/strong>.  Last time I checked, the Indy <strong>TIdHttpRequest<\/strong> doesn&#8217;t do anything either.  You have to use a <strong>TIdHttp<\/strong>.  No ?<\/p>\n<p>Yes, the mechanism for issuing a request on Android is not the same as Indy, but &#8211; just as with the <strong>MultipartEntityBuilder<\/strong> &#8211; it&#8217;s not exactly complicated, and in both cases it has to be done through the HTTP client object.<\/p>\n<p>I think it&#8217;s fair to say that <strong><em>if you don\u2019t know anything about it, it might take a bit of time to research it. But once you do know about it, this only takes a few minutes to write, and it works<\/em><\/strong>.<\/p>\n<h2>Indy is Better Because Of The Bugs<\/h2>\n<p>Next on the hit-list is the way that Android handles a 302 redirect response (or rather, the way it doesn&#8217;t) to a <strong>POST<\/strong> request where Indy takes the redirect in it&#8217;s stride and handles it for him.<\/p>\n<p>Depending on the version of Indy that Mason is using, this could be an old bug in Indy.  Or, if a more recent version, he has enabled an option that restores that previous buggy behaviour.  The HTTP protocol specification stipulates that clients only automatically follow <strong>GET<\/strong> and <strong>HEAD<\/strong> 302 redirects, &#8220;MUST NOT&#8221; automatically follow them otherwise, without first confirming with the user, and should NOT change the method (to a GET).<\/p>\n<p>In fact, it seems that Mason is dealing with a buggy server as well since from the description of the redirect response he is expecting it sounds like it should be a 303 redirect, not a 302 at all.<\/p>\n<p>Mason says that his Indy code behaves exactly like a browser would.  That may be true, but perhaps only an <em>erroneously implemented<\/em> browser, dealing with an erroneously implemented server.  \ud83d\ude09<\/p>\n<p>But, if you wish to implement an auto-redirect in the same way that Indy does, it should be a simple matter to do so.  See: http:\/\/stackoverflow.com\/questions\/5169468\/handling-httpclient-redirects<\/p>\n<h2>Why Is It So Hard To Get the Response as a String !?!!<\/h2>\n<h3>Answer: It&#8217;s Not<\/h3>\n<p>Finally, the issue of obtaining the response content in a string form is bemoaned.<\/p>\n<p>&#8220;<em>Indy gives me the HTML<\/em>&#8220;.<\/p>\n<p>Well, so does Android.  Oooooh, you mean you want the HTML content in a <em>string variable<\/em> ?<\/p>\n<p>Ok:<\/p>\n<pre class=\"brush: oxygene; title: ; notranslate\" title=\"\">\r\n    str := EntityUtils.toString(response.Entity);\r\n<\/pre>\n<p>Now admittedly this is bare-bones.  You should ensure that the response is valid and that there is an Entity present to convert, but this is precisely why you would put it in a convenience method if you were doing this a lot, which is all that the Indy implementation of Post() as a function returning a string does.<\/p>\n<p>In fact, the reason that Indy put&#8217;s the Delphi equivalent in a helper method is because without that helper method, it&#8217;s darned sight more work:<\/p>\n<pre class=\"brush: delphi; title: ; notranslate\" title=\"\">\r\nvar\r\n  LResponse: TMemoryStream;\r\nbegin\r\n  LResponse := TMemoryStream.Create;\r\n  try\r\n    Post(AURL, ASource, LResponse);\r\n    LResponse.Position := 0;\r\n    Result := ReadStringAsCharset(LResponse, ResponseCharset{$IFDEF STRING_IS_ANSI}, ADestEncoding{$ENDIF});\r\n                                                                                  \r\n  finally\r\n    FreeAndNil(LResponse);\r\n  end;\r\nend;\r\n<\/pre>\n<p>If I had to do that every time in Android I would absolutely want to hide it all away in a helper method.<\/p>\n<p>But wait &#8211; that&#8217;s exactly what <strong>EntityUtils<\/strong> is, except that it is arguably a cleaner, more elegant, and more intuitive approach, providing utilities that can be used on <strong>any<\/strong> &#8220;Entity&#8221;, rather than duplicating basically identical code all over the place inside numerous wrapper methods, as is the case with Indy.<\/p>\n<p>Copy and Paste is undeniably one mechanism for code re-use, but it can be taken too far and has largely been replaced by Object Oriented techniques in the modern era.  \ud83d\ude09<\/p>\n<h2>Bringing It All Together<\/h2>\n<p>So, let&#8217;s put everything we have so far together.  This is the complete implementation of the <strong>POSTThread.run()<\/strong> method:<\/p>\n<pre class=\"brush: oxygene; title: ; notranslate\" title=\"\">\r\n  method POSTThread.run; \r\n  var\r\n    http: AndroidHttpClient;\r\n    req: HttpPost;\r\n    mpe: MultipartEntityBuilder;\r\n    response: org.apache.http.HttpResponse;\r\n    s: String;\r\n  begin\r\n    http  := AndroidHttpClient.newInstance('HTTP TEST CLIENT');\r\n    req   := new HttpPost('http:\/\/posttestserver.com\/post.php');\r\n\r\n    mpe := MultipartEntityBuilder.create;\r\n    mpe.addTextBody('Username', 'test');\r\n    mpe.addTextBody('Password', 'password');\r\n    mpe.addTextBody('cmd',      'Login');\r\n\r\n    req.Entity := mpe.build;\r\n\r\n    response := http.execute(req);\r\n    s        := EntityUtils.toString(response.Entity);\r\n  end;\r\n<\/pre>\n<p>Actually, not <em>quite<\/em> complete.  I have omitted the final statement which will update my UI with the response, which needs to be performed on the UI thread.<\/p>\n<h2>Synchronize()<\/h2>\n<p>Just as there are many ways to achieve the objective of running some code on a background thread, there are also many ways to arrange for code to be performed on the UI thread.  What I show here is perhaps the quickest and dirtiest, being almost directly equivalent to <strong>Synchronize()<\/strong>.<\/p>\n<p>As if that wasn&#8217;t bad enough, I have shamelessly exploited Oxygene&#8217;s ability to fabricate such Delphi nasties as &#8220;Global Variables&#8221;, even in the Java landscape where such things are usually impossible.  In this case, I have declared a reference to my MainActivity in a global variable (Main).  This was just to save the bother of passing the reference into the thread, saving a few seconds of typing.  But this is a demo, and saving typing is what demo&#8217;s are all about, so no harm, no foul.  \ud83d\ude42<\/p>\n<p>So, using the reference to the <strong>MainActivity<\/strong>, I call the <strong>runOnUiThread()<\/strong> method and pass in an instance of a <strong>Runnable<\/strong> class.  Runnable, as it&#8217;s name suggest, implements a <strong>run()<\/strong> method (yes, <strong>Thread<\/strong> extends <strong>Runnable<\/strong>, but we don&#8217;t need another thread here, we just want to have a <strong>run()<\/strong> method scheduled on the existing UI Thread).<\/p>\n<p>I have implemented a showResponse(String) method on my MainActivity, and all I need is for my Runnable.run() method to call it.  A whole new class just to implement a one-liner override of a scaffolding method is too much like hard work, so I use an anonymous, inline class:<\/p>\n<pre class=\"brush: oxygene; title: ; notranslate\" title=\"\">\r\n    Main.runOnUiThread(new class Runnable(run := method\r\n                                                 begin\r\n                                                   Main.showResponse(s); \r\n                                                 end));\r\n<\/pre>\n<p>And there it is, done.<\/p>\n<p>Just for completeness, here&#8217;s the method in it&#8217;s entirety:<\/p>\n<pre class=\"brush: oxygene; title: ; notranslate\" title=\"\">\r\n  method POSTThread.run; \r\n  var\r\n    http: AndroidHttpClient;\r\n    req: HttpPost;\r\n    mpe: MultipartEntityBuilder;\r\n    response: org.apache.http.HttpResponse;\r\n    s: String;\r\n  begin\r\n    http  := AndroidHttpClient.newInstance('HTTP TEST CLIENT');\r\n    req   := new HttpPost('http:\/\/posttestserver.com\/post.php');\r\n\r\n    mpe := MultipartEntityBuilder.create;\r\n    mpe.addTextBody('Username', 'test');\r\n    mpe.addTextBody('Password', 'password');\r\n    mpe.addTextBody('cmd',      'Login');\r\n\r\n    req.Entity := mpe.build;\r\n\r\n    response := http.execute(req);\r\n    s        := EntityUtils.toString(response.Entity);\r\n\r\n    Main.runOnUiThread(new class Runnable(run := method\r\n                                                 begin\r\n                                                   Main.showResponse(s); \r\n                                                 end));\r\n  end;\r\n<\/pre>\n<p>Not that this also includes setting up the <strong>AndroidHttpClient<\/strong> (<strong>http<\/strong>), which Mason omits from his code.  The method above is everything you need to make a HTTP POST request of the required form.<\/p>\n<p>Redirect handling is not addressed in this example code since I didn&#8217;t have a test server to exercise that and don&#8217;t need one for my purposes (I think I could have played some more with the test POST server to create this test, but as I say, it&#8217;s not relevant to my needs.  I&#8217;ll leave Mason to try that, if he&#8217;s so inclined).<\/p>\n<p>And here&#8217;s a <a href=\"http:\/\/posttestserver.com\/data\/2014\/08\/11\/00.55.431166108482\">logged request<\/a> made using this code on the test server referenced in the code:<\/p>\n<p><code><br \/>\nTime: Mon, 11 Aug 14 00:55:43 -0700<br \/>\nSource ip: 27.252.213.239<\/p>\n<p>Headers (Some may be inserted by server)<br \/>\nREQUEST_URI = \/post.php<br \/>\nQUERY_STRING =<br \/>\nREQUEST_METHOD = POST<br \/>\nGATEWAY_INTERFACE = CGI\/1.1<br \/>\nREMOTE_PORT = 61529<br \/>\nREMOTE_ADDR = 27.252.213.239<br \/>\nHTTP_CONNECTION = close<br \/>\nHTTP_USER_AGENT = HTTP TEST CLIENT<br \/>\nHTTP_HOST = posttestserver.com<br \/>\nCONTENT_TYPE = multipart\/form-data; boundary=g6uL0L3BNb_xNFHi_tHz4jGazg-AO-tLCvUSc<br \/>\nCONTENT_LENGTH = 574<br \/>\nUNIQUE_ID = U@h2-9Bx6hIAAAzCAfgAAAAG<br \/>\nREQUEST_TIME_FLOAT = 1407743743.6923<br \/>\nREQUEST_TIME = 1407743743<\/p>\n<p>Post Params:<br \/>\nkey: &#039;Username&#039; value: &#039;test&#039;<br \/>\nkey: &#039;Password&#039; value: &#039;password&#039;<br \/>\nkey: &#039;cmd&#039; value: &#039;Login&#039;<br \/>\nEmpty post body.<\/p>\n<p>== Multipart File upload. ==<br \/>\nReceived 0 file(s)<br \/>\n<\/code><\/p>\n<h2>It&#8217;s Really Not Difficult<\/h2>\n<p>To be clear here.  I had not tackled <strong>any<\/strong> aspect of Android networking or HTTP requests until I started looking into this 4 hours ago.  I came to this entirely &#8220;cold&#8221;.<\/p>\n<p>In fact, it took me as long to write this post (2 hours) as it did to reach a working example from a standing, cold start.  Quite why it took Mason 2 days and yet he <em>still<\/em> didn&#8217;t get it working is utterly beyond me.<\/p>\n<p>When calling upon Stack Overflow in my research I paid attention to question and answer dates, aware that things can change and that perhaps I was coming across things that had only come to light since Mason went through this exercise.  But no, they all pre-dated his post of September 2013 (with the exception of one question dealing with <strong>MultipartEntityBuilder<\/strong>, though the class itself predates Sep 2013 by some way and there are other questions on Stack Overflow that deal with it).  He should have been able to find exactly the same information that I was working from.<\/p>\n<p>I should also say that it was a fortuitous coincidence that Mason should remind me (inadvertently) of his original post on an evening where investigating the development of a HTTP client was on my to do list, so I thank him for providing such a concrete framework for that investigation !  I&#8217;ve learned a lot in 2 of the last 3 hours  \ud83d\ude42<\/p>\n<p>But as a consequence I&#8217;m afraid I cannot agree that this is particularly difficult, unless you make it so for yourself by making assumptions and constantly seeking to achieve things in the familiar ways rather than researching the new ways that you need.<\/p>\n<p>I do however agree, whole-heartedly and unreservedly, when it is said about anything that <strong><em>if you don\u2019t know anything about it, it might take a bit of time to research it. But once you do know about it, this only takes a few minutes to write, and it works<\/em><\/strong>.<\/p>\n<p>\ud83d\ude42<\/p>\n<h2>Bookends and Footnotes<\/h2>\n<p>One final note is that Mason&#8217;s post is bookended by questioning and then challenging the notion that using Oxygene on Android avoids having to take a &#8220;Java Pill&#8221;.<\/p>\n<p>In doing so he makes the common mistake of conflating a language and it&#8217;s platform\/frameworks.<\/p>\n<p>When I said in an earlier post of my own that this absence of Java Pill was one of the reasons I liked Oxygene, I was referring obviously to the <strong>LANGUAGE<\/strong>.  Of course you cannot avoid dealing with the Java &#8211; and Android &#8211; frameworks.  Working with the native platform frameworks is the very philosophy underpinning Elements !<\/p>\n<p>And with good reason: those frameworks offer a lot, if you are prepared to put the leg-work in to learning them.<\/p>\n<p>Once upon a time I am sure that Mason knew as little about Indy as he now does about Android, and I am sure his knowledge of Indy is the result of far more than the 2 days he spent trying to get his code working on Android.<\/p>\n<p>Sure, with Indy you can get a <em>lot<\/em> of networking development done very quickly in Delphi, <strong>if you know Indy<\/strong>.  But Indy is not part of the platform API (imagine doing all this in <strong>WinSocks<\/strong>!!).  It&#8217;s not even &#8211; technically &#8211; part of Delphi.  It just comes &#8220;in the box&#8221;.  And make no mistake, Indy is not free from bugs or issues itself.<\/p>\n<p>And once you know the Android frameworks just as well, you can be just as productive in those.  And as a bonus there is a much wider community of developers and resources to call on for assistance and guidance than has ever been &#8211; or will ever be &#8211; the case with Indy.<\/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\">10<\/span> <span class=\"rt-label rt-postfix\">minutes]<\/span><\/span> Way back in September last year, Mason Wheeler blogged about his first experiences with developing for Android using Oxygene. I said at the time that I would look into reproducing his efforts and respond.<\/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":[],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p1TKYv-A8","jetpack_sharing_enabled":true,"jetpack-related-posts":[{"id":2280,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/2280\/","url_meta":{"origin":2240,"position":0},"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":1713,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/1713\/","url_meta":{"origin":2240,"position":1},"title":"How to Call Java Code from an Oxygene Android Application","date":"20 Sep 2013","format":false,"excerpt":"Lachlan just posted a link to a post on Google+ (also available as a PDF) demonstrating how to call Java from Delphi XE5. I was shocked at both the amount and the nature of the code involved. It is long, convoluted and ugly stuff (nb. that isn't a criticism of\u2026","rel":"","context":"In &quot;Android&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":2202,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/2202\/","url_meta":{"origin":2240,"position":2},"title":"What is Hydrogene ?  Asked and Answered","date":"03 Dec 2013","format":false,"excerpt":"Over the past few weeks there has been some speculation as to what the mysterious \"Hydrogene\" that RemObjects have been working on may or may not be. Well, that particular feline has slipped it's captors and escaped the bag. I'm not aware of any official announcement and I hope that\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":1817,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/1817\/","url_meta":{"origin":2240,"position":3},"title":"Getting the Battery Level on Android With Delphi","date":"01 Oct 2013","format":false,"excerpt":"Over the past few days I posted a two part series showing how to obtain the current battery level as part of the implementation of an Android AppWidget using Oxygene. As far as I can tell AppWidgets simply aren't possible using Delphi but reading the battery is quite straightforward Android\u2026","rel":"","context":"In &quot;Android&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":2252,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/2252\/","url_meta":{"origin":2240,"position":4},"title":"Making a Noise About on a Thread","date":"13 Aug 2014","format":false,"excerpt":"I'm working on an Android app at the moment, and for a bit of fun I decided to add a startup sound to brighten the day of every user that launches it. Which gives me another opportunity to present some of the advanced language features in Oxygene that make threading\u2026","rel":"","context":"In &quot;Android&quot;","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Audio-Resource.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":2240,"position":5},"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":[]}],"_links":{"self":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/2240"}],"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=2240"}],"version-history":[{"count":11,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/2240\/revisions"}],"predecessor-version":[{"id":2251,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/2240\/revisions\/2251"}],"wp:attachment":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/media?parent=2240"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/categories?post=2240"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/tags?post=2240"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}