飴屋

Androidアプリメモ/メモ4

ファイルを選択して読み込みたい

Androidにはファイル選択ダイアログが標準では用意されていないようです。(SDK8でやってます。)WindowsなどのGUIソフトの開発では一般的なこのダイアログですが、そもそもユーザにファイルを選択させるというインターフェイスはGoogleの望むところではないのでしょうか。その気持ちはわからないでもないです。Windowsを使っていても一生エクスプローラを起動させることのない人だっているでしょうし、デスクトップのアイコンが「ファイル」というものを具象化して表していると知らずにクリックしている人もたくさんいると思います。英数字の羅列に拡張子のついた意味不明なものが並んでいても困るばかりでしょう。

今回は体重の計測データをインポートするためにCSVファイルを選択してもらおうと思っているのですが、このような方法は過去の手法として消えていくのでしょうか?データはすべてクラウドサーバーの中に保管される・・・なんて時代が近づいています。でも、もうちょっとこのレガシー技術を使わせていただきます。多分、この古い手法に慣れた人も少なくはないと思います。

File[] files = this.getFilesDir().listFiles();
final ArrayList<String> items = new ArrayList<String>();
Pattern pat = Pattern.compile(".+\\.csv$",Pattern.CASE_INSENSITIVE);
for (File file : files) {
if (!file.isDirectory()) {
if (pat.matcher(file.getName()).matches()) items.add(file.getName());
}
}
if (items.size()>0) {
new AlertDialog.Builder(this).setTitle(R.string.titleSelectCSVFile)
.setItems((String[])items.toArray(new String[0]), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
FileInputStream fis = null;
try {
fis = UtilWeight.this.openFileInput(items.get(which));
byte[] reader = new byte[fis.available()];
while (fis.read(reader) != -1) {}
// インポート処理
} catch (IOException e) {

} finally {
if (fis != null) {
try {
fis.close();
Toast.makeText(UtilWeight.this,R.string.msgCSVImported,Toast.LENGTH_LONG).show();
} catch (IOException e) {

}
}
}
}
}).setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
}).setCancelable(true).create().show();
} else {
Toast.makeText(this,R.string.msgCSVFileNotFound,Toast.LENGTH_LONG).show();
}

まず、ファイル選択ダイアログを自分で作るところから始めます。アプリのデータが保存されている場所は「data/data/(アプリのID)/files」ディレクトリだったと思いますが、その中のファイルを全部取得します。Context.getFilesDirメソッドが上記のディレクトリを示してくれるようですので、File.listFilesメソッドで中身を全部調べます。

続いてファイル名の配列(items)を作ります。ディレクトリを除外することと、拡張子がcsvでないファイルを除外して、文字列の配列を作ります。

続いて、ダイアログを準備しようと思います。以前にも使ったことのあるAlertDialog.Builderがまた登場しました。AlertDialogっていろんなダイアログに使えるものなんですね。名前から想像される以上の威力を秘めていそうです。
setTitleしてファイル名の配列をsetItemsでセットしてあげるだけで選択ダイアログになるのでとても簡単ですね。ちなみにsetMessageとsetItemsを併用しようとしたらうまくいきませんでした。これらは同時に指定することはできないようです。その他にキャンセルボタンも前と同じようにくっつけておきました。

ファイル名の一覧上でファイルがタップされたときのハンドラにDialogInterface.OnClickListenerを使います。前にダイアログのOKボタンやキャンセルボタンのタップの制御にも使ったことがありましたが、今回はonClickメソッドに渡ってくる第二引数が大事になります。ファイル名の配列の何番目が押されたかをそこで確認して、読み込み対象のファイルを確定します。

前にファイルの書き込み処理を行ったときのように、ファイルの読み込み処理用にもopenFileInputという関数が用意されていましたので、これを使ってFileInputStreamのインスタンスを用意すれば、あとは自由にファイルを読み込めます。

今回簡単に用意したファイル選択ダイアログは、汎用的なものを作っておけば便利なのだろうと思います。親や子のディレクトリに移動できるだけでも随分と用途が広がるはずです。ただ、やっぱりファイル選択っていう作法はなじみのない人には混乱のもとになるので、もっとインポータやエクスポータを洗練する方法を考えた方がいいですね。

メモ一覧