tag:blogger.com,1999:blog-11728623803417078882017-09-05T20:32:27.232-07:00Scala Android blogLess painful Android development with ScalaSung-Ho Leehttps://plus.google.com/101502680169820776781noreply@blogger.comBlogger39125tag:blogger.com,1999:blog-1172862380341707888.post-47971242935696402032015-12-28T04:55:00.001-08:002016-02-11T18:46:18.455-08:00Scaloid 4.1 is releasedI just released Scaloid 4.1. This version has two notable changes:<br /><br /><h3>1. Specify onClick and onLongClick at once</h3>Normally, most of the buttons does nothing on long click, because programmers doesn't specifically allocate any behavior on it. In the current touch-input UIs, there are no common visual guide for user to determine something is able to being long touched or not; So I believe that it is better for user that buttons are assigned a default behavior for long touch. However, this was generally not so fun to write:<br /><pre><code>def touched() = toast("hi!")<br />SButton("Touch me", touched()).onLongClick(touched())<br /></code></pre> From Scaloid 4.1, this can be even more compactly rewritten as: <pre><code>SButton("Touch me", toast("hi!"), 0)<br /></code></pre> The third parameter specifies an interval of repeating calls when it is press-and-hold. If we specify it as '0', it is called once. <br /><br /><h3>2. Fix a bug on LocalServiceConnection</h3>Previously, <code>LocalServiceConnection[S <: LocalService].apply(f: S => Unit)</code> gives an instance of dead service when the service is killed and newly created. Now it is fixed and always gives the correct service to the function <code>f</code>. <br /><br /><br /><h3>Using Scaloid 4.1</h3>Scaloid is released to central maven repository.<br /><br />For a maven project:<br /><pre><code>&lt;dependency&gt;<br /> &lt;groupId&gt;org.scaloid&lt;/groupId&gt;<br /> &lt;artifactId&gt;scaloid_2.11&lt;/artifactId&gt;<br /> &lt;version&gt;4.1&lt;/version&gt;<br />&lt;/dependency&gt;<br /></code></pre>or for an sbt project: <br /><pre><code>libraryDependencies += "org.scaloid" %% "scaloid" % "4.1"<br /></code></pre><br />Sung-Ho Leehttps://plus.google.com/101502680169820776781noreply@blogger.com0tag:blogger.com,1999:blog-1172862380341707888.post-43737642331698870482015-08-14T08:00:00.000-07:002015-08-14T08:00:12.494-07:00Scaloid 4.0 is releasedToday I release Scaloid 4.0, which includes lots of improvements. <br /> <h1 style="background-color:#FFFF00">Incompatible changes</h1><h3>Scaloid 4.0 is best with Android API Level 16, while still supports Level 10</h3>Scaloid 4.0 distribution is compiled with Android API Level 16, still retaining compatibility with Level 10. Accessor methods and deprecation warning is based on API Level 16, so you have to carefully check the availability of API if you target lower version of Android. In our experience on building <a href="https://play.google.com/store/apps/details?id=com.soundcorset.client.android">an App for Gingerbread</a>, currently we found no obstruction that prevents building a Scaloid app for older devices.<br /><br />To compile with Scaloid 4.0, you have to specify build time Android API in <code>project.properties</code> file as <code>android-16</code> or higher.<br /> <br /><h3>LocalServiceConnection</h3>Usual use case of <code>LocalServiceConnection</code> is: <pre><code>val service = new LocalServiceConnection[MyService]<br />//...<br />service {<br /> myService => // do something with myService<br />}<br /></code></pre> The implementation of <code>apply()</code> is changed to: <pre><code>def apply[T](f: S => Unit): Unit = service.fold(onConnected(f))(f)<br /></code></pre> The block will be executed later if the service is not connected yet. Formally it was just did nothing when the service is not connected yet. This behavior now becomes <code>ifAvailable</code>. Then all the code using <code>apply(...)</code> should be changed to <code>ifAvailable(...)</code>.<br/><br /> <h3>SArrayAdapter</h3>Constructor parameter of <code>SArrayAdapter</code> is now <code>java.util.List</code>. <br/><br/><h3>spinnerDialog</h3><code>spinnerDialog</code> returns <code>Future[ProgressDialog]</code>. <br/><br/> <h1 style="background-color:#FFFF00">End of incompatible changes</h1><br/><h3>More convenient press-and-hold action</h3> We provided the press-and-hold action callback from the last release. The sample code below increases the number on the <code>TextView</code> in every 100 milliseconds: <pre><code>val num = STextView("0")<br />SButton("Increase").onPressAndHold(100, num.text = (num.text.toString.toInt + 1).toString)<br /></code></pre> The press-and-holds has separate callback from that of clicks. Often the behavior for a click and press-and-hold are the same. In this case, we have to assign it individually: <pre><code>val num = STextView("0")<br />SButton("Increase", num.text = (num.text.toString.toInt + 1).toString)<br />.onPressAndHold(100, num.text = (num.text.toString.toInt + 1).toString)<br /></code></pre> This kind of repetition is not looks good. From Scaloid 4.0, we introduce a shorter representation: <pre><code>val num = STextView("0")<br />SButton("Increase", num.text = (num.text.toString.toInt + 1).toString, 100)<br /></code></pre> <h3>Cleaner and type-safe way to access SharedPreference</h3>SharedPreference can be accessed in this way: <pre><code>val executionCount = preferenceVar(0) // default value 0<br />val ec = executionCount() // read<br />executionCount() = ec + 1 // write<br />executionCount.remove() // remove<br /></code></pre> Refer to this post for more details:<br/><a href="http://blog.scaloid.org/2015/07/type-safe-sharedpreference.html">http://blog.scaloid.org/2015/07/type-safe-sharedpreference.html</a><br /><br /><h3>`here` method</h3>To attach a view widget to a layout, we have two major way to do it. One is using <code>apply</code> method of companion object of views: <pre><code>new SLinearLayout {<br /> SButton("Hello") textColor Color.RED<br />}<br /></code></pre> The other is creating object with <code>new</code> keyword, and assign it to the layout using <code>+=</code> method: <pre><code>lazy val button = new SButton("Hello")<br /><br />onCreate {<br /> contentView = new SLinearLayout {<br /> this += button<br /> button textColor Color.RED<br /> }<br />}<br /></code></pre> In Scaloid 4.0, we have another choice: <code></code> <pre><code>lazy val button = new SButton("Hello")<br /><br />onCreate {<br /> contentView = new SLinearLayout {<br /> button.here textColor Color.RED<br /> }<br />}<br /></code></pre> As you see, <code>this +=</code> is abbreviated with <code>.here</code>. Because it returns <code>SButton</code>, method chaining is available.<br/><br/>Oftentimes, style is applied to widgets, and sometimes we want avoid it for some widget. We provide <code>hereWithoutStyle</code> method: <pre><code>lazy val button = new SButton("Hello") textColor Color.RED<br />lazy val redBtn = new SButton("Hello") textColor Color.RED<br /><br />contentView = new SLinearLayout {<br /> style {<br /> case b: Button => b textColor Color.BLUE<br /> }<br /> button.here // blue<br /> redBtn.hereWithoutStyle // red<br />}<br /></code></pre><code>here</code> method can also be applied to layouts: <pre><code>contentView = new SVerticalLayout {<br /> new SLinearLayout {<br /> SButton("1")<br /> SButton("2")<br /> }.here<br /> SButton("3")<br />}<br /></code></pre>Sung-Ho Leehttps://plus.google.com/101502680169820776781noreply@blogger.com0tag:blogger.com,1999:blog-1172862380341707888.post-80102802139778042582015-08-06T23:22:00.001-07:002015-08-10T23:22:01.311-07:00StateListDrawable DSL for cleaner button styles.XML is wordy and not programmable. One of the major goal of Scaloid is to replace XMLs with Scala code, to be more concise, type-safe and programmable. Scaloid 4.0-RC2 provides a new way to build <code>StateListDrawable</code> without XML. For example, given the XML drawable selector: <pre><code>&lt;?xml version="1.0" encoding="utf-8"?&gt;<br />&lt;selector xmlns:android="http://schemas.android.com/apk/res/android"&gt;<br /> &lt;item android:state_checked="true"<br /> android:drawable="@drawable/drumset_on"/&gt;<br /> &lt;item android:state_checked="false"<br /> android:drawable="@drawable/drumset_off"/&gt;<br />&lt;/selector&gt;<br /></code></pre><br/>This can be written with <code>SStateListDrawable</code> as shown here: <pre><code>new SStateListDrawable {<br /> +=(R.drawable.drumset_off, -SELECTED)<br /> +=(R.drawable.drumset_on, SELECTED)<br />}<br /></code></pre> It is definitely much cleaner and programmable. For example, we can write a program that returns a single-colored drawable for buttons: <pre><code>def c(color: Int) = new ColorDrawable(color)<br /><br />def btn(normal:Int, pressed:Int) = new SStateListDrawable {<br /> +=(c(pressed), PRESSED)<br /> +=(c(Color.LTGRAY), -ENABLED)<br /> +=(c(normal))<br />}<br /></code></pre> We pass normal color and pressed color in an <code>Int</code> type color code. We can further think that pressed color can be automatically determined by a normal color; It is really easy to implement: <pre><code>def btn(normal:Int): SStateListDrawable = btn(normal, pressedColor(normal))</code></pre> <code>SStateListDrawable</code> is included in Scaloid library, and the implementation of <code>btn</code> and <code>pressedColor</code> implemented in <code>org.scaloid.util.Styles</code>, which is included in Scaloid-util package.<br/><br/>The implementation is quite straightforward, take a look at the code, and you can easily have a conception about this idea:<br/><br/><a href ="https://github.com/pocorall/scaloid/blob/4.0-RC2/scaloid-common/src/main/scala/org/scaloid/common/app.scala#L343">Source of SStateListDrawable (Scaloid package)</a><br/><a href ="https://github.com/pocorall/scaloid/blob/72efb0ce049081d8697c597cf751d1de4592073c/scaloid-util/src/main/scala/org/scaloid/util/Styles.scala#L14">Source of Styles (Scaloid-util package)</a><br/>Sung-Ho Leehttps://plus.google.com/101502680169820776781noreply@blogger.com0tag:blogger.com,1999:blog-1172862380341707888.post-834500461102413012015-07-13T07:36:00.000-07:002015-08-10T23:16:12.758-07:00Type-safe SharedPreferenceScaloid provides <a href="http://blog.scaloid.org/2013/03/dynamicly-accessing-sharedpreferences.html">a concise way to access SharedPreference</a> using type dynamic of Scala language. A sample code that demonstrate it looks like this: <pre><code>val pref = Preferences()<br />val ec = pref.executionCount(0) // read with default value 0<br />pref.executionCount = ec + 1 // write<br />pref.remove("executionCount") // remove<br /></code></pre> It is clearly better than old-Android-API, but it still has some limitations: <ul><li><b>No compile-time name checks</b><br/>If there are a typo on the key name of the preferences, compiler does not warn you. It will be a nightmare if some preference name is used in multiple places and only one has a typo.</li><li><b>Key names should be a Scala symbol name</b><br/>For example, a <code>key.name@with:special#chars</code> cannot be accessed with Scala type dynamic</li><li><b>Inconsistencies with method and preference access</b><br/>In the above example, <code>pref.remove(...)</code> is a pre-defined method call, while <code>pref.executionCount(...)</code> is a preference access. </li></ul> Scaloid 4.0-RC2 contains a new way to access Preferences. Let's look into it: <pre><code>val executionCount = preferenceVar(0) // default value 0<br />val ec = executionCount() // read<br />executionCount() = ec + 1 // write<br />executionCount.remove() // remove<br /></code></pre> It is cleaner, performs compile-time validation, and better semantics. Scala macro accesses the value name to be assigned, <code>executionCount</code> in this example. If you want a keyname has special characters, we provide an alternative: <pre><code>val executionCount = preferenceVar("execution.count", 0)<br /></code></pre> Preference values does not have a dependency on <code>android.context.Context</code> when it is created. A <code>Context</code> is only needed when it is actually being accessed (e.g. reading, writing, removing). So, it can be a property of plain object (static method in Java terms), and can be defined only once: <pre><code>object Prefs { // It ensures compile-time name checking<br /> val executionCount = preferenceVar(0)<br /> val showTips = preferenceVar("show-tips", true)<br />}<br /><br />class MyActivity extends SActivity {<br /> // access it anywhere having implicit Context<br /> if(Prefs.showTips()) displayTips() <br />}<br /></code></pre> Let's compare it with the same code written in plain-old Android API: <pre><code>object Prefs { // No idea about types, awful naming convention<br /> val EXECUTION_COUNT = "executionCount"<br /> val SHOW_TIPS = "show-tips"<br />}<br /><br />class MyActivity extends SActivity {<br /> // Wordy and not type-safe<br /> if(defaultSharedPreference.getBoolean(Prefs.SHOW_TIPS, true)) displayTips() <br />}<br /></code></pre> The full source code is listed in <a href="https://github.com/pocorall/scaloid/blob/d1318eae688a1cd13611844f5b0fda1f8eade0e9/scaloid-common/src/main/scala/org/scaloid/common/helpers.scala#L171">the Scaloid github repository</a>. This is tested on <a href="https://play.google.com/store/apps/details?id=com.soundcorset.client.android">a millionth-downloaded production app, Soundcorset</a>.Sung-Ho Leehttps://plus.google.com/101502680169820776781noreply@blogger.com0tag:blogger.com,1999:blog-1172862380341707888.post-53780002789964982292015-04-17T23:25:00.001-07:002015-04-18T04:07:37.042-07:00Scaloid 4.0 RC1 releasedToday, I released a release candidate of Scaloid 4.0. This version has several feature additions and a notable change about versioning:<br /><br /><h3>Scaloid 4.0 is best with Android API Level 16, while still supports Level 10</h3>Scaloid 4.0 distribution is compiled with Android API Level 16, still retaining compatibility with Level 10. Accessor methods and deprecation warning is based on API Level 16, so you have to carefully check the availability of API if you target lower version of Android. In our experience on building <a href="https://play.google.com/store/apps/details?id=com.soundcorset.client.android">an App for Gingerbread</a>, currently we found no obstruction that prevents building a Scaloid app for older devices.<br /><br /><h3>Notes for incompatible changes</h3>To compile with Scaloid 4.0, you have to specify build time Android API in <code>project.properties</code> file as <code>android-16</code> or higher.<br /><br /><br />Scaloid is released to central maven repository.<br /><br />For a maven project:<br /><pre><code>&lt;dependency&gt;<br /> &lt;groupId&gt;org.scaloid&lt;/groupId&gt;<br /> &lt;artifactId&gt;scaloid_2.11&lt;/artifactId&gt;<br /> &lt;version&gt;4.0-RC1&lt;/version&gt;<br />&lt;/dependency&gt;<br /></code></pre>or for an sbt project: <br /><pre><code>libraryDependencies += "org.scaloid" %% "scaloid" % "4.0-RC1"<br /></code></pre><br />Sung-Ho Leehttps://plus.google.com/101502680169820776781noreply@blogger.com0tag:blogger.com,1999:blog-1172862380341707888.post-1783373334128421262014-10-30T07:15:00.000-07:002015-01-17T20:01:35.167-08:00Scaloid 3.6 is releasedToday I released Scaloid 3.6. This version contains several feature improvements:<br /><br /><h3>More concise intents</h3>Intents often has a long list of extra attributes. Your code assigning these attributes should looks like this:<br /><pre><code>new Intent().putExtra("valueA", valueA).putExtra("valueB", valueB).putExtra("valueC", valueC)<br /></code></pre>This is a shame. Using Scala macros, I made a new function <code>put(Any*)</code> on <code>Intent</code>, that can be used like this: <pre><code>new Intent().put(valueA, valueB, valueC)<br /></code></pre> <br /><br /> <h3>Intents can be started</h3>To start an activity from the intent above, we are writing like this:<br /><pre><code>startActivity(SIntent[MyActivity].put(valueA, valueB, valueC))<br /></code></pre>This is concise, but not really readable. From this version, we can rewrite it:<br /><pre><code>new Intent().put(valueA, valueB, valueC).start[MyActivity]<br /></code></pre> This looks more natural because it can be translated one-to-one in plain English: <pre><br />Create a new Intent, and put values A, B, and C. Then, start the MyActivity.<br /></pre><br /><br /> <h3>Wrap or fill</h3>I found that I am using layout properties <code>wrap</code> and <code>fill</code> very frequently. Because layout properties should written in <code><<...>></code> blocks, we have a lot of <code><<.wrap.>></code> and <code><<.fill.>></code> in our code. These idioms makes sense in terms of consistency, but not very pleasing. Because Scaloid is not stingy with providing shorthands, I dropped out <code><<...>></code> from it.<br /><br />Now we can specify 'wrap-ness' of a TextView like this: <br /><pre><code>textView.wrap</code></pre>This looks trivial at first. However, think about how many times you are using it.<br /><br />Additionally, we provide functions <code>fw</code> and <code>wf</code>, that is equivalent to <code><<(FILL_PARENT, WRAP_CONTENT).>></code> and <code><<(WRAP_CONTENT, FILL_PARENT).>></code> respectively.<br /> <br /> <br /> <h3>Drops support Scala 2.10</h3>Scaloid 3.6 is built on Scala 2.11.3, so you can use it with other Scala 2.11.x versions. From this version, I drops Scala 2.10 support to use full potential of recent improvements on macros.<br /><br /><br /><h3>Building Scala 2.11.3 on Android</h3>I've found that building Android apps with Scala 2.11.3 (and 2.11.4) results more proguard warning, that prevents Android projects from being built. The error messages are:<br /><pre class="hljs"><br />Warning: scala.collection.SeqLike$$anon$1: can't find enclosing method 'scala.collection.mutable.Map occCounts(scala.collection.SeqLike,scala.collection.Seq)' in program class scala.collection.SeqLike<br />Warning: scala.collection.immutable.MapProxy$$anon$1: can't find enclosing method 'scala.collection.immutable.MapProxy newProxy(scala.collection.immutable.MapProxy,scala.collection.immutable.Map)' in program class scala.collection.immutable.MapProxy<br />Warning: scala.collection.immutable.SetProxy$$anon$1: can't find enclosing method 'scala.collection.immutable.SetProxy newProxy(scala.collection.immutable.SetProxy,scala.collection.immutable.Set)' in program class scala.collection.immutable.SetProxy<br />Warning: scala.collection.parallel.ParMapLike$$anon$3: can't find enclosing method 'scala.collection.parallel.IterableSplitter scala$collection$parallel$ParMapLike$$keysIterator(scala.collection.parallel.ParMapLike,scala.collection.parallel.IterableSplitter)' in program class scala.collection.parallel.ParMapLike<br />Warning: scala.collection.parallel.ParMapLike$$anon$4: can't find enclosing method 'scala.collection.parallel.IterableSplitter scala$collection$parallel$ParMapLike$$valuesIterator(scala.collection.parallel.ParMapLike,scala.collection.parallel.IterableSplitter)' in program class scala.collection.parallel.ParMapLike<br />Note: there were 1 references to unknown classes.<br /> You should check your configuration for typos.<br /> (http://proguard.sourceforge.net/manual/troubleshooting.html#unknownclass)<br />Note: there were 2 classes trying to access generic signatures using reflection.<br /> You should consider keeping the signature attributes<br /> (using '-keepattributes Signature').<br /> (http://proguard.sourceforge.net/manual/troubleshooting.html#attributes)<br />Warning: there were 5 unresolved references to program class members.<br /> Your input classes appear to be inconsistent.<br /> You may need to recompile the code.<br /> (http://proguard.sourceforge.net/manual/troubleshooting.html#unresolvedprogramclassmember)<br />[trace] Stack trace suppressed: run last android:proguard for the full output.<br /></pre>To build it successfully, add <code>"-keepattributes Signature", "-dontwarn scala.collection.**"</code> to your proguard options. Please refer to <a href="https://github.com/pocorall/hello-scaloid-sbt/commit/d1ac185531c022680dd9fe6e53762e89361f13ae">this commit log on hello-scaloid-git project</a> that illustrates this patch.<br /><br /><br /><h3>Using Scaloid 3.6.1</h3>Scaloid is released to central maven repository.<br /><br /><b>Update:</b> Scaloid 3.6 was built on Scala 2.11.3, <a href="https://issues.scala-lang.org/browse/SI-8899">that has some bug on its compiler</a>. I rebuilt Scaloid on Scala 2.11.4 and released it as 3.6.1<br /><br />For a maven project:<br /><pre><code>&lt;dependency&gt;<br /> &lt;groupId&gt;org.scaloid&lt;/groupId&gt;<br /> &lt;artifactId&gt;scaloid_2.11&lt;/artifactId&gt;<br /> &lt;version&gt;3.6.1-10&lt;/version&gt;<br />&lt;/dependency&gt;<br /></code></pre>or for an sbt project: <br /><pre><code>libraryDependencies += "org.scaloid" %% "scaloid" % "3.6.1-10"<br /></code></pre><br />Sung-Ho Leehttps://plus.google.com/101502680169820776781noreply@blogger.com1tag:blogger.com,1999:blog-1172862380341707888.post-69377265998515409382014-05-05T06:58:00.002-07:002014-05-05T22:08:43.540-07:00Scaloid 3.4 is releasedToday I released Scaloid 3.4. This version contains no new features, but reflects important policy changes:<br /><br /><h3>Recommends Scala 2.11</h3>From this version, Scaloid will be released for Scala 2.11 only. But don't worry, you can easily build your own with Scala 2.10. <br /><br /><h3>Drops Froyo support</h3>Last month, we found an <a href="http://blog.scaloid.org/2014/04/android-api-8-is-incompatible-with.html">incompatibility between Android API 8 and Scala 2.11</a>. From this version, we drop support Froyo. <br /><br /><br />Scaloid is released to central maven repository.<br /><br />For a maven project:<br /><pre><code>&lt;dependency&gt;<br /> &lt;groupId&gt;org.scaloid&lt;/groupId&gt;<br /> &lt;artifactId&gt;scaloid_2.11&lt;/artifactId&gt;<br /> &lt;version&gt;3.4-10&lt;/version&gt;<br />&lt;/dependency&gt;<br /></code></pre>or for an sbt project: <br /><pre><code>libraryDependencies += "org.scaloid" %% "scaloid" % "3.4-10"<br /></code></pre><br />Sung-Ho Leehttps://plus.google.com/101502680169820776781noreply@blogger.com1tag:blogger.com,1999:blog-1172862380341707888.post-77812955644397415622014-04-22T23:25:00.000-07:002014-04-24T17:33:37.128-07:00Android API 8 is incompatible with mutable collections from Scala 2.11I've found that newly introduced class <code>scala.collection.mutable.AnyRefMap</code> and <code>mutable.LongMap</code> are using <code>java.util.Arrays.copyOf(...)</code>, that is available only on Android API level 9 and above. This means that your Android app might not work with Froyo devices if you build it with Scala 2.11. Because the current market share of the API level &lt; 9 is less than 1 percent, this limitation is not serious.<br/><br/>However, if you stick to support older Android devices, here is a workaround:<br/><ul><li>Add <code>-dontwarn scala.collection.mutable.**</code> in your proguard settings.</li><li>Do not use <code>scala.collection.mutable.LongMap</code> and <code>mutable.AnyRefMap</code>. Make sure these classes not be called in transitive way.</li></ul>Sung-Ho Leehttps://plus.google.com/101502680169820776781noreply@blogger.com2tag:blogger.com,1999:blog-1172862380341707888.post-41667614231942597922014-04-20T06:22:00.000-07:002014-04-20T06:22:14.486-07:00Scaloid 3.3 is releasedToday I released Scaloid 3.3. This version achieves some feature enhancements including:<br /><br /><h3>Scala 2.11 support</h3>Scala 2.11 is out! We release this version of Scaloid in both of Scala 2.10 and 2.11. <br /><br /><h3>Press-and-Hold action</h3><a href="http://blog.scaloid.org/2014/04/press-and-hold-action-on-android.html">We support press-and-hold action listener for any subtype of android.view.View object.</a><br /><br /><h3>Any return type of event listener is accepted </h3>Please refer to <a href="https://github.com/pocorall/scaloid/issues/78">issue #78</a><br /><br />Scaloid is released to central maven repository.<br /><br />For a maven project:<br /><pre><code>&lt;dependency&gt;<br /> &lt;groupId&gt;org.scaloid&lt;/groupId&gt;<br /> &lt;artifactId&gt;scaloid_2.10&lt;/artifactId&gt;<br /> &lt;version&gt;3.3-8&lt;/version&gt;<br />&lt;/dependency&gt;<br /></code></pre>or for an sbt project: <br /><pre><code>libraryDependencies += "org.scaloid" %% "scaloid" % "3.3-8"<br /></code></pre><br />Sung-Ho Leehttps://plus.google.com/101502680169820776781noreply@blogger.com0tag:blogger.com,1999:blog-1172862380341707888.post-16549343750736653062014-04-19T20:37:00.000-07:002014-04-20T06:12:11.786-07:00Press-and-hold action on Android<div>Sometimes we need to receive repeated callback when a user pressing a button continuously. For example, when we make a number picker, press-and-hold on "+" button will constantly increase the number.</div><div><br /></div>Android does not support this explicitly, but we can handle this behavior with&nbsp;<code>postDelayed</code> event. Here is a link to a code snippet doing this:<br /><div><br /></div><div><a href="http://stackoverflow.com/questions/7938516/continuously-increase-integer-value-as-the-button-is-pressed">http://stackoverflow.com/questions/7938516/continuously-increase-integer-value-as-the-button-is-pressed</a></div><div><br /></div><div>This works fine, but a little remaining problem is that this code should be encapsulated to be reused in other places. I wrote the following trait doing the encapsulation:<br /><br /><pre><code>trait PressAndHoldable {<br /> def basis: android.view.View<br /><br /> class PressAndHoldListener(interval: Int, onPressed: () =&gt; Unit) extends View.OnTouchListener with View.OnLongClickListener {<br /> var autoIncrementing: Boolean = false<br /> private val repeatUpdateHandler = new android.os.Handler()<br /><br /> override def onTouch(v: View, event: MotionEvent): Boolean = {<br /> if (event.getAction == MotionEvent.ACTION_UP &amp;&amp; autoIncrementing) {<br /> autoIncrementing = false<br /> }<br /> false<br /> }<br /><br /> override def onLongClick(p1: View): Boolean = {<br /> autoIncrementing = true<br /> repeatUpdateHandler.post(new RptUpdater)<br /> false<br /> }<br /><br /> class RptUpdater extends Runnable {<br /> override def run() {<br /> if (autoIncrementing) {<br /> onPressed()<br /> repeatUpdateHandler.postDelayed(this, interval)<br /> }<br /> }<br /> }<br /> }<br /><br /> def onPressAndHold(interval: Int, onPressed: =&gt; Unit) {<br /> val listener = new PressAndHoldListener(interval, () =&gt; onPressed)<br /> basis.setOnTouchListener(listener)<br /> basis.setOnLongClickListener(listener)<br /> }<br />}<br /></code></pre><br />This trait is added on Scaloid 3.3 release. So you can just use onPressAndHold method for any <code>android.view.View</code> objects:</div> <pre><code>val num = STextView("0")<br />SButton("Increase").onPressAndHold(100, num.text = (num.text.toString.toInt + 1).toString)<br /></code></pre> Sung-Ho Leehttps://plus.google.com/101502680169820776781noreply@blogger.com0tag:blogger.com,1999:blog-1172862380341707888.post-47971712442325357222014-02-01T07:41:00.001-08:002014-03-03T16:28:23.157-08:00Scaloid 3.2 is releasedToday I released Scaloid 3.2. This version achieves some feature enhancements including:<br /><br /><h3>Properly handle TableLayout</h3><a href="https://github.com/pocorall/scaloid/issues/68">https://github.com/pocorall/scaloid/issues/68</a><br /><br /><h3>Enriched android.database.Cursor</h3><a href="http://blog.scaloid.org/2014/02/simple-enhancements-on-accessing.html">Now we can access database in more functional style.</a><br /><br /><h3>px2sp and px2dip</h3>We can simply convert pixel unit into sp unit or dip unit. <br /><pre><code>32.px2dip // convert 32 pixel into dip unit<br /></code></pre><br />Scaloid is released to central maven repository.<br /><br />For a maven project:<br /><pre><code>&lt;dependency&gt;<br /> &lt;groupId&gt;org.scaloid&lt;/groupId&gt;<br /> &lt;artifactId&gt;scaloid_2.10&lt;/artifactId&gt;<br /> &lt;version&gt;3.2-8&lt;/version&gt;<br />&lt;/dependency&gt;<br /></code></pre>or for an sbt project: <br /><pre><code>libraryDependencies += "org.scaloid" %% "scaloid" % "3.2-8"<br /></code></pre><br />Sung-Ho Leehttps://plus.google.com/101502680169820776781noreply@blogger.com0tag:blogger.com,1999:blog-1172862380341707888.post-62934223186719785182014-02-01T06:51:00.000-08:002014-03-03T16:25:42.875-08:00Simple enhancements on accessing Android built-in SqliteFunctional programming rocks. However, legacy Java libraries prevent us to stay in such an ideal world. The job objective of Scaloid is to help write Android code in more elegant style. Although Scaloid doing good job on layout building, I haven't do much things about databases yet.<br/><br/>There are many DB frameworks for Scala. If you writing an app relying on DB extensively, I recommend to use one of them. But when you are using the built-in Sqlite just for storing some casual data, it is not a bad idea that using Android APIs for database access. The biggest problem in this case is that the code is not neat, because of its API architecture. Let's see a common example:<br/><br/><pre><code>def readDailyPractice(query: String, params: Array[String]) = {<br /> var dailyTime: List[DailyPractice] = List()<br /> val c = getReadableDatabase.rawQuery(query, params)<br /> try {<br /> while (c.moveToNext()) {<br /> dailyTime = dailyTime :+ <br /> new DailyPractice(c.getString(0), c.getString(1), c.getLong(2))<br /> } <br /> } finally c.close()<br /> dailyTime<br />}<br /></code></pre><br/>We have to use variable for the return object because the <code>android.database.Cursor</code> does not provide Scala-compatible iterator. Another clutter is <code>close()</code> call in try-finally section. This can be reduced in more functional-style:<br/><br/><pre><code>def readDailyPractice(query: String, params: Array[String]) = <br /> getReadableDatabase.rawQuery(query, params).closeAfter(_.map(c => <br /> new DailyPractice(c.getString(0), c.getString(1), c.getLong(2)).toList)<br /> )<br /></code></pre><br/>By declaring <code>implicit def cursor2RichCursor(c: Cursor) = new RichCursor(c)</code>, or extending the trait <code>org.scaloid.common.DatabaseImplicits</code> to your class, The <code>android.database.Cursor</code> implicitly converted into <code>RichCursor</code>, which implements <code>Iterable[Cursor]</code>. Now, we can use many useful iterator methods such as map, foreach, and foldLeft.<br/><br/>I also introduce a function <code>closeAfter[T](body: RichCursor => T):T</code> that closes the cursor after evaluating its parameter.<br/><br/>One of the important thing that can be missed is to convert the mapped result into a List. <code>Iterator.map</code> returns another Iterator that evaluate the original iterator(RichCursor in this case) on demand. The implementation of <code>Iterator.map</code> looks like this:<br/><br/><pre><code>def map[B](f: A => B): Iterator[B] = new AbstractIterator[B] {<br /> def hasNext = self.hasNext<br /> def next() = f(self.next())<br />}<br /></code></pre><br/>So if we missed to convert the iterator to List or other form, newly created Iterator generated from the mapping will evaluate the Cursor that is already closed, and vomit the exception. This issue is too detailed, and very easy to miss at first. What we just need is iterate each rows and map a row with a domain object, and forget about cursor. So I created a wrapper function that does this mission simply:<br/><br/><pre><code>def readDailyPractice(query: String, params: Array[String]) = <br /> getReadableDatabase.rawQuery(query, params).orm(c => <br /> new DailyPractice(c.getString(0), c.getString(1), c.getLong(2)))<br /></code></pre><br/>As the name of the function implies, it does very simple form of Object-Relation-Mapping.<br/> <br/>In other cases, we often need just one record from the query result. For example, getting count of something, or retrieving some column about a particular user. Even such a simple requirement, we have to write a verbose code as:<br/><br/><pre><code>def readOneRecord(query: String, params: Array[String], default: String) = <br /> try {<br /> val c = getReadableDatabase.rawQuery(query, params)<br /> if (c.moveToFirst()) c.getString(0) else default<br /> } finally c.close()<br /></code></pre><br/>I created a helper method <code>toString(defaultVal)</code> for this purpose. We can rewrite the code above as:<br/><br/><pre><code>def readOneRecord(query: String, params: Array[String], default: String) = <br /> getReadableDatabase.rawQuery(query, params).toString(default)<br /></code></pre><br/>Other accessors, toShort, toLong, toInt, toFloat, and toDouble is available as well.<br/><br/>All of these magic can be done by the implicitly converted class <code>RichCursor</code>. The source code of <code>RichCursor</code> is very simple.<br/><br/><pre><code>class RichCursor(c: Cursor) extends Iterable[Cursor] {<br /> def iterator = new CursorIterator<br /><br /> class CursorIterator extends Iterator[Cursor] {<br /> def hasNext = c.getPosition < c.getCount - 1<br /><br /> def next() = {<br /> c.moveToNext()<br /> c<br /> }<br /> }<br /><br /> def closeAfter[T](body: RichCursor => T) = try body(this) finally c.close()<br /><br /> def orm[T](body: Cursor => T) = closeAfter(_.map(body).toList)<br /><br /> def toLong(default: Long): Long = closeAfter(csr => if (c.moveToFirst()) c.getLong(0) else default)<br /><br /> // definitions of toString, toShort... is straightforward<br />}<br /></code></pre><br/>This class is also available on Scaloid 3.2.1<br/>Sung-Ho Leehttps://plus.google.com/101502680169820776781noreply@blogger.com1tag:blogger.com,1999:blog-1172862380341707888.post-69400364305403860382013-11-28T06:27:00.001-08:002014-03-03T16:29:02.686-08:00Scaloid 3.0 is releasedToday we are pleased to announce Scaloid 3.0. Some new feature highlights are as shown below:<br /><br /><h3>Redesign of LocalServiceConnection</h3>LocalServiceConnection is redesigned to use <code>Option</code>, and prevents possibility of <code>NullPointerException</code>, which was very frequent when accessing service with <code>LocalServiceConnection</code>.<br/><br/>This is a <b style="color:RED">breaking change</b> in source code level. Please migrate the code as introduced in a blog post below:<br /><a href="http://blog.scaloid.org/2013/11/redesign-of-localserviceconnection.html">http://blog.scaloid.org/2013/11/redesign-of-localserviceconnection.html</a><br /><br /><h3>Changed SImageView(r: Int) to SImageView(r: Drawable)</h3>We believe that source level compatibility is not broken. However, rebuild is required because the parameter signature is changed.<br/><br /><a href="https://github.com/pocorall/scaloid/commit/4f708eb4017b848a1f6ae5d542435b61781473fe">https://github.com/pocorall/scaloid/commit/4f708eb4017b848a1f6ae5d542435b61781473fe</a><br /><br /><h3>SPaint support</h3>We added an initial attempt to embrace graphics feature of Android API. Please refer to <a href="http://blog.scaloid.org/2013/11/usage-driven-design-choosing-parameters.html">this blog post</a> for a design principle behind this addition.<br/><br/><a href="https://github.com/pocorall/scaloid/commit/b0dc224935a9a4c2133d0a5404a72646f04d0215">https://github.com/pocorall/scaloid/commit/b0dc224935a9a4c2133d0a5404a72646f04d0215</a><br /><br />For a maven project:<br /><pre><code>&lt;dependency&gt;<br /> &lt;groupId&gt;org.scaloid&lt;/groupId&gt;<br /> &lt;artifactId&gt;scaloid_2.10&lt;/artifactId&gt;<br /> &lt;version&gt;3.0-8&lt;/version&gt;<br />&lt;/dependency&gt;<br /></code></pre>or for an sbt project: <br /><pre><code>libraryDependencies += "org.scaloid" %% "scaloid" % "3.0-8"<br /></code></pre><br />Sung-Ho Leehttps://plus.google.com/101502680169820776781noreply@blogger.com2tag:blogger.com,1999:blog-1172862380341707888.post-75880958459657068382013-11-17T00:06:00.000-08:002014-03-03T16:27:42.802-08:00Usage driven design - choosing parametersScaloid is originally made to improve my daily life that codes Android apps. Although Scaloid relies on some core design principles that is behind of automatic wrapper generator, sometimes code can be improved from some heuristics. For example, I found that my code has several functions much like this:<br/><br/><pre><code>def createMyPaint(): Paint = {<br /> val p = new Paint()<br /> p.setColor(0xffff6666)<br /> p.setTextSize(14.sp)<br /> p<br />}<br /></code></pre><br/>Soon I added a wrapper class of <code>android.graphics.Paint</code> to Scaloid. Then the code above is improved as:<br/><br/><pre><code>def createMyPaint() = SPaint().color(0xffff6666).textSize(14.sp)<br /></code></pre><br/>All of my codes and <a href="https://www.google.com/webhp?hl=ko#q=android+%22new+paint()%22&safe=off">a Google search</a> reveals that <code>setColor()</code> is always called after a new Paint instance is initialized. It is very natural to think about a color when we tried to paint something. So I added it as the first parameter of the method <code>SPaint.apply()</code>; then the code can be rewritten as:<br/><br/><pre><code>def createMyPaint() = SPaint(0xffff6666).textSize(14.sp)<br /></code></pre><br/>We have reached the minimum code as possible.<br/><br/>This feature is shipped with Scaloid 3.0-M2. You can include this version of Scaloid into a maven project by:<br /><pre><code>&lt;dependency&gt;<br /> &lt;groupId&gt;org.scaloid&lt;/groupId&gt;<br /> &lt;artifactId&gt;scaloid_2.10&lt;/artifactId&gt;<br /> &lt;version&gt;3.0-8-M2&lt;/version&gt;<br />&lt;/dependency><br /></code></pre>or a sbt project by: <br /><pre><code>libraryDependencies += "org.scaloid" %% "scaloid" % "3.0-8-M2"<br /></code></pre>Sung-Ho Leehttps://plus.google.com/101502680169820776781noreply@blogger.com0tag:blogger.com,1999:blog-1172862380341707888.post-13312936350286466642013-11-15T05:50:00.000-08:002014-03-04T00:41:55.426-08:00Redesign of LocalServiceConnectionFor the current version of Scaloid, the type of <code>LocalServiceConnection.service</code> is <code>[S &lt;: LocalService]</code>. This value is null if the service is not yet connected. So it is exposed to the possibility of <code>NullPointerException</code>. To avoid the exception, users must check that the service is connected, as shown below:<br /><br /><pre><code>class MyService extends LocalService {<br /> def getNumber(): Int = 3<br />}<br /><br />class Activity extends SActivity {<br /> val number = new LocalServiceConnection[MyService]<br /><br /> def onButtonClick(v:View) {<br /> val num = if(number.connected) number.service.getNumber() else 0<br /> doSomethingWith(num)<br /> }<br />}<br /></code></pre><br />The problem is that the checking is very easy to forget. So I changed the type of <code>LocalServiceConnection.service</code> to <code>Option[S]</code>, so that the possibility of NPE goes away. Moreover, I added some additional helper methods that decreases clutters from your code:<br /><br /><pre><code>def onButtonClick(v:View) {<br /> val num = number(_.getNumber(), 0)<br /> doSomethingWith(num)<br />}<br /></code></pre><br />The method <code>LocalServiceConnection.apply[T](f: S =&gt; T, defaultVal: T): T</code>&nbsp;returns the result of the function f if the service is connected, and returns <code>defaultVal</code> otherwise. This is far more cleaner than the previous one.<br /><br />If we don't want to return something, and therefore we don't have any default value, we can use it as:<br /><pre><code>def onButtonClick(v:View) {<br /> number(s =&gt; doSomethingWith(s.getNumber()))<br />}<br /></code></pre>We often tests some condition and evaluates different expression according to the condition:<br/><pre><code>def onButtonClick(v:View) {<br /> val result = if(number(_.getNumber(), 0) > 10) <br /> "10 < " + number(_.getNumber()) else "fail"<br /> doSomethingWith(result)<br />}<br /></code></pre>It can also be reduced to:<br/><pre><code>def onButtonClick(v:View) {<br /> val result = number(_.getNumber() > 10, "10 < " + _.getNumber(), "fail")<br /> doSomethingWith(result)<br />}<br /></code></pre><br/>Because we have a breaking change, this feature will be shipped with Scaloid 3.0. You can evaluate this feature from the first milestone release. For a maven project:<br /><pre><code>&lt;dependency&gt;<br /> &lt;groupId>org.scaloid</groupId&gt;<br /> &lt;artifactId>scaloid_2.10&lt;/artifactId&gt;<br /> &lt;version>3.0-8-M1&lt;/version&gt;<br />&lt;/dependency&gt;<br /></code></pre>or for an sbt project: <br /><pre><code>libraryDependencies += "org.scaloid" %% "scaloid" % "3.0-8-M1"<br /></code></pre><br />Sung-Ho Leehttps://plus.google.com/101502680169820776781noreply@blogger.com0tag:blogger.com,1999:blog-1172862380341707888.post-20826846039143409702013-11-13T21:24:00.000-08:002014-08-30T01:07:16.241-07:00Using scala.concurrent.Future on AndroidFrom Scala 2.10, a concurrent execution function <code>scala.concurrent.ops.spawn</code> is deprecated, replaced with <code>scala.concurrent.Future</code>, and will be removed from Scala 2.11.<br /><br />I rewrote my app with <code>scala.concurrent.Future</code> as an <a href="http://docs.scala-lang.org/overviews/core/futures.html">official Scala documentation</a> suggests: <br /><pre><code>import ExecutionContext.Implicits.global<br />Future {<br />// ...<br />}<br /></code></pre><br />However, after I uploaded the app to Google Play, I received a ton of crash report: <br /><pre><code>java.lang.ExceptionInInitializerError<br />at scala.concurrent.impl.ExecutionContextImpl.createExecutorService(ExecutionContextImpl.scala:77)<br />at scala.concurrent.impl.ExecutionContextImpl.&lt;init&gt;(ExecutionContextImpl.scala:28)<br />at scala.concurrent.ExecutionContext$Implicits$.global$lzycompute(ExecutionContext.scala:63)<br />at scala.concurrent.ExecutionContext$Implicits$.global(ExecutionContext.scala:63)<br />at com.soundcorset.client.android.SoundcorsetService$Metronome.start(SoundcorsetService.scala:38)<br />...<br />Caused by: java.lang.Error: java.lang.NoSuchFieldException: parkBlocker<br />at scala.concurrent.forkjoin.ForkJoinPool.&lt;clinit&gt;(ForkJoinPool.java:2852)<br />... 20 more<br />Caused by: java.lang.NoSuchFieldException: parkBlocker<br />at java.lang.ClassCache.findFieldByName(ClassCache.java:510)<br />at java.lang.Class.getDeclaredField(Class.java:683)<br />at scala.concurrent.forkjoin.ForkJoinPool.&lt;clinit&gt;(ForkJoinPool.java:2847)<br />... 20 more<br /></code></pre><br />Scala library has its own copy of <code>ForkJoinPool</code> implementation, which includes dynamic invocations, that is <code>parkBlocker</code> in this case. Unfortunately, some Android devices does not have this method, so we've got this awful crash report.<br /><br />The solution is very simple: Do not use <code>ExecutionContext.Implicits.global</code>. Declare a custom implicit ExecutionContext instead. For example:<br /><pre><code>implicit val exec = ExecutionContext.fromExecutor(<br /> new ThreadPoolExecutor(100, 100, 1000, TimeUnit.SECONDS,<br /> new LinkedBlockingQueue[Runnable]))<br /><br />Future {<br />// ...<br />}</code></pre><br />This works perfect in production. <br /><br /><b>EDIT:</b> If the minimum API level of your app is above 11, consider using <a href="http://developer.android.com/reference/android/os/AsyncTask.html#THREAD_POOL_EXECUTOR">AsyncTask.THREAD_POOL_EXECUTOR</a> instead of making your own thread executor: <pre><code>implicit val exec = ExecutionContext.fromExecutor(<br /> AsyncTask.THREAD_POOL_EXECUTOR)<br /></code></pre>Thanks <a href="https://plus.google.com/+NiklasKlein-taig">Niklas Klein</a> for this suggestion. Sung-Ho Leehttps://plus.google.com/101502680169820776781noreply@blogger.com13tag:blogger.com,1999:blog-1172862380341707888.post-5505451427303087672013-11-10T08:42:00.003-08:002014-03-04T00:44:50.695-08:00Scaloid 2.5 is releasedWe announce Scaloid 2.5, which is a maintenance release.<br /><br />This version includes screen dimension queries (org.scaloid.util.Configuration) for multiple device configuration.<br /><br />You can include this version of Scaloid into a maven project by:<br /><pre><code>&lt;dependency&gt;<br /> &lt;groupId&gt;org.scaloid&lt;/groupId&gt;<br /> &lt;artifactId&gt;scaloid_2.10&lt;/artifactId&gt;<br /> &lt;version&gt;2.5-8&lt;/version&gt;<br />&lt;/dependency&gt;<br /></code></pre>or a sbt project by: <br /><pre><code>libraryDependencies += "org.scaloid" %% "scaloid" % "2.5-8"<br /></code></pre><br /><br />Next major release will be 3.0, preceded by several milestone releases.Sung-Ho Leehttps://plus.google.com/101502680169820776781noreply@blogger.com0tag:blogger.com,1999:blog-1172862380341707888.post-47558124196971522462013-09-18T22:48:00.000-07:002014-03-04T00:46:32.164-08:00Unit of measurement of TextView.setTextSize()The <a href="https://play.google.com/store/apps/details?id=com.soundcorset.client.android">Soundcorset metronome and tuner</a>, in which I wrote it with Scaloid, is keep growing and hits 70,000 downloads. Until recently, it has a strange problem that it displays very large text for some devices, so that some button texts are clipped away out of the layout. After some code investigation, I found that it is very tricky pitfall because the code does not seems to have any problem at first: <pre><code>STextView("Hello").textSize(20 sp) // not correct!<br /></code></pre> The unit specification like <code>20 sp</code> is very common in Scaloid. The implicit function <code>sp</code> converts the number from the sp unit to the pixel unit. The code above looks fine because the most of the Android API receives a size as the pixel unit. But there was a single exception. The method <code>TextView.setTextSize(float)</code> does not receives a size as the pixel unit, it receives sp unit instead. It may cause a mistake because the most of other APIs handles a size as the pixel unit, even in <code>TextView.getTextSize()</code>!!! So I overridden <code>STextView.textSize</code> so that the APIs have consistency in pixel units: <pre><code>@inline def textSize (p: Int) = textSize_=(p)<br />@inline def textSize_=(p: Int) = { <br /> basis.setTextSize(android.util.TypedValue.COMPLEX_UNIT_PX, p)<br /> basis <br />}<br /></code></pre> Now we can safely use the method <code>textSize</code> with the implicit unit conversions: <pre><code>STextView("Hello").textSize(20 sp) // correct :-D<br /></code></pre> <a href="https://github.com/pocorall/scaloid/commit/bea58f2ce0fde16d8a2822089c1f6eac75ad5fb0">I patched the current snapshot</a>, and it will be available at the next release of Scaloid. Sung-Ho Leehttps://plus.google.com/101502680169820776781noreply@blogger.com0tag:blogger.com,1999:blog-1172862380341707888.post-87457406360435875782013-09-01T19:08:00.000-07:002014-03-04T00:51:07.540-08:00Syntactic sugar for multiple device configurationThe most common question about Scaloid that I received is that how to adapt multiple device configuration.<br /><br /> Basically, a layout written in Scaloid is just an ordinary Scala code, so you can just freely composite the layout according to the device configuration: <br /><pre><code>if(width &gt; 900 dip) STextView("The display is wider than 900 dips!")<br /></code></pre><br />This is simple, concise and intuitive in compared to XML description. Moreover, this promotes the '<a href="http://en.wikipedia.org/wiki/Responsive_web_design">responsive design</a>', which adapts various screen dimensions with single layout description. <br /><br />The only problem was that we have to manually prepare required variables, such as <code>width</code> in the example above. To address this issue, I wrote a package of helper methods that can be used to determine device configurations such as screen layout and resolution in dot-per-inch. All you need is just importing <code>org.scaloid.util.Configuration._</code>. <br /><pre><code>import org.scaloid.util.Configuration._<br /><br />if(long) SButton("This button is shown only for a long screen "<br /> + "dimension ("+ width + ", " + height + ")")<br />if(landscape) this += new SLinearLayout {<br /> SButton("Buttons for")<br /> SButton("landscape layout")<br /> if(dpi &gt;= HDPI) SButton("You have a high resolution display!")<br />}<br /></code></pre>The source code is pretty straightforward. <a href="https://github.com/pocorall/scaloid/blob/master/scaloid-common/src/main/st/org/scaloid/util/Configuration.scala">Look at the source code</a> to figure out how it works.Sung-Ho Leehttps://plus.google.com/101502680169820776781noreply@blogger.com0tag:blogger.com,1999:blog-1172862380341707888.post-56499688294894370352013-08-05T01:03:00.000-07:002014-03-04T00:53:24.628-08:00Scaloid 2.3 is releasedToday I released Scaloid version 2.3. This version is a maintenance release that fixes several issues since the latest version. Major improvements include: <br /><br /><h3>More convenient and organized constructors</h3>Scaloid provided the two-argument <code>apply()</code> function for the object SButton; The first argument represents the text, and the second represents onClick behavior. <pre><code>val button = SButton("Greet", toast("hello"))<br /></code></pre><br />In this version, this kind of initialization is generalized to cover constructors of every classes that inherits <code>TextView</code>. For example: <pre><code>val textView = new STextView("Greet", toast("hello"))<br /></code></pre><br />Scaloid also provides concise initialization functions(in both constructor and apply method) for the classes that inherits <code>ImageView</code>. For example: <pre><code>val imageView = new SImageView(R.drawable.greet, toast("hello"))<br /></code></pre><br /> <h3>More general constructors for SArrayAdapter</h3>Please refer to the github issues <a href="https://github.com/pocorall/scaloid/issues/57">#57</a> and <a href="https://github.com/pocorall/scaloid/issues/58">#58</a>.<br /><br /><h3>...and several minor improvements on APIs</h3><br /> You can include this version of Scaloid into a maven project by: <pre><code>&lt;dependency&gt;<br /> &lt;groupId&gt;org.scaloid&lt;/groupId&gt;<br /> &lt;artifactId&gt;scaloid_2.10&lt;/artifactId&gt;<br /> &lt;version&gt;2.3-8&lt;/version&gt;<br />&lt;/dependency&gt;<br /></code></pre> or a sbt project by: <pre><code>libraryDependencies += "org.scaloid" %% "scaloid" % "2.3-8"<br /></code></pre>Sung-Ho Leehttps://plus.google.com/101502680169820776781noreply@blogger.com0tag:blogger.com,1999:blog-1172862380341707888.post-66362517193194160452013-06-23T03:05:00.000-07:002014-03-04T00:54:58.183-08:00Scaloid 2.1 is releasedToday I released Scaloid version 2.1.<br /><br />Improvements in this version is shown below:<br /><br /><ul><li>Fixed a regression related to SArrayAdapter</li><li>Uses ClassTag instead of ClassManifest, which is deprecated from Scala 2.10</li><li>Improved APIdoc</li><li>Covers Android API more completely (added SWebView)</li></ul><br />This version is not binary compatible with previous versions. Please clean rebuild your project to upgrade Scaloid to 2.1.<br /><br />You can include this version of Scaloid into a maven project by: <br /><pre><code>&lt;dependency&gt;<br /> &lt;groupId&gt;org.scaloid&lt;/groupId&gt;<br /> &lt;artifactId&gt;scaloid_2.10&lt;/artifactId&gt;<br /> &lt;version&gt;2.1-8&lt;/version&gt;<br />&lt;/dependency&gt;<br /></code></pre>or a sbt project by: <br /><pre><code>libraryDependencies += "org.scaloid" %% "scaloid" % "2.1-8"<br /></code></pre>Sung-Ho Leehttps://plus.google.com/101502680169820776781noreply@blogger.com1tag:blogger.com,1999:blog-1172862380341707888.post-65154950304062146142013-06-17T03:56:00.000-07:002014-03-04T00:55:37.480-08:00Scaloid 2.0 is releasedToday I released Scaloid 2.0, a new step forward to Scala+Android development.<br /><br />This version fixes several regressions that is found since the last release candidate.<br /><br />Some of the feature highlights on this version are:<br /><ul><li>Build tool is moved to sbt</li><li>New sbt based template generator, in which large part of the generation is automated (thanks guersam)</li><li>Therefore Scaloid library covers Android APIs more completely</li><li>Source code becomes more modular</li><li>Artifact and version&nbsp;naming&nbsp;is changed to sbt-style.</li></ul><br />You can include this version of Scaloid into a maven project by: <br /><pre><code>&lt;dependency&gt;<br /> &lt;groupId&gt;org.scaloid&lt;/groupId&gt;<br /> &lt;artifactId&gt;scaloid_2.10&lt;/artifactId&gt;<br /> &lt;version&gt;2.0-8&lt;/version&gt;<br />&lt;/dependency&gt;<br /></code></pre>or a sbt project by: <br /><pre><code>libraryDependencies += "org.scaloid" %% "scaloid" % "2.0-8"<br /></pre>Sung-Ho Leehttps://plus.google.com/101502680169820776781noreply@blogger.com0tag:blogger.com,1999:blog-1172862380341707888.post-42057506541220562182013-06-08T09:50:00.000-07:002014-03-04T00:56:05.184-08:00Scaloid 2.0-RC2 is releasedScaloid 2.0-RC2 is released.<br /><br />This version fixes several regression bugs from the RC1. I fixed all of the reported bug. Please test it and report issues to <a href="https://github.com/pocorall/scaloid/issues?direction=desc&amp;state=open" target="_blank">github issues page</a>.<br /><br />Some of the feature highlights on version 2.0 are:<br /><ul><li>Build tool is moved to sbt</li><li>New sbt based template generator, in which large part of the generation is automated (thanks guersam)</li><li>Therefore Scaloid library covers Android APIs more completely</li><li>Source code becomes more modular</li><li>Artifact and version&nbsp;naming&nbsp;is changed to sbt-style.</li></ul><br />You can include this version of Scaloid into a maven project by: <br /><pre><code>&lt;dependency&gt;<br /> &lt;groupId&gt;org.scaloid&lt;/groupId&gt;<br /> &lt;artifactId&gt;scaloid_2.10&lt;/artifactId&gt;<br /> &lt;version&gt;2.0-8-RC2&lt;/version&gt;<br />&lt;/dependency&gt;<br /></code></pre>or a sbt project by: <br /><pre><code>libraryDependencies += "org.scaloid" %% "scaloid" % "2.0-8-RC2"<br /></code></pre>Sung-Ho Leehttps://plus.google.com/101502680169820776781noreply@blogger.com2tag:blogger.com,1999:blog-1172862380341707888.post-16104977005293306842013-06-06T09:33:00.001-07:002014-03-04T00:56:47.754-08:00Scaloid 2.0-RC1 is releasedI just released Scaloid 2.0-RC1 to the central maven repository.<br /><br />Thanks to guersam and other contributors, Scaloid progressed large steps toward version 2.0. Some of highlights are listed below:<br /><br /><br /><ul><li>Build tool is moved to sbt</li><li>New sbt based template generator, in which large part of the generation is automated</li><li>Therefore Scaloid library covers Android APIs more completely</li><li>Source code becomes more modular</li><li>Artifact and version&nbsp;naming&nbsp;is changed to sbt-style.</li></ul><div><br />You can include this version of Scaloid into a maven project by: <br /><pre><code>&lt;dependency&gt;<br /> &lt;groupId&gt;org.scaloid&lt;/groupId&gt;<br /> &lt;artifactId&gt;scaloid_2.10&lt;/artifactId&gt;<br /> &lt;version&gt;2.0-8-RC1&lt;/version&gt;<br />&lt;/dependency&gt;<br /></code></pre>or a sbt project by: <br /><pre><code>libraryDependencies += "org.scaloid" %% "scaloid" % "2.0-8-RC1"<br /></code></pre><br /></div>We will focus on making the core library more mature, and launching optional libraries based on the new generator.<br /><br />Keep thrilling with concise and type-safe Android development!Sung-Ho Leehttps://plus.google.com/101502680169820776781noreply@blogger.com4tag:blogger.com,1999:blog-1172862380341707888.post-17793012680553921232013-04-24T22:14:00.003-07:002014-03-04T00:59:36.314-08:00Accessing widgets in view classesIn conventional Android programming, UI widgets are accessed by using <code>findViewById()</code> method as shown below: <pre><code>var name: EditText = null<br /><br />override def onCreate(b: Bundle) {<br /> super.onCreate(b)<br /> setContentView(R.layout.main)<br /><br /> name = findViewById(R.id.name).asInstanceOf[EditText]<br />}<br /><br />def printName() {<br /> println("The name is " + name.getText())<br />}<br /></code></pre> This causes some major problems:<br/><br/><li><b>Not type-safe</b><br/>You have to manually track the type of the widget, and no compile-time guarantee that you did not made any mistake. </li><li><b>The member <code>name</code> is mutable</b><br/>It is better to declare <code>name</code> as immutable because it refers only one widget. </li><li><b>Possibility of NullPointerException</b><br/>Accessing <code>name</code> before calling <code>onCreate()</code> summons NPE-the-horrible! </li><li><b>Requires extra XML configurations to maintain</b><br/>Use XML layout if you like housekeeping chores. </li><br/> In Scaloid, you can rewrite it with: <pre><code>var name: SEditText = null<br /><br />onCreate {<br /> contentView = SVerticalLayout {<br /> name = SEditText("Default name")<br /> }<br />}<br /><br />def printName() {<br /> println("The name is " + name.text)<br />}<br /></code></pre> This looks much better, because it is type-safe and eliminates XML configurations. However, the member <code>name</code> is still a mutable variable. It can be improved as shown below: <pre><code>lazy val name = new SEditText("Default name")<br /><br />onCreate {<br /> contentView = SVerticalLayout {<br /> this += name<br /> }<br />}<br /><br />def printName() {<br /> println("The name is " + name.text)<br />}<br /></code></pre> Now the member <code>name</code> is a lazy value, therefore the possiblilty of NPE is eliminated as well. Sung-Ho Leehttps://plus.google.com/101502680169820776781noreply@blogger.com8