Android SDKでファイル選択ダイアログを作る

test125_01.png
Androidはユーザーにファイルを意識させない設計がされているためなのか、標準でファイル選択ダイアログが用意されていません。ちょっと不便すぎるので今回はファイル選択ダイアログを作成します。

まずはJavaで雛形となるプロジェクトを作り、「menu」ボタンからファイル選択画面を開くSelectFile()を呼び出す流れを作る。この状態ではSelectFile()が実装されていないのでビルドできません。
package com.Test125;

import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;

public class Test125Act extends Activity
{
	@Override
	public void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu)
	{
		super.onCreateOptionsMenu(menu);

		int		nId = 0;

		menu.add(0,nId++,Menu.NONE,"Open").setIcon(android.R.drawable.ic_menu_set_as);

		return true;
	}


	@Override
	public boolean onOptionsItemSelected(MenuItem item)
	{
		switch(item.getItemId())
		{
		case 0:
			SelectFile();
			return	true;

		default:
			break;
		}

		return super.onOptionsItemSelected(item);
	}
}

test125_02.png
プロジェクトに「SelectFileDialog.java」ファイルを追加して、ファイル選択ダイアログのメイン処理を実装する。

AlertDialog.Buildeを作り、そこにファイル名のリストメニューを表示。クリックされたアイテムがフォルダならさらに下のフォルダ用のAlertDialog.Builderを作り表示。クリックされたのがファイルなら終了という流れです。
package com.Test125;
 
import java.io.File;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.view.KeyEvent;

public class SelectFileDialog extends Activity
	implements	DialogInterface.OnClickListener
				,DialogInterface.OnKeyListener
{
	private	File		_fileCurrent;	//現在表示しているフォルダ
	private	File[]		_aFileList;		//現在表示しているフォルダのファイル一覧
	private	String[]	_astrFileName;	//現在表示しているフォルダのメニュー用ファイル名
	private	Context		_context;

	private	Dialog		_dlgThis;

	public SelectFileDialog(Context context)
	{
		_context = context;
	}



	@Override
	public void onPause()
	{
		if(_dlgThis != null && _dlgThis.isShowing())
			_dlgThis.dismiss();
		
		super.onPause();
	}


/*	@Override
	public void onResume()
	{
		Log.d("Test125","--onResume--- ");

		if(_dlgThis != null)
			_dlgThis.show();
		
		super.onResume();
	}

	public	String	GetCurrentPath()
	{
		if(_dlgThis == null || _dlgThis.isShowing() == false || _fileCurrent == null)
			return	"";

		return	_fileCurrent.getAbsolutePath();
	}
*/	

	public	boolean	Show(String strInitPath)
	{
		boolean	ret;

		ret = CreateFileList(strInitPath);
		if(ret == false)
			return	false;

		
		AlertDialog.Builder dlgBuilder = new AlertDialog.Builder(_context);
		dlgBuilder.setCancelable(true);
		dlgBuilder.setOnKeyListener(this);
		dlgBuilder.setTitle(_fileCurrent.getPath());
		dlgBuilder.setItems(_astrFileName,this);

		_dlgThis = dlgBuilder.create();
		_dlgThis.show();

		return	true;
	}


	public	void	Close(DialogInterface dialog,File fileSelected)
	{
		((onSelectFileDialogListener)_context).onFileSelected_by_SelectFileDialog(fileSelected);
		dialog.dismiss();
		_dlgThis = null;
	}


	@Override
	public void onClick(DialogInterface dialog, int which)
	{
		File	file = _aFileList[which];

		if(file.isDirectory())
		{
			//フォルダが選択されたので開く
			Show(file.getAbsolutePath());
			dialog.dismiss();
		}
		else
		{
			//選択されたので終了
			Close(dialog,file);
		}
	}


	@Override
	public boolean  onKey(DialogInterface dialog, int keyCode, KeyEvent event)
	{
		if(keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_DOWN)
		{
			File	fileParent;

			fileParent = _fileCurrent.getParentFile();
			if(fileParent != null)
			{
				Show(fileParent.getAbsolutePath());
				dialog.dismiss();
			}
			else
			{
				//ルートだったので終了
				Close(dialog,null);
			}

			return	true;
		}
		return	false;
	}


	private	boolean	CreateFileList(String strPath)
	{
		File[]	aFiles;
		
		_aFileList = null;
		_astrFileName = null;

		_fileCurrent = new File(strPath);
		if(_fileCurrent == null)
			return	false;
		
		aFiles = _fileCurrent.listFiles();
		if(aFiles == null || aFiles.length == 0)
		{
			_aFileList = new File[0];
			_astrFileName = new String[0];
			return	true;
		}
		

		int			i;
		int			nCount;
		String[]	astrName;

		astrName = new String[aFiles.length];

		nCount = 0;
		for(i = 0; i < aFiles.length; i++)
		{
			if(aFiles[i].isDirectory() && aFiles[i].isHidden() == false)
			{
				//ディレクトリの場合
				astrName[i] = aFiles[i].getName() + "/";
				nCount++;
			}
			else if(aFiles[i].isFile() && aFiles[i].isHidden() == false)
			{
				//通常のファイル
				astrName[i] = aFiles[i].getName();
				nCount++;
			}
			else
			{
				aFiles[i] = null;
			}
		}


		_aFileList = new File[nCount];
		_astrFileName = new String[nCount];

		nCount = 0;
		for(i = 0; i < aFiles.length; i++)
		{
			if(aFiles[i] != null)
			{
				_aFileList[nCount] = aFiles[i];
				_astrFileName[nCount] = astrName[i];
				nCount++;
			}
		}

		//ソートするならここでソート
		
		return	true;
	}


	public interface onSelectFileDialogListener
	{
		public void onFileSelected_by_SelectFileDialog(File file);
	}
}

test125_03.png
そして再び戻ってSelectFileDialogを呼び出す処理を実装する。

本当はSelectFileDialogをメンバー変数ではなく、ローカルに宣言して利用できるようにしたかったのですが、、、ファイル選択ダイアログを開いているときに端末の向きを変えてオリエンテーションが変わるとOnPause、OnResumeが呼ばれずにメモリリークが起きるので、苦肉の策としてこのような実装にしました。
package com.Test125;

import java.io.File;

import com.Test125.SelectFileDialog.onSelectFileDialogListener;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;

public class Test125Act extends Activity
		implements onSelectFileDialogListener
{
	@Override
	public void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu)
	{
		super.onCreateOptionsMenu(menu);

		int		nId = 0;

		menu.add(0,nId++,Menu.NONE,"Open").setIcon(android.R.drawable.ic_menu_set_as);

		return true;
	}


	@Override
	public boolean onOptionsItemSelected(MenuItem item)
	{
		switch(item.getItemId())
		{
		case 0:
			SelectFile();
			return	true;

		default:
			break;
		}

		return super.onOptionsItemSelected(item);
	}


	protected	SelectFileDialog	_dlgSelectFile;

	
	private	void	SelectFile()
	{
		//ここで画面回転を固定すべき(画面が固定されていないなら)

		_dlgSelectFile = new SelectFileDialog(this);
		_dlgSelectFile.Show("/sdcard/");
	}

	
	@Override
	public void onFileSelected_by_SelectFileDialog(File file)
	{
		//ここで画面回転の固定を解除すべき(SelectFileDialog利用前に画面が固定されていなかったなら)

		if(file != null)
			Log.d("Test125","selected : " + file.getName());
		else
			Log.d("Test125","not selected");

		_dlgSelectFile = null;
	}

	
	@Override
	public void onPause()
	{
		if(_dlgSelectFile != null)
			_dlgSelectFile.onPause();
		
		super.onPause();
	}
}

test125_04.png
これで実行して、「memu」ボタンを押すとメニューが表示され、、、

test125_05.png
メニューの「Open」をクリックすると、、、

test125_06.png
ファイル選択ダイアログが開きました。フォルダを選択するとその中が表示され、「戻る」ボタンを押すとひとつ上のフォルダに移ります。

そして端末の向きを変えると、、、メニューが終了します。本当は向きを変えてメニューを再表示させるべきですが複雑になるのでやめました。




プロジェクトファイルをダウンロード


カテゴリー「android」 のエントリー