【Android】VideoViewを使って動画再生アプリを作る②
-- 内部ストレージのファイル検索 --

内部ストレージのファイル検索について実装します。またファイルの検索中はプログレスダイアログを表示して操作できない状態にします。

実装

プログレスダイアログを表示

後述しますが、ファイル検索は並列処理(マルチスレッド)で行い、プログレスダイアログの表示をメインスレッドで行います。こうしておかないと画面の更新ができないためです。

final ProgressDialog progressDialog = new ProgressDialog(MainActivity.this);
progressDialog.setTitle("ファイル検索中");
progressDialog.setMessage("---");
progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
progressDialog.setCancelable(false);
progressDialog.show();

内部ストレージのパスを取得

まずは検索する場所、内部ストレージのパスは以下で取得できます。また、これはマルチスレッドの中で使うのでfinalで宣言しておきます。

final String path = Environment.getExternalStorageDirectory().getPath();

並列処理の実装

並列処理は Thread クラスを使用します。なお、通常はスレッド内からメインスレッドのUI (ここではプログレスダイアログ) へのアクセスはできません。これを解決するために Handler クラスを利用します。メインスレッドで定義した Handler クラスの run メソッドによりメインスレッドのUIの操作が可能になります。ここではファイル検索が終了したらメインスレッドのプログレスダイアログを閉じています。

final Handler handler = new Handler();
new Thread(new Runnable() {
    @Override
    public void run() {
        // ファイル検索開始
        searchFiles(path);
        
        // ファイル検索が終了したらダイアログを閉じる
        handler.post(new Runnable() {
            @Override
            public void run() {
                progressDialog.dismiss();
            }
        }
    }
}).start();

ファイル検索

searchFilesは検索結果をリストビューにセットするメソッドで、searchTargetFilesでファイル検索をしています。

searchTargetFileは内部でディレクトリを再帰的に検索し、検索対象のファイルが見つかったらサイズや更新日などの属性情報をItemクラスに詰めてList形式で返却します。

/**
 * ファイル検索してViewにセット
 * @param path 検索する場所
 */
private void searchFiles(String path) {
    listItems = searchTargetFiles(path);

    // 出力結果をリストビューに表示
    handler.post(new Runnable() {
        @Override
        public void run() {
            setListView();
        }
    });
}

/**
 * 対象ファイル検索
 * @param path 検索する場所
 * @return
 */
private List<Item> searchTargetFiles(final String path){
    // 検索場所をダイアログに表示する
    handler.post(new Runnable() {
        @Override
        public void run() {
            progressDialog.setMessage(path);
        }
    });

    List<Item> listItems = new ArrayList<>();
    final File directory = new File(path);
    if (!directory.canRead()) {
        return new ArrayList<>();
    }

    // 指定したディレクトリに含まれるファイル、ディレクトリの配列
    String[] files = directory.list();
    for (String fileName : files){
        File subFile = new File(directory.getPath() + "/" + fileName);

        if(subFile.isDirectory()){
            Log.d(tag, "dir:" + subFile.getName());
            listItems.addAll(searchTargetFiles(subFile.getPath()));
        } else{
            Log.d(tag, "file:" + subFile.getName());
            int pos = subFile.getName().lastIndexOf(".");
            if (pos != -1) {
                if(!subFile.getName().substring(0, 1).equals(".")
                    && subFile.getName().substring(pos + 1).toLowerCase().equals("mp4")) {

                    Item item = new Item();
                    item.setName(subFile.getName());
                    item.setPath(subFile.getParent());
                    item.setSize(subFile.length());
                    item.setLastModified(new Date(subFile.lastModified()));
                    listItems.add(item);
                    Log.d(tag, subFile.getPath());
                }
            }
        }
    }

    return listItems;
}

動作確認

実行すると画像左のダイアログが表示され、検索が終了すると画像右のように検索結果がリスト表示されます。このリスト表示はsearchFilesのsetListViewでItemクラスの属性をカスタムリストビューで表示していますが、次回はここについて触れていきたいと思います。

コメント

このブログの人気の投稿

docker-compose up で proxyconnect tcp: dial tcp: lookup proxy.example.com: no such host

docker-compose で起動したweb、MySQLに接続できない事象

【PHP】PHP_CodeSnifferを使う(コーディングルールのカスタマイズ)