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 



0 件のコメント:

コメントを投稿