ラベル Android の投稿を表示しています。 すべての投稿を表示
ラベル Android の投稿を表示しています。 すべての投稿を表示

2013年3月9日土曜日

EstevaX メモ パフォーマンス測定


[EstevaX 作業日記]
   KyoroTextのコードはすべて捨てることにしました。 新たに作り直します。
   次のアプリのメタファはEstevaです。  AESTIVALISを誤記した結果、Estevaになりました。
     # Just In Time に、情報を表示すること
     # AESTIVALIS のように直感的に扱えること
   を目標とします。


[課題]
    KyoroTextの反省として、パフォーマンスの問題があります。 ちょっとした修正が、大きくパフォーマンスに影響することがありました。
    そして、このような問題をそくざに検知することができませんでした。
    今回は開発を開始したタイミングで、この問題に対応したいと考えています。

[試み]
    EstevaXでは、 パフオーマンス測定用の自動テストを作ることにTRYしてみることしました。
    具体的には、以下のような感じです。
      -A. Instrumentation#setAutomaticPerformanceSnapshots()
      -B. Aでしている事を、別の方法で実現する。
      -C. cpuの使用率を計測する。

    ○Aは「Android Application Testing Guide」 で紹介された方法です。(http://dtmilano.blogspot.jp/)
    cpuの処理時間を元に計測できるので、より良い的なことがかかれいました。
 
    ○Bは、直接必要なAPIをたたけば良いのではないか?と考えるにいたり、「PerformanceCollector(Androidのソース)」から
    APIの使い方を流用することを思いつきまた。

    ○Cは、「TOPコマンドをたたくだけで良いかな」と考えています。
 

[A. Instrumentation#setAutomaticPerformanceSnapshots()]
   Instrumentation#setAutomaticPerformanceSnapshots() を コールすると、Instrumentationが終了時に、
   以下のような素敵ログをはいてくれます。
   このうち、cpu_time execution_time に着目して、実際にプロセスが使用した時間を取得できます。
INSTRUMENTATION_RESULT: other_pss=3969
INSTRUMENTATION_RESULT: java_allocated=6146
INSTRUMENTATION_RESULT: global_freed_size=20128
INSTRUMENTATION_RESULT: native_private_dirty=16
INSTRUMENTATION_RESULT: native_free=132
INSTRUMENTATION_RESULT: global_alloc_count=1475
INSTRUMENTATION_RESULT: other_private_dirty=2880
INSTRUMENTATION_RESULT: global_freed_count=344
INSTRUMENTATION_RESULT: sent_transactions=-1
INSTRUMENTATION_RESULT: java_free=193
INSTRUMENTATION_RESULT: received_transactions=-1
INSTRUMENTATION_RESULT: pre_sent_transactions=-1
INSTRUMENTATION_RESULT: other_shared_dirty=2604
INSTRUMENTATION_RESULT: pre_received_transactions=-1
INSTRUMENTATION_RESULT: execution_time=5230398
INSTRUMENTATION_RESULT: native_size=2912
INSTRUMENTATION_RESULT: native_shared_dirty=24
INSTRUMENTATION_RESULT: cpu_time=317
INSTRUMENTATION_RESULT: java_private_dirty=1396
INSTRUMENTATION_RESULT: native_allocated=2779
INSTRUMENTATION_RESULT: gc_invocation_count=0
INSTRUMENTATION_RESULT: java_shared_dirty=8796
INSTRUMENTATION_RESULT: global_alloc_size=91221
INSTRUMENTATION_RESULT: java_pss=1685
INSTRUMENTATION_RESULT: java_size=6339
INSTRUMENTATION_RESULT: native_pss=16
INSTRUMENTATION_CODE: -1

   ためしに 私が書いたコードは、以下のところに起きました。
   https://github.com/kyorohiro/KyoroSamples/tree/master/InstrumentationSample

   adb shell am instrument -w .kyorohiro.samples.android.instrumentation/info.kyorohiro.samples.android.instrumentation.MyInstrumentation
   で動作します。



[-B. Aでしている事を、別の方法で実現する。]
    Aは使い勝手が悪いです。 instrumentationの動作が完了するまで結果が出力されまん。
    なので、別の方法をとることにしました。

    Androidの該当するコード(PerformanceCollector)を呼んでみると、対応するAPIは公開されていることがわかります。
    具体的には、SystemClock.uptimeMillis() と、 Process.getElapsedCpuTime() です。
    直接このメソッドをコールすれば、プロセスがCPUの使用している時間だけをとることができます。
    かなり便利です。そして簡単です。

    ※ためしに 私が書いたコードは、以下のところに起きました。
    https://github.com/kyorohiro/KyoroSamples/tree/master/PerformanceCheckSample
    ※ ↑はCPUの使用時間以外も、Aの場合と同等の結果を任意のタイミングで返すことができます。


   当面は、 Process.getElapsedCpuTime()を使用してパフォーマンスを測定することにしました。
   何か問題が見つかるまでは、これでいこうと考えています。

2013年2月20日水曜日

Inside KyoroStress -1- Create Low Memory Killer situation on purpose!!

 Android PF have kill alive process when heigher priority process need heap. 
 This report  explain that produce Low Memory Killer situation on purpose

 You think it so simple. just to make application to consume many heap.
 but, it difficult that your thinking way.
 following problem
  - A. Android PF restrict application java heap per one process.
  - B. heap comsuming application is killed by Android PF.
  
 This report introduce KyoroStress 's solution.

[KyoroStress solution]
  Kyoro Stress done following approach.
    - 1. Booting many service in the process of differing respectively.
    - 2. Each Service consumes a lot of heaps. 

  The problem of A is solved by booting many process, and B too,
  alive heap is more consume instead of kill service's heap 


[BigEater(consuming heap service) 's senario]
  - 1. consume the specified heap.
     if retry is true, then consuming heap is repeated repeatedly until the specified heap is consumed
  - 2. recovery killed service
     if retry is true, then repeated repeatedly until killing this working thread.
  - 3. END

 you think. if ALL Service is killed by PF, when this senario is failed.
 but no problem. PF revcovery Killed service.
 so, keeping to consuming heap situation.

[KyoroStressV2 's manual]

  # start 
   start consuming heap.
  # stop
   stop consuming heap. and release.
  # num of big eater
   booting process num.
  # eatup java heap size
   consuming heap size per one process.
  # is retry
   retry option
  # show notification
   if true, consume notification.
 # lowMoemory
   if true, mean low memory state
  # availMemory
   available memory,
  # threshold
   boundary low memory state.
  # dalvik.vm.heapsize 
   if android:largeHeap="true" 's application available heap size.
  # dalvik.vm.heapgrowthlimit
   if android:largeHeap="false" 's application available heap size.
  # lahalito
   now consuming java heap
  # kadorto
   now recovery another killed process.
  # done all task
  all task is end.

[Output]
  There is apk and source is following site 
   https://github.com/kyorohiro/KyoroStressV2
  Google Play address is following 
   https://play.google.com/store/apps/details?id=info.kyorohiro.helloworld.stressv2

2013年2月17日日曜日

KyoroStressの技術 -1- Low Memory Killer を意図的に発生させたい

[課題] Low Memory Killer を意図的に発生させたい
  Androidには、ヒープが涸渇すると使われていないアプリをKillする機能があります。
  この記事では、意図的にヒープを枯渇させて、この状態をつくる方法について説明します。
  
  単純にヒープを大量に消費するアプリを作成すれば良いように思えます。
  しかし、これだけでは上手くいきません。
    -A ひとつのアプリで消費できるヒープが制限されているため、ひとつのアプリで端末のヒープが涸渇している状態をつくれない。
    -B ヒープを涸渇しているアプリがPFにKILLされる場合がある。
   といった問題があります。

  KyoroStressV2での解決方法を紹介します。


[KyoroStressでの解決方法]
  Kyoro Stress では、以下のような方法をとりました。
    - 1. 複数のServiceを、各々異なるプロセスで起動する。
    - 2. 各々Serviceで大量のヒープを消費する。

  複数のプロセスを立ち上げれば、PFのヒープを枯渇させることができます。これで、(A)の問題が解決できました。
  また、Bについては、「生きているプロセス」が「KILLされたプロセス」の分もヒープを消費すれば上手くいけそうです。

[BigEater(ヒープ消費サービス)の動作]
  KyoroStressV2で、ヒープを消費するサービスは以下のシナリオで動作しています。
  - 1. 指定されたヒープを取得する。
     is retry が true の時、指定されたヒープを取得できるまで、1を何度も繰り返す。
  - 2. KILLされたサービスを復活させる。
       is retry が true の時、Threadが死ぬまで、何度も2を繰り返す。
  - 3. 終了
  といった感じです。
  このままでは、すべてのServiceがPFにKILLされたら上手くいかないように思うかも知れません。
  しかし、時間がたつと(数秒)、PFはKILLしたServiceを再起動します。
  このため、ServiceがすべてKILLされても、ヒープを大量に消費しようとする状態は保持されます。


[使い方]
  KyoroStressV2の操作方法について説明します。
  # start 
      ヒープの消費を開始します。
      ヒープの消費率監視を開始する。
  # stop
      ヒープの消費を終了する。そして、開放する。
  # num of big eater
      起動するプロセスの数
  # eatup java heap size
      ひとつのプロセスが消費するヒープサイズ
  # is retry
      オンならば、ヒープを確保できるまで、何度もトライする。
  # show notification
      オンならば、Notificaiotn表示をする。
 # lowMoemory
      true ならば、 ロウメモリー状態
  # availMemory
   使用可能なメモリ
  # threshold
      この値よりも低い場合は、ロウメモリー状態
  # dalvik.vm.heapsize 
      ひとつのプロセスがandroid:largeHeap="true"の時に使用可能なJavaヒープ
  # dalvik.vm.heapgrowthlimit
      android:largeHeap="false"の時に使用可能なJavaヒープ
  # lahalito
      指定されたヒープを取得しにいっている状態
  # kadorto
      PFのKILLされたサービスを再起動させようとしている状態
  # done all task
    Serviceはすべての作業を完了した。そのため、もう何もすることはない状態


[成果物]
  以下の場所にソースとAPKがあります。
   https://github.com/kyorohiro/KyoroStressV2
  Google Playでも公開しています。
   https://play.google.com/store/apps/details?id=info.kyorohiro.helloworld.stressv2

[次回]
   より、詳細な仕組みは別の記事で解説します。
 - Serviceごとに、別プロセスにする方法は?
 - アプリが使用可能なヒープを調べる方法は?
 - Low Memory 状態を取得する方法は?
 - 制限を越えてヒープを取得する方法?

-------
kyorohiro work

kyorohiro.strikingly.com

2013年2月11日月曜日

KyoroText で使用されている技術 その12 AndroidでCoverageを計測したい


[課題] カバレッジを計測したい!!


基本、アプリ作成する時は、ユニットテスト(JUnitとか)を書きながら、コードを書いていきます。
動作確認しながらコードが書けるので作業がはかどります。

しかし、自分が書いたユニットテストが想定した通りのできか?うまくテストできているか?
を確認するすべはありません。

どの程度テストできているかを定量的に客観的に数値化する方法があれば、
それらを確認するすべになります。※テスト作成のど忘れとした時に、気がつくことができます!!

KyoroTextでしようとしている方法について解説します。


客観的なデータがあれば、うまく想定したとおりにテストできていることが保障できます。
保障できないにしても心の安心を得ることはできるでしょう。


[カバレッジ]
 どの程度テストができているかを計る方法として、カバレッジという表現があります。
 まずは、AndroidでCoverageをとる方法について解説します。

 #カバレッジとは何か?
  Coverageは、テストした時にどの程度の網羅性があるかを数値化します。
  具体的には、「テストできたクラスはのどのくらい?」「テストできたメソッドはどのくらい?」
 「テストできた行はどのくらい?」といった事を計測するのです。

 例えば、以下のようなコードがあったとして
 public void test(int a) {
   if(a>10) {
      --A--
   } else {
      --B--
   }
 }
 aが、11の時だけテストしたとすると、50%のテストができたといえます。
 aが、11の時と、aが10の時をテストした場合、100%のテストができたといえます。

 このように、自分が書いたコードがテストとできているかを、客観的にあらわす事ができるのです。
 これがCoverageです。


[EMMA]
 EMMAというツールを使うことで簡単にカバレッジをとる事ができます。
 EMMAはJavaのクラスファイルを書き換えます。
 すべてのif文の前後、メソッドの先頭等に、Coverageを測定するためのコードを埋め込みます。

 EMMAは単純に、埋め込んだコード上で通過した部分を記録しておき。アプリが終了するタイミングで、そのデータをストレージ上に記録します。


[EMMA Android]
 Androidには、EMMAがすでにSDKに含まれています。
 今回はそのまま、Androidに含まれている機能を使用することにしました。
 ※ 実現方法とかは機会があれば解説したいです。今回はしません。

 1. antからビルドできるようにする。
  ---> cd {ターゲットのprojectがある場所}
  ---> android.bat update project --path .
 2. テストプロジェクトともantからビルドできるようにす。
  ---> cd {ターゲットの test projectがある場所}
  ---> android update test-project -m <ターゲットのprojectの絶対パス> -p .
 3. emma用にAPKをビルドする。
  ---> cd {ターゲットのprojectがある場所}
  ---> ant emma debug install
 4 . テストプロジェクトもビルドする。
  ---> cd {ターゲットの test projectがある場所}
  ---> ant emma debug install test


後は結果がでます。

[成果物]
#サンプルのコードを書きました。
https://github.com/kyorohiro/KyoroSamples/tree/master/EmmaSample
 - runtest.sh
   テスト実施します。
 - createbuildxml.sh
   ビルド環境を作ります。

#以下のような、Coverageの結果が出力されます。
https://github.com/kyorohiro/KyoroSamples/tree/master/EmmaSample/tests/bin

[参考]
http://d.hatena.ne.jp/halts/20120201/p1
http://blog.pboos.ch/post/35269158339/android-coverage-report-for-unit-tests


[次回]
Google Playで、KyoroStressが1000ダウンロードを超えました。KyoroStressについて解説します。
Androidで、アプリが殺されるタイミングは何?殺された時、殺された後のアプリの動作は何?
といった事を解説します。

2013年1月27日日曜日

KyoroText で使用されている技術 その11




[課題] Terminalっぽいことを、してみたい。

私はxyzzyというEditorを愛用しています。xyzzyには、Editorからshellを操作する機能があります。
「KyoroTextにも、Shellモードが欲しいなぁ~」と考えていました。

ためしに実装してみたら、そこそこ動いたので簡単に紹介します。


[問題]
 Googleを多様して、以下のような問題を解決できました。
 -A Androidで、CLIアプリを動作させめ方法は?
 -B cd した後の、現在参照しているフォルダを利用したい?


[A] Androidで、CLIアプリを動作させる方法は?
 自分以外のAndroidアプリを起動する場合、通常は、Intentを使用します。
「cd」「ls」dateといった。/system/bin配下にあるネイティブアプリを動作させるには、
 どうすれば良いのでしょうか? Intentで実現できるのでしょうか?

 Runtimeクラス、ProcessBuilderクラスで実現できます。
 細かな使い方は、Google先生に聞くと良いでしょう。

 KyoroTextでは、以下のようなコードを書きました。
 https://github.com/kyorohiro/KyoroHelloAndroid/tree/master/KyoroCommon/src/info/kyorohiro/helloworld/util/shell
 CLIAppKicker

>
>   CLIAppKicker#start(String command)
>
startを呼ぶとCLIアプリを起動します。


 [B] cd した後の、現在参照しているフォルダを利用したい?

「Aの問題」が解決しました。なので、「ls」使いたい時は、「CLIAppKicker#start("ls")」
 とすれば、「ls」が呼べます。

 しかし、うまくいかない場合があります。
「cd」です。

 以下のようなシナリオを考えてみましょう。
  1. "/" にいる。
  2. cd mnt とする。
  3. cd sdcard
 として、SDカード配下に移動したいとする。

  1. CLIAppKicker#start("cd mnt")
  2. CLIAppKicker#start("cd sdcard")
 のようなコードで実現できそうです。しかし、
 子プロセスの情報は引き継がれません。

  1. CLIAppKicker#start("cd mnt")
  ---> /mntい移動する。
  2. CLIAppKicker#start("cd sdcard")
  --> /sdcardに移動する。
 となり、思い通りの場所(/mnt/sdcard)に移動できません。




 この問題は、CLIAppKicker#start("sh") とすることで解決できます。
 KyoroTextでは、以下のようなコードを書きました。
 https://github.com/kyorohiro/KyoroHelloAndroid/tree/master/KyoroCommon/src/info/kyorohiro/helloworld/util/shell
 CmdSession.java




[気をつけた点]
 topコマンドなど、プロセスが動作し続けるアプリでは、「InputStream#available() == 0」の状態で、InputStream#read()すると、次へ進まなくります。データが入力されるまで待機するためです。
なので、必ず、「InputStream#available() > 0」ことを確認してから、InputStream#read()する
ようにしました。



[次回]
テスト自動化はできた!!どのくらいテストできたか定量的に客観的にしりたい!!
どうすればよいでしょうか?
次回はEMMAというテストカバレッジツールを使用する方法について解説します。


2013年1月19日土曜日

KyoroText で使用されている技術 その10


[課題] File#listFiles(FileFilter filter) を中断できるようにしたい

KyoroTextはテキストビューアなので、ファイルシステムからテキストファイルを選択して、開く機能が必要です。

解決すべきシナリオは、
アプリ  : 1. ファイルシステム上のファイルの一覧を表示する。
ユーザー: 2. ファイルまたはフォルダーを選択する。
アプリ  : 3. 選択されたものがファイルならば、テキストとして表示する。フォルダならば、1に戻る。
といった感じでとても単純です。

しかし、ちょっとした罠があります。それは、「一覧表示すべきファイルの数: 0~無限」ということです。
大量のファイルを表示する場合、以下の問題が発生します。
[A] 一覧を出すのに時間がかかる。 
[B] 一覧表示すべきファイルの数は、ヒープに収まらないこともありえる。

たとえば、[A]については、端末起動直後などに10000件程度のファイル一覧を取得する場合、10秒以上待たされる場合もありました。
つまり、Thread#interrupt()が呼ばれても、最悪10秒以上は処理を返さないことがあるということです。


 [Androidの作り] 
// 
// 実際のコードです。
//
    public File[] listFiles(FileFilter filter) {
        File[] files = listFiles();
        if (filter == null || files == null) {
            return files;
        }
        List result = new ArrayList(files.length);
        for (File file : files) {
            if (filter.accept(file)) {
                result.add(file);
            }
        }
        return result.toArray(new File[result.size()]);
    }

[A]、[B] の各々はJava側では解決する方法はなさそうですね!!


 [KyoroTextの解決方法] 

[A]に時間がかかることはあきらめて、中断できる機能を追加することにしました。

1. File#listFiesの呼び出す時は、専用のスレットを呼び出す。
2. 1の処理が終わるまで待つ。
3. もしも、Thread#interruptが呼ばれたら、File#listFilesの処理が終わるのを待つのをやめる。

具体的には、以下のような機能を用意しました。

#AsyncronousTaskクラス

 AsyncronousTask atask = new AsyncronousTask#AsyncronousTask(Runnable 作業完了を監視したいタスク)
  Thread runner = new Thread(atask);
  runner.start();
  if(atask.syncTask()) {
     // タスクが完了した。
  } else {
     // interruptされた
  }

https://github.com/kyorohiro/KyoroHelloAndroid/blob/master/KyoroCommon/src/info/kyorohiro/helloworld/util/AsyncronousTask.java

https://github.com/kyorohiro/KyoroHelloAndroid/blob/master/KyoroCommon/src/info/kyorohiro/helloworld/util/FileListGetter.java

 [PS] 

次回、今回のAsyncronousTaskを使用する方法だと、使用する側は、AsyncronousTaskと監視対象の両方のクラスを制御しなくてはならない。これを一つにまとめると、使いやすさがUPします。
KyoroTextでおこなった方法について説明します。

キーワードは、Future Task 



2013年1月14日月曜日

KyoroText で使用されている技術 その9


InputConnectionの使い方の説明は、家に帰って動作確認しながらでないと、
記事が書けないようです。
家に帰ったら、別の事がしたなって、全然ブログま更新ができていませんでした。

InputConnectionの使い方の説明が終わるまでは、次には進まないぞ!!と考えていましたが、
やめました。

※ 通勤中に電車の中で書けるような事でないとダメみたい。


[課題] 走らせるスレッドを制限したい その1

同時に複数のスレッドごりごり走ると、低性能な端末だとダメダメな感じです。
なので、スレッド数をある程度管理化におく必要があります。
なおかつ、あまり、作業を作る側は、管理している側を意識したくない。


[KyoroTextでの解決]
  同時にひとつだけ、Threadが動く事を保障したクラスを用意しておいて。
  作業(Runnable)をそのクラスに渡す。

[パターン]
 いくつかパターンがあります。例えば、
- 1  指定された作業をキューにつんで置いて、順番にアクセスする。
- 2  作業が指定されたら、他の作業をすべて殺して、その作業を優先する。
- 3  等々

今回は、-2をとりました。

[作り]
 使う側は、とりあえず、以下のメソッドに依頼したい作業を指定するだけ。
  SingleTaskRunner#start(Runnable task)

 管理側
  1. 動作中のThreadを中断する。
  2. joinして、Threadが終了するのを待つ
  3. 新しい作業を開始する。
 
 ちょっと工夫した点は、1.、2、3 の作業を、別スレッドで行うようにしたところ。
 このstartメソッドを呼び出した側がロックを開放しないと、今動作中のThreadが終了しない
 といった事がおきると困のます。なので、別スレッドにしておくほうが安全です。
※ 工夫したというよりは、上記が理由で、KyoroTextにて、デットロックを起こしてしまったので、直したという表現がただしい。

[中身] 
 https://github.com/kyorohiro/KyoroHelloAndroid/blob/master/KyoroCommon/src/info/kyorohiro/helloworld/util/SingleTaskRunner.java


[次回のネタ]
- データ保存操作だとかを、バックグラウンドで実施したい。しかし、バックグラウンドへ移動すると、PFから、プロセスキルされる可能性が高くなります。(※例えServiceと動作していても)
  KyoroTextでの、プロセスキルへの対策を説明します。
  キーワードは、 low memory killer,  taskmanager, process kill

2013年1月1日火曜日

KyoroText で使用されている技術 その8



その7の続き...


[小課題] SurfaceViewでEditorを作る。その1 
- 未確定文字と確定文字について


 確定文字と未確定文字の扱いについて説明します。

 日本語を入力する場合、一旦、「ひらがな」を入力した後で、「漢字」に変換します。この変換される前の状態を
「未確定文字」、変換後の状態を「確定文字」と呼ぶことにします。

 例えば、「お腹が空いた」と入力したい場合、
 1. 「おなかがすいた」と未確定文字を入力
 2. 「お腹が空いた」と確定文字に変換
 となります。


 APIの流れを見てみましょう。
   1. IMEアプリ : フォーカスがあるViewから、InputConnectionを取得する。
   2. IMEアプリ : InputConnection#setComposingText("おなかがすいた", 1);
   3. Editor    : 未確定文字をユーザーに表示
   4. IMEアプリ : InputConnection#inputCommitText("お腹が空いた", 1);
   5. Editor    : 確定文字として、テキストを更新


[サンプル]
 - 上記シナリオをInstrumentationで記載しました。ログを仕込めば、APIの流れがわかります。
  https://github.com/kyorohiro/KyoroSamples/blob/master/KyoroSampleSurfaceViewEditor/src/info/kyorohiro/samples/android/test/CheckForComposingText.java



[PS]

 -  setComposingText()、inputCommitText() で渡されるテキストについて 
  setComposingText()、inputCommitText() で渡されるテキストはCharSequenceです。
  Spannable装飾ありのテキストが渡さることがあります。

  例えば、「<|>」をカーソルとします。「おなかがすいた」と入力した後で、
 「おなか」だけを変換したい場合、以下のようなシナリオになります。
 1.「おなかがすいた<|>」と入力
  2.「おなか<|>がすいた」と移動
  3.「お腹<|>がすいた」と変換
  4.「お腹がすいた<|>」と確定する。

  ほとんどの場合、この時のカーソル位置は、Editor側のカーソルではありません。
  IMEのものです。装飾ありのテキストを使用して表現されます。
  例えば、  「おなか<|>がすいた」は、「おなか」の部分の背景色をグレーにするとかしています。

  ※ このような変換処理は、IMEアプリ側がやってくれるわけですが、
     Editor側は、装飾情報を解析して、ユーザーに表示してあげる必要があります。


 -  setComposingText()、inputCommitText() で渡されるnewCursorPositionについて
Editor側のカーソル位置を表しています。
 * 0 の時、「<|>お腹がすいた」
 * 1 の時、「お腹がすいた<|>」

となります。




2012年12月26日水曜日

KyoroText で使用されている技術 その7


[課題] SurfaceViewでEditorを作る。


このページにアクセスする人を増やすため、
特定のAndroid APIをネタに記事を書くことにしました。

kyorohiroが良く知っているけど、ググッても得られない情報がありました。
SurfaceView上にEditorを実現する方法です。

これを読めば、OpenGlで書かれたEditor!!なんかも簡単に作れるようになるかも知れまもせん。

[構成]

 KyoroTextから、IME関連のエッセンスを抜き取って単体アプリ化しました。
これをサンプルとして、APIの解説をします。「KyoroSampleSurfaceViewEditor」といいます。5-6回に分割してAPIを解説する予定です。

これによりにより、以下のような効能があります。
- InputConnection の使い方が理解できます。
- InputMethodServiceを理解して、android用のソフトウェアキーボードを作成できるようになります。
- また、上記の機能のテストを作成したりする際に必要な知識が手に入ります。
※ 一部だけですが..。


[サンプルコード]
https://github.com/kyorohiro/KyoroSamples
の、KyoroSampleSurfaceViewEditorです。

ソースをコピーした後で、「Eclipse->File->Import->Existing Projects into WorlSpace」
よりプロジェクトをインポートしてご利用ください。


[次回]
今回は内容の紹介だけです。
次回から、APIの解説します。




2012年12月24日月曜日

KyoroText で使用されている技術 その6


この記事を読む人はカナリ少ないです。
今読んでいる「あなた」、もしかすると「あなた」だけかもしれません。 
.. そんな、「あなた」だけがための今回の課題は、「ヒープに収まらないテキストを編集したい」です!! 


[課題]ヒープに収まらないテキストを編集したい 


KyoroTextはでっかいデータをノータイムで表示できる事を実現したアプリです。 
なので、KyoroTextで編集するデータはヒープに収まらないデータとなります。 

ヒープに収まらないデータの一部を変更/編集したい場合、どうすればよいでしょうか? 
KyoroTextでとった方法を解説します。 



[作戦] 
パパパッと思いついた作戦は、以下の2つです。 
  -a 変更したところだけ記録する。 
  -b 内部ストレージを、ヒープであるかのように使用する。適当にキャッシュして、ストレスなく扱えるように調整する。 

「-a」を実現するLogicは直ぐに思いついたのですが、「-b」を、実現するLogicは直ぐに思いつきませんでした。また、応答速度の最悪値が、良く無い場合には、うまく同期させる機能が必要になるかもしれません。 
とりあえず、簡単に実現できそうな、「-a」を実装することにしました。 


[変更点だけ記録する方法] 

  KyoroTextで採用したデータ構造はかなり単純です。 
  以下のような情報を持ったデータをListに記録しているだけです。 
   -「N行目にデーターを追加した」 
   -「N行目のデーターを削除した」 

  「テスト」と「UNDO/REDOの実装」が簡単になるように、「追加」「削除」の2つだけにしました。これだけで、編集前と変種後の差分を全て表現できます。例えば、「特定の行のテキストを置換する場合」には、以下のような感じで表せます。 
   1. 置換する行を削除する。 
   2. 置換した後のテキストを、削除した行に追加する。 


これならば、簡単に実現できそうですね!! 


具体的には、以下のような感じになりました。 改善の余地はかなりある。
https://github.com/kyorohiro/KyoroHelloAndroid/tree/master/KyoroCommon/src/info/kyorohiro/helloworld/display/widget/editview/differ


https://github.com/kyorohiro/KyoroHelloAndroid/tree/master/TestForKyoroCommon/src/info/kyorohiro/helloworld/display/widget/editview/differ


[次回のネタ]

  このブログに来る人は、特定のキーワード(APIとかフレームワーク名だとか)をGoogleした人がほとんどみたいです。より多くの人の目にとまるように、特定のキーワードが使って何か書く予定です。
  - SurfaceView上で、InputConnactionを使った簡単なサンプル
  - Robotiumを使った簡単なサンプル
  - JavaのC#への変換ついて、特定のツールの使い方
  - ..
  - .


2012年12月23日日曜日

KyoroText で使用されている技術 その5


[課題] 文字コードを自動認識させる。 


KyoroTexでは、テキストデータを表示/編集するためのツールです。 このテキストデータの扱いの難しところとして、「どの言語」なのか、「どのPFで書かれた」ものか、「どのようなツール」で書かれたデータなのかによって、データ構成が異なります。
例えば、「EUCJP」というルールに従うと、「あ」は 0xA4A2 で表せますが、「SJIS」というルールだと、0x82A0 であらわせます。 


テキストデーターを適切に読み込むには、どのようなルールで書かれたテキストデータなのかを、前もって知っている必要があります。 

しかし、テキストデータには、どのルールで書かれたものなのかが記載されていません。
KyoroTextで、どのようにしてこのルールを判定しているのかを説明します。 


[判定方法] 


  結論から書くと、jcharsetというライブラリを使用しています。「使っていますよ!」 だけだと物足りないので、文字コード(ルール)の判定する仕組みについて、さわりだけ説明します。 

文字コードの判定方法として、以下のような方法が考えられます。 
- a. テキストデータが、特定の文字コードのルールに沿ったものか確認する。 
- b. テキストデータに、含まれるバイトデータの出現率から、適当な文字コードを推測する。 
- c. テキストデータの、テキストの並びの出現率から、適当な文字コードを推測する。 
と行ったものです。 

例えば、日本語だと、改行のまえに、「。」があったり、英語表記と比較して、半角のスペースが少なかったりする。 ISO2022系の文字コードだと、文字の切り替えにESCが使用されると行った特徴を上手く利用して判定するのです。 


KyoroTextでは、自前でこれらの判定モジュールを作成することはあきらめました。  

KyoroTextで使用しているのは、Mozillaで使用されているchardatのJava版です。 


[参考] 
jchardatのPSMについて解説できたらなと考えていたのですが、PSM(Parallel State Machine)の部分が上手く理解できなかったので、あきらめました。 

もっとjchardatを知りたい方は、以下のページなどを参照してみてください。 

- http://www-archive.mozilla.org/projects/intl/UniversalCharsetDetection.html 
- http://jchardet.sourceforge.net/ 


[次回]
KyoroTextはでっかいデータをノータイムで表示できる事を実現したアプリです。
なので、KyoroTextで編集するデータはヒープに収まらないデータとなります。

メモリーに収まらないデータの一部を編集したい場合、どうすればよいでしょうか?
次回はKyoroTextで実現した解決方法について紹介します。


2012年12月20日木曜日

KyoroText で使用されている技術 その4


[課題] ひとつの画面に複数のテキストを表示したい。 

androidやiPhoneは、WindowsやMacとは異なり、ディスプレイを一つのアプリが専有してしまいます。そのため、テキストを比較したい時には、交互に表示したりしなくてはなりません。WindowsやMACに慣れた方にとって、スマートフォンに対して不満を持つ点ではないでしょうか。 
この問題を解決するために、画面を分割する機能を追加して、同時に複数のテキストを表示できるようにしました。


同時にディスプレイに表示できるのは、本当に一つのアプリだけなのでしょうか。そんな事はないだろうと考えているあなた、その考えは正しいです。残念ながら、使用したことがないので解説できませんが、「Overlay Window android」で、Googleして見てください。実現方法がわかると思います。 



[画面分割] 
画面を分割する方法として、2つ頭に浮かびました。 
  - eclipse的な方法 
  - emacs的な方法 

KyoroTextでは、emacs的な方法を採用しました。いつも、xyzzyというエディタを使用しているせいで、emacs的な方法に愛着があったのが一番の理由です。 
また、実現方法も直に思いついたので、深く検討せずに実装してしまいました。まだまだ洗練されたものでは有りませんが、簡単に構造を紹介します。 


[構造] 
KyoroTextの画面分割には、二分木を使用しています。文章で説明するのは難しいので、直接データーを構造を記述することにします。この方が直感的に理解できると思います。


1. 起動時は以下のようなリスト構造となっています。
[テキストA] 


2. 画面分割にはすると以下のような感じになります。 
[[テキストA, テキストB]] 

- --- A
 |
  --- B

3. さらに、フォーカスがテキストBにある状態で画面分割した場合は、以下のようになります。
[[テキストA, [テキストB,テキストC]]]
- --- A
 |
  --- --- B
     |
      --- C


とても単純ですね!! 簡単に実現できそうです。
後は、この構造に合わせて、UI操作を作れば良いのです。



[登場したクラス]
 Screen#separateScreen(Screen target)



[たぶん次回のネタ]

前回はRobotiumがオヌヌメですよっと宣伝しました。
RobotiumがSeleniumライクに動作させるためにどのような事をしているのか?
で、KyoroText用のテストフレームワークにどのように取り込もうとしているのか?
について、解説します。

2012年12月19日水曜日

KyoroText で使用されている技術 その3


[課題] 自動テストにどのフレームワークを使用しよう? 

作成したプログラムを検証するのに、UnitTestを書くのはもちろんのことです。しかし、加えて、ユーザー操作を必要とするシナリオも自動化したくなるかも知れません。そんな時はどうすれば良いでしょうか? Unitテストでユーザー操作のシナリオも実行できるのでしょうか? 
ユーザー操作が必要なテストは、テスターを雇ってテストを実施してもらうのはどうでしょうか? 個人で趣味で作っているような, アプリでは無理そうですね。でも、一定の品質があることを確認してからリリースしたい。そう思いませんか 

KyoroTextで採用しようとしている方法を紹介します。 


[選択できるカード] 
  そんな時は、自動人形に実施してもらえばよいのです。 今時の携帯端末は、ユーザー操作もUnitテストでかけるのです。 
  - InstrumentationTestCase 
  - Robotium 
  - NativeDriver 
  - MonkeyRunner 
などあります。 

  今回は、「InstrumentationTestCase」「Robotium」「NativeDriver」について、簡単な解説を行った後で、KyoroTextで採用した方法を紹介します。 


[Instrumentation] 
  Androidでは、ユーザー操作をプログラムで書くためのクラスが提供されています。「Robotium」「NativeDriver」もこのクラスを使用しています。 
例えば、 
  - 上下キーを押す。 
  - 画面をタップする。 
といったことができます。 


[Robotium] 
  Selenimという、ホームページをテストするためにツールを参考にしてつるられたテストツールです。Android sdk で 提供されている AndroidInstrumentationTestCaseを使用してテストシナリオをかきます。 
基本は、Android Sdkで提供されている機能を、簡単にラッピングして使い勝手を良くした。のと、SeleniumライクなApiを実現するために、ひと工夫したApiが提供されています。 

[NativeDriver] 
  Seleniumの正当な派生物でありGoogleが提供しているテストツールです。androidだけでなくiOSなどもテストターゲットにはいっています。Selenimとコンパチな開発環境を提供しており。Ruby javascriptなどのJava以外の言語でテストが書けます。 
NativeDriverは、自前のサーバーをandroid上で動作させています。Rubyやjavascriptで書かれたシナリオから送られてくるテキストデーターを逐一解釈してInstrumentationを通してandroidアプリ操作します。 

[NativeDriver と Robotiumの違い] 
   - Robotiumは、Seleniumっぽい何かだが、NativeDriverはSeleniumそのもの。 
   -  Robotiumは同一プロセス上で動作しているので、直接テスト対象のアプリのクラスにアクセスできるが、NativeDriverはSeleniumでサポートしている範囲の事のみ、アプリのクラスに直接アクセスできない。 
   -  Robotiumのコードはシンプルで量が少ないが、NaiveDrivermはSelenium化のためのコードが、多くを占めていて、コード量が多い。 




[KyoroText選択] 
KyoroTextでは、Robotiumのコードから使用したいエッセンスを取り出して。自前のテストフレームワークに追加していく方法をとっています。 
NativeDriverが、Seleniumの正当な拡張であり、なおかつ、Android OS を提供しているGoogleから出ているテストフレームワークであることを考えると。 ※ WEBアプリやIOSでも使用できる優れもの!!! 
Robotiumの存在が弱くかじる方がほとんどではないでしょうか。RobotiumにGoogleみたいなモンスター企業がバックにないぞ。大丈夫か?と考えるのが正常な人の判断です。 


私がNativeDriverを選択肢なかったのは、「NativeDriverはSeleniumの正当な派生物であるがために、融通がきかない。」という理由からです。また、Robotiumの方がコードがシンプルで量も少なく、簡単に理解できます。 


でも今後の互換性は大丈夫か、「きちんと最新の環境にすぐに対応してくれるのか?」と不安を覚えるかも知れません。「Google様がなんとかしてくれるはずだ!!」という考え方もあるでしょう。 
または、私のように、「最悪自分で何とかできなきゃダメなんだ」と考えるのもありです。 
どちらも、イケてる判断です。 

※よく、他のブログなどでは、非公開APIを使っているRobotiumの互換性は将来的には不安だ!と情報が流れていたりしますが、NativeDriverも、非公開APIを使用していますよ!! 

Google様がサポートし続けるなんて保証はありません。ならば自分が即座に対応できものを使用しようと考えました。 
ならば、シンプルで、融通がきくRobotiumがだんぜん良さそうです。 

たぶん次回のネタ

 KyoroTextは、画面を無限分割する事ができます。とても便利です。
 どのように実現したのか?分割方法としてどんな候補があったのか?
 紹介します。

2012年12月13日木曜日

KyoroText で使用されている技術 その1の次

続き...

[共有メモリから取得]
 Dalvikは、アプリごとに使用しているJavaヒープをカウントしており、一定量以上のヒープを取得できないようになっています。しかし、Nativeヒープにはその制限は適用されていません。
 そこで、Androidで大きめのヒープが必要な場合は、Nativeヒープを取得することが考えられます。
 一つは、native側で mallocしてあげる。一つは、android.os.MemoryFileを使用すると良いです。

[KyoroTextの対処]
 ここまで、説明しておいて何ですが、KyoroTextでは、Nativeヒープを使用する方法は取りませんでした。Javaヒープだけで、済ませていまいます。

その2に続きます。

KyoroText で使用されている技術 その1



 数十回に渡って、KyoroText で使用されている技術について、紹介していきたいと思います。
※ androidとj2seで、自作Editorを作成する方法を紹介します。
    以下ような内容を含んでいます。
      - androidにて、InputConnectionより確定文字、未確定文字、キーイベントを取得する方法
      - j2seにて、未確定文字、確定文字を取得する方法。
  


[はじめに]
  私は今「Kyoro Text」というアプリを作成しています。その際に、「試行錯誤したこと」や、「得たノウハウ」をまとめていきたいと考えています。
  当初、Text Editorという、文字の表示と編集するだけのアプリに、悪戦苦闘するとは、考えていませんでした。
  皆さんも、たかだかEditor程度と思いでしょう。 たかだかEditorと言う認識で正しいのかも知れません。 間違いなのかもしれません。この判断をくだすための材料を提供したいと思います。


[進め方] 
  この文章を読んで頂いている皆様は、多分、androidやJ2SEでEditorを作るのに必要なAPIだとか、その使い方だとかを知りたくてこの文章を読んでいるのではないでしょうか?
残念ながら, あなたのご期待に沿う事は出来ないかも知れません。
  モチロン、apiの使い方にもついて、触れる事は多々あると思います。しかし、apiの使い方をメインに説明しようとは考えてません。
  Editorを作成するにあたり、どのような課題があって、それをどのように克服したのかを説明します。
  残念ながら、優れた対処方法はほとんどありませんが、試行錯誤の結果を物語として楽しんでいただけたらと思います。


[課題一覧]
  - Androidで、PC等で編集したテキストを表示するには、ヒープが足りない。
  - ..
  - ..
  - ..



[課題] Androidで、PC等で編集したテキストを表示するには、ヒープが足りない。

  KyoroTextが対象としていた端末はLowSepcなものが有り。 使用可能なJavaヒープが少ないため、Javaヒープ上にデータをすべて読み込んでから表示する事が困難でした。

  また、Fileから、データを読み込む速度も重要な要素です。 Fileからデータを読み込む速度は高機能を歌っている端末だからといって早いわけではなく。古い型のものの方が早かったりしました。
このため、 最新の端末なのにタカダカ数千キロバイト程度のテキストを読み込むのにカナリ待たされたりする事があるわけです。

  これらの状況をふまえて、ユーザーにストレスを与えないように、即座に画面に表示して上げるようにする必要がありました


[androidのメモリ]

  本当に使えるメモリはそんなに少ないのか?という疑問から解決していきましょう。
 端末には、数メガのヒープを確保してもありあまる程のようりょうがあります。
  これを特別な方法で取得できないのでしょうか?
  結論から言うとデキます。なので、この特殊な方法を使用するという手もあります。

簡単に紹介しましょう。
  - malloc
  - MemoryFile
  - ByteBuffer.alllocateDirect

続く.. 中途半端なところで、ごめんなさい!!


[PS]

来年初頭に、KyoroTextの安定版をだす予定です。
そこで、「KyoroTextを紹介するページをつらないとなぁ~」と考えました。
機能の紹介だけだと、平凡な感じがしました。
そこで、KyoroTextを作成するにあたり悪戦苦闘した事を、記事にすることにしまた。

この記事が第一回目となります。
たぶん何度も書き直します。



Game Boy の VGM から JavaScript への変換後に、 生成AIの補正が有効だった事について

Game Boy の VGM から JavaScript への変換後に、 生成AIの補正が有効だった事について Tetorica FM2612 Playground には GameBoy や Genesis の VGM ファイル から JavaScript へ変換する機能を持って...