Scala 㧠Android ã¢ããªéçº(Log ç·¨)
ãã°ãåºåããéããã°åºåä½ç½®ã®æ å ±ãä¸ç·ã«åºåããã
package com.github.cooldaemon.HelloWorld import _root_.android.util.{Log => ALog} object Log { val TAG = "HelloWorld" def e(m: String) = printlog(ALog.e, m) def w(m: String) = printlog(ALog.w, m) def i(m: String) = printlog(ALog.i, m) def d(m: String) = printlog(ALog.d, m) def v(m: String) = printlog(ALog.v, m) private def printlog(f: (String, String) => Int, m: String): Int = { val st = ((new Throwable()).getStackTrace).apply(2) f(TAG, "%s.%s(%s:%s): %s".format( st.getClassName, st.getMethodName, st.getFileName, st.getLineNumber, m )) } }
製ååºè·æã«ã¯ããã°ãåºåããªããã注æã
Scala 㧠Android ã¢ããªéçº(AsyncTask ç·¨)
ScalaでAndroidアプリ作成時、AsyncTaskの可変長引数メソッドが使えないことへの対策とサンプル ― Gist ã丸ãã¯ãªã
Scala ã¯ãå¯å¤é·å¼æ°ãæã¤ã¡ã½ãããä¸æ¸ãã§ããªãã®ã§ãå¯å¤é·å¼æ°ãä¸æ¸ãæ¸ã¿ã® /path/to/hello-world/src/main/java/com/github/cooldaemon/HelloWorld/AsyncTask.java ãä½æããã
package com.github.cooldaemon.HelloWorld; public abstract class AsyncTask<Params, Progress, Result> extends android.os.AsyncTask<Params, Progress, Result> { @Override protected Result doInBackground(Params... params) { return doInBackground(params.length > 0 ? params[0] : null); } abstract protected Result doInBackground(Params param); @Override protected void onProgressUpdate(Progress... values) { onProgressUpdate(values.length > 0 ? values[0] : null); } protected void onProgressUpdate(Progress value) {} @SuppressWarnings({"unchecked"}) protected final void publishProgress(Progress value) { super.publishProgress(value); } }
ç¨æãã AsyncTask ãç¶æ¿ãã¦ãå¥ã¹ã¬ããã§å¦çãããã¿ã¹ã¯ãè¨è¿°ããã
//å¯å¤é·å¼æ°ã使ããªãåã¯ãcase class ã§å¯¾å¿ãã case class FooParam(foo: String, bar: String) // AsyncTask ãã Activity ãæä½ãã(doInBackground ã¯é¤ã)ããã« Activity ã®ã¤ã³ã¹ã¿ã³ã¹ã渡ãã¦ãã class FooTask(val activity: FooActivity) extends AsyncTask[FooParam, Int, Either[Throwable, Unit]] { override protected def onPreExecute() { // Activity ã«å¤åãå ãããä¾ãã°ãã¤ã¢ãã°ã®è¡¨ç¤ºãªã© } // doInBackground ã ãå¥ã¹ã¬ããã§åä½ãã // doInBackground å 㧠publishProgress ã使ã㨠UI ã®ã¹ã¬ããã« Int ã®å¤ãéãã // éã£ã Int ã®å¤ã¯ onProgressUpdate ã§åãåãã override protected def doInBackground(param: FooParam): Either[Throwable, Unit] = { for { _ <- ham(param).right chick <- egg(param).right _ <- spam(param, chick).right } yield () } override protected def onProgressUpdate(progress: Int) { // ããã°ã¬ã¹ã®æ´æ° } // AsyncTask ã® cancel ã¡ã½ããã使ç¨ããã㨠onCancelled ãå¼ã°ãã override protected def onCancelled() { // doInBackground ã®åæ¢ãä¿ããä¾ãã° doInBackground ã§åç §ãã¦ãããã©ã°ã onCancelled ã§æ´æ°ãããªã© } override protected def onPostExecute(result: Either[HttpClientErrorResult, Unit]) { // Activity ã«å¤åãå ãããä¾ãã°ãã¤ã¢ãã°ãæ¶ããªã© } }
ãã®ã³ã¼ãã¯ãç»é¢ã®å転ã«å¯¾å¿ãã¦ããªãã
ç»é¢ãå転ãã㨠Activity ã®ã¤ã³ã¹ã¿ã³ã¹ã¯ç½®ãæããããã AsyncTask ã¯æ®ãç¶ããã®ã§ AsyncTask ãä¿æãã Activity ã®ã¤ã³ã¹ã¿ã³ã¹ãç½®ãæããå¿
è¦ãããã
ã¾ããç»é¢ã®å転㨠ProgressDialog ãçµã¿åãããå ´åãç»é¢å転å¾ã« ProgressDialog ãå表示ããå¿
è¦ããããonCreateDialog ã«é ¼ãäºã«ãªãã
ProgressDialog ãå表示ããå ´åã以åã® ProgressDialog é²è¡ç¶æ³ãå¼ãç¶ãã ãããã£ã³ã»ã«å¦çãæ£å¸¸ã«åä½ãããå¿
è¦ãããã®ã§ããªãã¹ãç»é¢ãå転ããªãããã«åºå®ãã¦ãããæ¹ãè¯ãã
ãããã©ããã¦ã AsyncTask + ProgressDialog + ç»é¢å転ã«å¯¾å¿ãããã®ã§ããã°ãActivity ããæä½ã§ãã AsyncTask 㨠ProgressDialog ã管çãã object ãç¨æããã
ãã®è¾ºãã¯ããã¦ã³ãã¼ãç·¨ã§è©³ãã解説ããã
Scala 㧠Android ã¢ããªéçº(AlertDialog ç·¨)
æ¯åãAlertDialog ãä½ãã®ã¯é¢åãªã®ã§ã次ã®ãããªãªãã¸ã§ã¯ããä½ã£ã¦ããã
package com.github.cooldaemon.HelloWorld import _root_.android.content.Context import _root_.android.app.{Dialog, AlertDialog => AAlertDialog} import _root_.android.content.DialogInterface object AlertDialog { def create(message: String)(f: () => Unit)(implicit c: Context): Dialog = { (new AAlertDialog.Builder(c)) .setMessage(message) .setCancelable(true) .setPositiveButton("ã¯ã", new DialogInterface.OnClickListener() { override def onClick(dialog: DialogInterface, id: Int) { f.apply() dialog.dismiss() } }) .setNegativeButton("ããã", new DialogInterface.OnClickListener() { override def onClick(dialog: DialogInterface, id: Int) { dialog.cancel() } }) .create() } }
次ã®ããã« onCreateDialog å ã§ä½¿ç¨ããã
class FooActivity extends TypedActivity { // ..snip.. object DialogID extends Enumeration { val WIFI,BLUETOOTH = Value } override protected def onCreateDialog(id: Int, args: Bundle): Dialog = id match { case id if id == DialogID.WIFI.id => AlertDialog.create("Wi-Fiè¨å®ãè¡ã") { () => startActivity(new Intent(android.provider.Settings.ACTION_WIFI_SETTINGS)) } case id if id == DialogID.BLUETOOTH.id => AlertDialog.create("Bluetoothè¨å®ãè¡ã") { () => startActivity(new Intent(android.provider.Settings.ACTION_BLUETOOTH_SETTINGS)) } } // ..snip.. }
Scala 㧠Android ã¢ããªéçº(NDK ç·¨)
ä¸æºå
å§ãã« /path/to/hello-world/project/build.scala ã次ã®ããã«ä¿®æ£ããã
// ..snip.. object AndroidBuild extends Build { lazy val main = Project ( "Hello World", file("."), settings = General.fullAndroidSettings ++ AndroidNdk.settings // ããã追å ) // ..snip.. }
次㫠/path/to/hello-world/src/main/jni/ ãä½æããã
$ make -p /path/to/hello-world/src/main/jni/
ã©ããã¼ã¯ã©ã¹ãä½ã
ãã®ã¯è©¦ãã«ãã¡ã¤ã«ã®æ å ±ãåå¾ããã©ãã /path/to/hello-world/src/main/scala/FileStat.scala ãä½æããã
package com.github.cooldaemon.HelloWorld import _root_.java.io.File import _root_.java.util.{Map => JMap} import _root_.scala.collection.JavaConversions._ object extendFileStat { implicit def fileToFileStat(file: File): FileStat = new FileStat(file) } class FileStat(file: File) { System.loadLibrary("file_stat") @native private[this] def getStat(name: String): JMap[String, Long] def stat: Map[String, Long] = mapAsScalaMap(getStat(file.toString)).toMap }
C é¢é£ã®ãã¡ã¤ã«ãç¨æãã
.class ãã¡ã¤ã«ãä½ãããä¸åº¦ã³ã³ãã¤ã«ãããã®å¾ãjavah ã§ã©ããã¯ã©ã¹ãã C ããããã¡ã¤ã«ãä½æããã
$ cd /path/to/hello-world $ sbt > compile > exit $ javah -o ./src/main/jni/file_stat.h -classpath ./target/scala-2.9.1/classes com.github.cooldaemon.HelloWorld.FileStat
sbt çµç±ã§ javah ãå®è¡ããæ¹æ³ã¯è©¦ãã¦ããªãã
Makefile ã¨ã㦠/path/to/hello-world/src/main/jni/Android.mk ãä½æããã
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := file_stat LOCAL_SRC_FILES := file_stat.c #LOCAL_C_INCLUDES += $(SBT_MANAGED_JNI_INCLUDE) include $(BUILD_SHARED_LIBRARY)
æå¾ã«ãã¡ã¤ã«æ¬ä½ /path/to/hello-world/src/main/jni/file_stat.c ãä½æããã
#include <sys/stat.h> #include "file_stat.h" jobject NewLong(JNIEnv* env, jlong value) { jclass longClass = (*env)->FindClass(env, "java/lang/Long"); jmethodID init = (*env)->GetMethodID(env, longClass, "<init>", "(J)V"); jobject longObj = (*env)->NewObject(env, longClass, init, value); (*env)->DeleteLocalRef(env, longClass); return longObj; } JNIEXPORT jobject JNICALL Java_com_github_cooldaemon_HelloWorld_FileStat_getStat (JNIEnv *env, jobject obj, jstring name) { jclass mapClass = (*env)->FindClass(env, "java/util/HashMap"); jmethodID init = (*env)->GetMethodID(env, mapClass, "<init>", "(I)V"); jobject mapObj = (*env)->NewObject(env, mapClass, init, 1); jmethodID put = (*env)->GetMethodID(env, mapClass, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); jboolean iscopy; const char *mfile = (*env)->GetStringUTFChars(env, name, &iscopy); struct stat finfo; lstat(mfile, &finfo); (*env)->CallObjectMethod(env, mapObj, put, (*env)->NewStringUTF(env, "dev"), NewLong(env, finfo.st_dev) ); (*env)->CallObjectMethod(env, mapObj, put, (*env)->NewStringUTF(env, "ino"), NewLong(env, finfo.st_ino) ); (*env)->CallObjectMethod(env, mapObj, put, (*env)->NewStringUTF(env, "mode"), NewLong(env, finfo.st_mode) ); (*env)->CallObjectMethod(env, mapObj, put, (*env)->NewStringUTF(env, "nlink"), NewLong(env, finfo.st_nlink) ); (*env)->CallObjectMethod(env, mapObj, put, (*env)->NewStringUTF(env, "uid"), NewLong(env, finfo.st_uid) ); (*env)->CallObjectMethod(env, mapObj, put, (*env)->NewStringUTF(env, "gid"), NewLong(env, finfo.st_gid) ); (*env)->CallObjectMethod(env, mapObj, put, (*env)->NewStringUTF(env, "rdev"), NewLong(env, finfo.st_rdev) ); (*env)->CallObjectMethod(env, mapObj, put, (*env)->NewStringUTF(env, "size"), NewLong(env, finfo.st_size) );
ã³ã³ãã¤ã«ãã¦ã¿ãã
$ sbt > android:ndk-build
使ç¨ãã
val f = new File(context.getFilesDir, "foo") import extendFileStat._ f.stat foreach {case (k, v) => Log.d(k + ":" + v.toString)}