Quello che lo snippet di codice seguente vi permette di fare è di creare un dialogo per la selezione di un file o di una directory.

Vi allego anche una screen in modo da vedere il risultato finale:

Questa è la modalità di selezione di file, che ci permette di navigare fra le varie cartelle. Nella modalità di selezione directory avremmo sotto di questo un tasto con scritto "Select directory".
Questa è la modalità di selezione di file, che ci permette di navigare fra le varie cartelle. Nella modalità di selezione directory avremmo sotto di questo un tasto con scritto “Select directory”.

Lo snippet è veramente facile da implementare, avete bisogno solamente di creare una classe con questo codice:
[fancy_header]FileDialog.java[/fancy_header]

import java.io.File;
import java.io.FilenameFilter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
 

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.os.Environment;
import android.util.Log;
 
public class FileDialog
{
	private static final String PARENT_DIR = "..";
	private final String TAG = getClass().getName();
	private String[] fileList;
	private File currentPath;
 
	public interface FileSelectedListener
	{
		void fileSelected(File file);
	}
 
	public interface DirectorySelectedListener
	{
		void directorySelected(File directory);
	}
 
	private ListenerList fileListenerList = new ListenerList();
	private ListenerList dirListenerList = new ListenerList();
	private final Activity activity;
	private boolean selectDirectoryOption;
	private String fileEndsWith;
 
	/**
	 * @param activity
	 * @param initialPath
	 */
	public FileDialog(Activity activity, File path, String fileEndsWith)
	{
		this.activity = activity;
		if (!path.exists()) path = Environment.getExternalStorageDirectory();
		setFileEndsWith(fileEndsWith);
		loadFileList(path);
	}
 
	/**
	 * @return file dialog
	 */
	public Dialog createFileDialog()
	{
		Dialog dialog = null;
		AlertDialog.Builder builder = new AlertDialog.Builder(activity);
 
		builder.setTitle(currentPath.getPath());
		if (selectDirectoryOption)
		{
			builder.setPositiveButton(activity.getString(R.string.file_dialog_positive_button), new OnClickListener()
			{
				@Override
                public void onClick(DialogInterface dialog, int which)
				{
					fireDirectorySelectedEvent(currentPath);
				}
			});
		}
 
		builder.setItems(fileList, new DialogInterface.OnClickListener()
		{
			@Override
            public void onClick(DialogInterface dialog, int which)
			{
				String fileChosen = fileList[which];
				File chosenFile = getChosenFile(fileChosen);
				if (chosenFile.isDirectory())
				{
					loadFileList(chosenFile);
					dialog.cancel();
					dialog.dismiss();
					showDialog();
				}
				else
					fireFileSelectedEvent(chosenFile);
			}
		});
 
		dialog = builder.show();
		return dialog;
	}
 
 
	public void addFileListener(FileSelectedListener listener)
	{
		fileListenerList.add(listener);
	}
 
	public void removeFileListener(FileSelectedListener listener)
	{
		fileListenerList.remove(listener);
	}
 
	public void setSelectDirectoryOption(boolean selectDirectoryOption)
	{
		this.selectDirectoryOption = selectDirectoryOption;
	}
 
	public void addDirectoryListener(DirectorySelectedListener listener)
	{
		dirListenerList.add(listener);
	}
 
	public void removeDirectoryListener(DirectorySelectedListener listener)
	{
		dirListenerList.remove(listener);
	}
 
	/**
	 * Show file dialog
	 */
	public void showDialog()
	{
		createFileDialog().show();
	}
 
	private void fireFileSelectedEvent(final File file)
	{
		fileListenerList.fireEvent(new FireHandler()
		{
			@Override
            public void fireEvent(FileSelectedListener listener)
			{
				listener.fileSelected(file);
			}
		});
	}
 
	private void fireDirectorySelectedEvent(final File directory)
	{
		dirListenerList.fireEvent(new FireHandler()
		{
			@Override
            public void fireEvent(DirectorySelectedListener listener)
			{
				listener.directorySelected(directory);
			}
		});
	}
 
	private void loadFileList(File path)
	{
		this.currentPath = path;
		List r = new ArrayList();
		if (path.exists())
		{
			if (path.getParentFile() != null) r.add(PARENT_DIR);
			FilenameFilter filter = new FilenameFilter()
			{
				@Override
                public boolean accept(File dir, String filename)
				{
					File sel = new File(dir, filename);
					if (!sel.canRead()) return false;
					if (selectDirectoryOption)
						return sel.isDirectory();
					else
					{
						boolean endsWith = fileEndsWith != null ? filename.toLowerCase(Locale.ENGLISH).endsWith(fileEndsWith) : true;
						return endsWith || sel.isDirectory();
					}
				}
			};
 
			String[] fileList1 = path.list(filter);
			Arrays.sort(fileList1);
			for (String file : fileList1)
			{
				if(!file.toLowerCase(Locale.ENGLISH).startsWith(".")) r.add(file);
			}
		}
		fileList = r.toArray(new String[] {});
	}
 
	private File getChosenFile(String fileChosen)
	{
		if (fileChosen.equals(PARENT_DIR))
			return currentPath.getParentFile();
		else
			return new File(currentPath, fileChosen);
	}
 
	public void setFileEndsWith(String fileEndsWith)
	{
		this.fileEndsWith = fileEndsWith != null ? fileEndsWith.toLowerCase(Locale.ENGLISH) : fileEndsWith;
	}
}
 
class ListenerList
{
	private List listenerList = new ArrayList();
 
	public interface FireHandler
	{
		void fireEvent(L listener);
	}
 
	public void add(L listener)
	{
		listenerList.add(listener);
	}
 
	public void fireEvent(FireHandler fireHandler)
	{
		List copy = new ArrayList(listenerList);
		for (L l : copy)
		{
			fireHandler.fireEvent(l);
		}
	}
 
	public void remove(L listener)
	{
		listenerList.remove(listener);
	}
 
	public List getListenerList()
	{
		return listenerList;
	}
}

android-code

Adesso, per usarlo all’ interno della nostra activity ci basta fare:

	protected void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		File mPath = new File(Environment.getExternalStorageDirectory() + "//DIRECTORY//");
		fileDialog = new FileDialog(this, mPath, ".txt"); //Ci mostrerà solamente i files con estensione .txt
                //E le directories.
		fileDialog.addFileListener(new FileDialog.FileSelectedListener()
		{
			public void fileSelected(File file)
			{
				Log.d(getClass().getName(), "selected file " + file.toString());
			}
		});
                // Se vogliamo selezionare una directory:
		fileDialog.addDirectoryListener(new
		FileDialog.DirectorySelectedListener() 
                {
			public void directorySelected(File directory) 
                	{
		    	Log.d(getClass().getName(), "selected dir " + directory.toString());
			}
		});
		fileDialog.setSelectDirectoryOption(false);
		fileDialog.showDialog();
	}

All’ interno delle callback abbiamo a disposizione rispettivamente il file o la directory selezionate dall’ utente e le potremo utilizzare come meglio crediamo.
Un problema (se posso definirlo così) è il fatto che Android di fatto non aspetta il risultato del dialogo per continuare l’esecuzione del programma, essendo questo eseguito in maniera asincrona.

Questo vuol dire che se avete per esempio una funzione nel menu che apre un dialogo per la selezione di un file, è nella callback che dovrete implementare tutta la logica relativa a quel file e non utilizzarla, per esempio, per impostare un oggetto File.

Infine lo snippet non è stato creato da me ma trovato su StackOverflow e in giro per il web. Ad ogni modo questa è una versione leggermente modificata dall’ originale che aveva un piccolo bug per la selezione di un file basata sull’ estensione.

Un’ ultima cosa: questa piccola utility dovrebbe essere compatibile con qualunque versione di Android (le classi utilizzate sono state aggiunte all’ API 1) quindi potrete utilizzarle (a meno che non diventino deprecate) senza paura per qualsiasi progetto 😉