[課題] 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月27日日曜日
KyoroText で使用されている技術 その11
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月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月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を作成するにあたり悪戦苦闘した事を、記事にすることにしまた。
この記事が第一回目となります。
たぶん何度も書き直します。
登録:
投稿 (Atom)
Game Boy の VGM から JavaScript への変換後に、 生成AIの補正が有効だった事について
Game Boy の VGM から JavaScript への変換後に、 生成AIの補正が有効だった事について Tetorica FM2612 Playground には GameBoy や Genesis の VGM ファイル から JavaScript へ変換する機能を持って...
-
[課題] Low Memory Killer を意図的に発生させたい Androidには、ヒープが涸渇すると使われていないアプリをKillする機能があります。 この記事では、意図的にヒープを枯渇させて、この状態をつくる方法について説明します。 単純にヒープを大...
-
Emscripten と OpenGLを使ってゲームを作ろうと思いたって、 まずは、SDL2の基本的な使い方を試していた。 しかし、今の所は、SDL 1系 の方が、良いと思いました。 SDL2があるのに、SDL1 を選ぶのはなぜか? # 201...
-
Dart の Native Extensions を利用して、 SDL を用いたマルチプラットフォームのゲーム開発環境を作れるか検証してみた。 結論からいくと、 「Mac 上で動作する SDL x Dart の アプリは動作させることが難しいよ」 と言うことです。 Wind...