Android file chooser dialog

Создание удобного OpenFileDialog для Android

Наверное, как и многие разработчики под Android, столкнулся на днях с необходимостью реализовать в своем приложении выбор файла пользователем. Так как изначально в Android такого функционала нет, обратился к великому и ужасному. Это показалось мне странным, но из вороха вопросов на stackoverflow и небольшого числа отечественных форумов можно выделить всего три основных источника:

  1. Android File Dialog – почти все ссылки из stackoverflow ведут сюда. В принципе, неплохое решение, но реализовано через отдельную activity, а хотелось чего-то в духе OpenFileDialog’а из .Net.
  2. В данной статье речь идет вообще об отдельном файл-менеджере, и почерпнуть какие-то идеи из неё не удалось.
  3. Идея же отсюда очень понравилась, однако, как мне показалось реализовать все это можно несколько красивее.

В результате, начав реализовывать своё решение, я столкнулся с некоторыми трудностями решать которые показалось очень интересно. А посему, решил описать в данной статье не просто готовое решение, а все шаги, которые к нему привели. Желающие пройти их вместе –
Итак, приступим! В любой привычной среде (я использую IntelliJ IDEA) создадим новое приложение. На главной activity расположим одну единственную кнопку и напишем к ней, пока пустой, обработчик нажатия:

Создадим новый класс с конструктором:

а в обработчике кнопки вызовем диалог:

Кнопки показались, теперь надо бы и сами файлы найти. Начнем поиск с корня sdcard, для чего определим поле:

и реализуем следующий метод:

(так как главное требование к классу – работать сразу у любого разработчика, без подключения дополнительных библиотек, — то никаких google-collections использовать не будем, и с массивами приходится работать по старинке), а в конструкторе к вызову setNegativeButton добавим .setItems(getFiles(currentPath), null).

Что же, неплохо, однако файлы не отсортированы. Реализуем для этого дела Adapter как внутренний класс, заменим setItems на setAdapter и немного перепишем getFiles:

Еще лучше, но нам надо по клику на папке идти внутрь. Можно достучаться до встроенного listview, но я просто подменил его собственным (это потом пригодится). Плюс, изменения adapter’а внутри обработчика listview вызывало exception, и список файлов пришлось вынести в отдельное поле:

Отлично, вот только нажав на папку Android мы получаем список всего из одного каталога data, и наше окно тут же уменьшается в размере.

Возможно это нормально, но мне это не понравилось, и я стал искать возможности размер сохранить. Единственный найденный мною вариант – это установка setMinimumHeight. Установка этого свойства для listview вызвала дополнительные проблемы, но они решились оберткой его в LinearLayout:

Результат, все равно получился немного не таким, каким хотелось бы: при старте диалог развернут на весь экран, а после перехода в каталог Android – уменьшается до 750px. Да еще и экраны разных устройств имеют разную высоту. Решим сразу обе этих проблемы, установив setMinimumHeight в максимально возможную для текущего экрана:

Не нужно пугаться того, что мы устанавливаем в setMinimumHeight полный размер экрана, сама система уменьшит значение до максимально допустимого.
Теперь появляется проблема понимания пользователя, в каком каталоге он сейчас находится, и возврата вверх. Давайте разберемся с первой. Вроде все легко — установить значение title в currentPath и менять его при изменении последнего. Добавим в конструктор и в метод RebuildFiles вызов setTitle(currentPath).

А нет – заголовок не изменился. Почему не срабатывает setTitle после показа диалога, документация молчит. Однако мы может это исправить, создав свой заголовок и подменив им стандартный:

И снова не все ладно: если пройти достаточно далеко, то строка в заголовок влезать не будет

Решение с установкой setMaximumWidth не верно, так как пользователь будет видеть только начало длинного пути. Не знаю, насколько верно мое решение, но я сделал так:

Решим теперь проблему с возвратом. Это достаточно легко, учитывая, что у нас есть LinearLayout. Добавим в него еще один TextView и немного отрефракторим код:

Возможность возвращаться на шаг вверх, может привести пользователя в каталоги, к которым ему доступ запрещен, поэтому изменим функцию RebuildFiles:

(cообщение пока не очень информативное, но вскоре мы добавим разработчику возможность исправить это).
Ни один OpenFileDialog не обходится без фильтра. Добавим и его:

Обратите внимание — фильтр принимает регулярное выражение. Казалось бы – все хорошо, но первая выборка файлов сработает в конструкторе, до присвоения фильтра. Перенесем её в переопределенный метод show:

Осталось совсем чуть-чуть: вернуть выбранный файл. Опять же, я так и не понял зачем нужно устанавливать CHOICE_MODE_SINGLE, а потом все равно писать лишний код для подсветки выбранного элемента, когда он (код) и так будет работать без CHOICE_MODE_SINGLE, а потому обойдемся без него:

Источник

Android file chooser dialog

android-file-library is a lightweight file/folder chooser.

1. with AndroidX

MediaStore for Android Q (still in beta)

A demo-app can be installed from Play Store.

A Xamarin nuget package by @Guiorgy can be found at

  • bugs fixed
  • minor fixes for themes
  • #60, #61, #62 fixed
  • revamped Dpad controls
  • added cancelOnTouchOutside and enableDpad (true by default)
  • mainly by Guiorgy.

rewrite demo app

#48: add displayPath(boolean) , thank you @Guiorgy, and your android-smbfile-chooser.

new style demo app by @Guiorgy.

NOTE: displayPath is true by default now.

since v1.1.16, bumped targer sdk to 1.8 (please include the following into your build.gradle)

no WRITE_EXTERNAL_STORAGE requests if not enableOptions(true) ;

after requested permissions, try showing dialog again instead of return directly;

#42: onBackPressedListener not fired. Now, use withCancelListener to handle back key. see also below

#45: add titleFollowsDir(boolean) to allow title following the change of current directory.

create new folder on the fly, and the optional multiple select mode for developer, thx @Guiorgy.

Up ( .. ) on the primary storage root will be replaced with .. SDCard , it allows to jump to external storage such as a SDCard and going back available too.

Читайте также:  Best android mods apk

DPad supports, arrow keys supports (#30)

More images (beyond v1.1.16) have been found at Gallery

android-file-chooser was released at jcenter, declare deps with:

for the newest version(s), looking up the badges above.

taste the fresh

there is a way to taste the master branch with jitpack.io:

  1. add the jitpack repository url to your root build.gradle:

Tips for using JitPack.io

To disable gradle local cache in your project, add stretegy into your top build.grable :

Sometimes it’s right, sometimes . no more warrants.

  1. I am hands down AlertDialog .
  2. Any codes about ChooserDialog , such as the following demo codes, should be only put into UI thread.

FileChooser android library give a simple file/folder chooser in single call (Fluent):

Choose a Folder

Date Format String

Since 1.1.3, new builder options withDateFormat(String) added.

Modify Icon or View Layout of AlertDialog :

Since 1.1.6, 2 new options are available:

1.1.7 or Higher, try withNegativeButton() and/or withNegativeButtonListener()

BackPressedListener will be called every time back key is pressed, and current directory is not the root of Primary/SdCard storage. LastBackPressedListener will be called if back key is pressed, and current directory is the root of Primary/SdCard storage.

OnCancelListener will be called when touching outside the dialog ( cancelOnTouchOutside must be set true), and when pressing back key. If BackPressedListener is overridden, it wont be called if dialog.dismiss is used instead of dialog.cancel . OnCancelListener will NOT be called when pressing the negative button. use withNegativeButtonListener for that.

And, old style is still available. No need to modify your existing codes.

1.1.8+. Now you can customize each row.

since 1.1.17, DirAdatper.GetViewListener#getView allows you do the same thing and more, and withRowLayoutView will be deprecated. See also: withAdapterSetter(setter)

1.1.9+. withFileIcons(resolveMime, fileIcon, folderIcon) and withFileIconsRes(resolveMime, fileIconResId, folderIconResId) allow user-defined file/folder icon.

resolveMime : true means that DirAdapter will try get icon from the associated app with the file’s mime type.

1.1.9+. a AdapterSetter can be use to customize the DirAdapter .

More information in source code of DirAdapter .

since 1.1.17, DirAdapter.overrideGetView() supports GetViewListener interface.

You can disallow someone enter some special directories.

With withStartFile() , you can limit the root folder.

a tri-dot menu icon will be shown at bottom left corner. this icon button allows end user to create new folder on the fly or delete one.

withOptionResources(@StringRes int createDirRes, @StringRes int deleteRes, @StringRes int newFolderCancelRes, @StringRes int newFolderOkRes)

withOptionStringResources(@Nullable String createDir, @Nullable String delete, @Nullable String newFolderCancel, @Nullable String newFolderOk)

withOptionIcons(@DrawableRes int optionsIconRes, @DrawableRes int createDirIconRes, @DrawableRes int deleteRes)

see the sample codes in demo app.

NOTE:

  1. extra WRITE_EXTERNAL_STORAGE permission should be declared in your AndroidManifest.xml .
  2. we’ll ask the extra runtime permission to WRITE_EXTERNAL_STORAGE on Android M and higher too.

as named as working.

psuedo .. SDCard Storage and .. Primary Storage

since v1.11, external storage will be detected automatically. That means user can switch between internal and external storage by clicking on psuedo folder names.

since the latest patch of v1.14, it allows the chooser dialog title updated by changing directory.

since the latest patch of v1.15, it allows a path string displayed below the title area.

since v1.16, its default value is true.

As a useful complement, customizePathView(callback) allows tuning the path TextView. For example:

since 1.1.17, this can also be done through a custom theme:

you can customize the text of buttons:

For Library Developers

Just fork and build me currently.

Contributions and translations are welcome.

feel free to make a new issue.

many peoples report or contribute to improve me, but only a few of them be put here — it’s hard to list all.

This project exists thanks to all the people who contribute. [Contribute].

Become a financial contributor and help us sustain our community. [Contribute]

Support this project with your organization. Your logo will show up here with a link to your website. [Contribute]

Источник

Simple Android File Chooser

By Roger Keays, 3 June 2015

Surprisingly, the Android API doesn’t include a file chooser. I’m not sure why that is, I guess the developers don’t want to make the assumption that the device has a user filesystem available. Anyway, it’s not my job to speculate on what the Android developers talk about over lunch. I just need a file chooser.

It seems like there are a few options out there but I wanted something uber simple and ultra light. It’s just for users to select an import file.

My solution is a single Java class utilising regular android Dialog and ListViews. It just wires up the event handlers to read from the disk and refresh the list. You provide a FileSelectedListener implementation to handle the file selection event. Menial stuff that you don’t want to bother implementing yourself. It can be used like this:

Here is the FileChooser class which you can cut and paste into your project. Public domain code so do what you want with it.

About Roger Keays

Roger Keays is an artist, an engineer, and a student of life. He has no fixed address and has left footprints on 40-something different countries around the world. Roger is addicted to surfing. His other interests are music, psychology, languages, the proper use of semicolons, and finding good food.

You May Also Like

Leave a Comment

When you understand the following trick, you may ignore everything else:

Like my page http://www.facebook.com/atramegadynamics/

Hello friends. I updated the file to cater for more feature. \

[code]
package com.atramega.schbell;
import android.Manifest;
import android.app.Dialog;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.os.Environment;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager.LayoutParams;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TableLayout;
import android.widget.TextView;
import android.widget.Toast;

import java.io.File;
import java.io.FileFilter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class FileChooser <
private static final String PARENT_DIR = «..»;

private Context the_context;
private ListView listView;
private Dialog dialog;
private File currentPath;
private String title = «Choose File»;
private boolean dirsOnly = false;
private boolean canShow = true;
private boolean excludeDotPrefixDirs = false;
private boolean excludeDotPrefixFiles = false;

private String extension = null;
private FileChosenListener fileChosenListener;
public interface FileChosenListener <
void onFileChosen(File file);
>

public FileChooser setFileChosenListener(FileChosenListener fileChosenListener) <
this.fileChosenListener = fileChosenListener;
return this;
>

public FileChooser(final Context context) <
this.the_context = context;
dialog = new Dialog( context );
listView = new ListView(context);
dialog.setContentView(listView );
dialog.getWindow().setLayout(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);
if( (ContextCompat.checkSelfPermission(the_context, Manifest.permission.READ_EXTERNAL_STORAGE)!= PackageManager.PERMISSION_GRANTED)
|| (ContextCompat.checkSelfPermission(the_context, Manifest.permission.WRITE_EXTERNAL_STORAGE)!= PackageManager.PERMISSION_GRANTED) ) <
String msg = «First setup Storage permissions in Settings — Apps — «+the_context.getString(R.string.app_name)+» — permissions»;
Toast.makeText(the_context, msg, Toast.LENGTH_LONG);
Toast.makeText(the_context, msg, Toast.LENGTH_LONG);
Toast.makeText(the_context, msg, Toast.LENGTH_LONG);
canShow = false;
>
>

public void setExtension(String extension) <
this.extension = (extension == null) ? null :
extension.toLowerCase();
>
public void setDirsOnly(boolean val) <
this.dirsOnly = val;
>
public void excludeDotPrefixDirs(boolean val) <
this.excludeDotPrefixDirs = val;
>

public void excludeDotPrefixFiles(boolean val) <
this.excludeDotPrefixFiles = val;
>

public void setTitle(String title) <
this.title = title;
>
public void showDialog() <
if(canShow) <
refresh(Environment.getExternalStoragePublicDirectory(«»));
dialog.show();
>
>

private File[] getDirsUnder(File path) <
File[] dirs = path.listFiles(new FileFilter() <
@Override public boolean accept(File file) <
return (file.isDirectory() );//&& file.canRead());
>
>);
return dirs;
>
private File[] getFilesUnder(File path) <
File[] files = path.listFiles(new FileFilter() <
@Override public boolean accept(File file) <
if (!file.isDirectory()) <
//if (!file.canRead()) else
if (extension == null) <
return true;
> else <
return file.getName().toLowerCase().endsWith(extension);
>
> else <
return false;
>
>
>);
return files;
>

/**
* Sort, filter and display the files for the given path.
*/
private void refresh(File path) <
this.currentPath = path;
if (path.exists()) <
File[] dirs = getDirsUnder(path);
File[] files = getFilesUnder(path);
Arrays.sort(dirs);
Arrays.sort(files);
ArrayList fileList = new ArrayList<>();
fileList.add(null); //item 0 for the heading
if(path.getParentFile() != null && path.getParentFile().canRead()) < //this parrent be used used as item 1
fileList.add( path.getParentFile() );
> else <
fileList.add(null); //item 1 does no
>
for (File dir : dirs) <
if( !(excludeDotPrefixDirs && dir.getName().startsWith(«.»)) )< fileList.add(dir); >
>
if(!dirsOnly) <
for (File file : files ) <
if( !(excludeDotPrefixFiles && file.getName().startsWith(«.»)) )< fileList.add(file); >
>
>
listView.setBackgroundColor(the_context.getColor(R.color.atramegaLightGray));
listView.setAdapter(new FileArrayAdapter(the_context, 0, fileList));
>
>
/**
* Convert a relative filename into an actual File object.
*/
private File getChosenFile(String fileChosen) <
if (fileChosen.equals(PARENT_DIR)) <
return currentPath.getParentFile();
> else <
return new File(currentPath, fileChosen);
>
>
//custom ArrayAdapter
public class FileArrayAdapter extends ArrayAdapter <
public Context context;
public List myFileList;
public FileArrayAdapter(Context contex, int resourc, ArrayList myFileLis) <
super(contex, resourc, myFileLis);
this.context = contex;
this.myFileList = myFileLis;
>

//called when rendering the list
public View getView(final int position, final View convertView, ViewGroup parent) <
LinearLayout linearLayout = new LinearLayout(the_context);
linearLayout.setOrientation( LinearLayout.HORIZONTAL );
linearLayout.setPadding(10, 10, 5, 5);
linearLayout.setDividerPadding(5);
////////////////////////
TextView name_textView = new TextView(the_context);
name_textView.setTextColor( the_context.getColor(R.color.atramegaBlack) );
name_textView.setTextAlignment(View.TEXT_ALIGNMENT_VIEW_START);
name_textView.setHeight(40);
name_textView.setTextSize(18);
///////////////////////////
ImageView dir_imageButton = new ImageView(the_context);
dir_imageButton.setImageDrawable( the_context.getDrawable(android.R.drawable.sym_contact_card) );
dir_imageButton.setVisibility( View.INVISIBLE );
////////////////////////////////
ImageView file_imageButton = new ImageView(the_context);
file_imageButton.setImageDrawable( the_context.getDrawable(android.R.drawable.stat_notify_chat) );
file_imageButton.setPadding(10, 0, 0, 0);
file_imageButton.setVisibility( View.GONE );
////////////////////////////////
linearLayout.addView(dir_imageButton);
linearLayout.addView(file_imageButton);
linearLayout.addView(name_textView);
//////////////////////////////
if(position==0) < //heading
name_textView.setText(title);
name_textView.setTextAlignment( View.TEXT_ALIGNMENT_CENTER );
name_textView.setTextColor(the_context.getColor(R.color.atramegaWhite));
linearLayout.setBackgroundColor(the_context.getColor(R.color.atramegaBlue));
return linearLayout;
> else < //directories and files
if( null != myFileList.get(position)) <
final File fileItem = myFileList.get(position);
name_textView.setText( » «+fileItem.getName() );
if (fileItem.isDirectory()) <
if (position == 1) < //parent directory
name_textView.setTextColor(the_context.getColor(R.color.atramegaBlue) );
linearLayout.setBackgroundColor(the_context.getColor(R.color.atramegaLightBlue));
> else < //other directories
dir_imageButton.setVisibility( View.VISIBLE );
file_imageButton.setVisibility( View.GONE );
>
> else < //files
dir_imageButton.setVisibility( View.GONE );
file_imageButton.setVisibility( View.VISIBLE );
>

if(!fileItem.canRead()) <
name_textView.setTextColor( the_context.getColor(R.color.atramegaGray));
linearLayout.setEnabled(false);
>
linearLayout.setOnClickListener(new View.OnClickListener() <
@Override
public void onClick(View v) <
if (fileItem.isDirectory()) <
refresh(fileItem);
> else <
if (fileChosenListener != null) <
fileChosenListener.onFileChosen(fileItem);
>
dialog.dismiss();
>
>
>);
if (dirsOnly && fileItem.isDirectory()) <
linearLayout.setOnLongClickListener(new View.OnLongClickListener() <
@Override
public boolean onLongClick(View view) <
if (fileChosenListener != null) <
fileChosenListener.onFileChosen(fileItem);
>
dialog.dismiss();
return false;
>
>);
>
> else <
linearLayout.removeAllViews();
File[] dirs = context.getExternalFilesDirs(null);
String[] names = <"Internal Storage", "SD Card", "External Storage 2">; int i = 0;
for( File dir: dirs) <
while(null != dir.getParentFile() && dir.getParentFile().canRead()) <
dir = dir.getParentFile();
>
final File the_dir = dir;
Button button = new Button(the_context);
try <
button.setText( names[i++] );
>catch (IndexOutOfBoundsException iobe)<>finally <>
button.setOnClickListener(new View.OnClickListener() <
@Override
public void onClick(View view) <
refresh(the_dir);
>
>);
linearLayout.addView(button);
>
return linearLayout;
>
return linearLayout;
>
>

FileChooser fc = new FileChooser( the_context );
fc.setTitle(«Choose a File»);
fc.excludeDotPrefixDirs(true);
fc.excludeDotPrefixFiles(true);
fc.setFileChosenListener(new FileChooser.FileChosenListener() <
@Override
public void onFileChosen(final File chosenFile) <
fillFromString( Globals.readFile(chosenFile) );
>
>);
fc.showDialog();

Hello. Thanks a lot to every one. After going through the main post and one advice, i have come up with the following for those who want to pass context instead of activity. I found this important since I was using a fragment

package _YOUR PACKAGE_;
import android.app.Activity;
import android.app.Dialog;
import android.app.TimePickerDialog;
import android.content.Context;
import android.graphics.Color;
import android.os.Environment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager.LayoutParams;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.ListView;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.TimePicker;

import java.io.File;
import java.io.FileFilter;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.TimeZone;

public class FileChooser <
private static final String PARENT_DIR = «..»;

private Context the_context;
private ListView list;
private Dialog dialog;
private File currentPath;

// filter on file extension
private String extension = null;
public void setExtension(String extension) <
this.extension = (extension == null) ? null :
extension.toLowerCase();
>

// file selection event handling
public interface FileSelectedListener <
void fileSelected(File file);
>
public FileChooser setFileListener(FileSelectedListener fileListener) <
this.fileListener = fileListener;
return this;
>
private FileSelectedListener fileListener;
public FileChooser(Context context) <
this.the_context = context;
dialog = new Dialog( context );
list = new ListView(context);
list.setOnItemClickListener(new AdapterView.OnItemClickListener() <
@Override public void onItemClick(AdapterView parent, View view, int position, long id) <
String fileChosen = (String) list.getItemAtPosition(position);
File chosenFile = getChosenFile(fileChosen);

if (chosenFile.isDirectory()) <
refresh(chosenFile);
> else <
if (fileListener != null) <
fileListener.fileSelected(chosenFile);
>
dialog.dismiss();
>
>
>);
dialog.setContentView(list);
dialog.getWindow().setLayout(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);
refresh( Environment.getRootDirectory() );//getExternalStorageDirectory( ) );
>

public void showDialog() <
dialog.show();
>

private File[] getDirsUnder(File path) <
File[] dirs = path.listFiles(new FileFilter() <
@Override public boolean accept(File file) <
return (file.isDirectory() && file.canRead());
>
>);
return dirs;
>
private File[] getFilesUnder(File path) <
File[] files = path.listFiles(new FileFilter() <
@Override public boolean accept(File file) <
if (!file.isDirectory()) <
if (!file.canRead()) <
return false;
> else if (extension == null) <
return true;
> else <
return file.getName().toLowerCase().endsWith(extension);
>
> else <
return false;
>
>
>);
return files;
>
/**
* Sort, filter and display the files for the given path.
*/
private void refresh(File path) <
this.currentPath = path;
if (path.exists()) <
File[] dirs = getDirsUnder(path);
File[] files = getFilesUnder(path);
Arrays.sort(dirs);
Arrays.sort(files);

// convert to an array
int i = 0;
String[] fileList;
if (path.getParentFile() == null || !path.getParentFile().canRead()) <
fileList = new String[dirs.length + files.length];
> else <
fileList = new String[dirs.length + files.length + 1];
fileList[i++] = PARENT_DIR;
>

for (File dir : dirs) < fileList[i++] = dir.getName(); >
for (File file : files )

// refresh the user interface
dialog.setTitle(currentPath.getPath());
list.setAdapter( new ArrayAdapter(the_context,
android.R.layout.simple_list_item_1, fileList) <
@Override public View getView(int pos, View view, ViewGroup parent) <
view = super.getView(pos, view, parent);
((TextView) view).setSingleLine(true);
return view;
>
>);
>
>
/**
* Convert a relative filename into an actual File object.
*/
private File getChosenFile(String fileChosen) <
if (fileChosen.equals(PARENT_DIR)) <
return currentPath.getParentFile();
> else <
return new File(currentPath, fileChosen);
>
>

You can contact me on Facebook www.facebook.com/atramegadynamics/

First of all, thans very much for your sharing, it is very helpful.

But, in the very first dialog display, first list item with «..» should not appear, because we can not ask parent of root to list files.

If one tap on this «..» item, device will crash.

So I suggest make following fix in refresh():

if (path.getParentFile() == null) <
fileList = new String[dirs.length + files.length];
> else <
fileList = new String[dirs.length + files.length + 1];
fileList[i++] = PARENT_DIR;
>

if (path.getParentFile() == null || !path.getParentFile().canRead()) <
fileList = new String[dirs.length + files.length];
> else <
fileList = new String[dirs.length + files.length + 1];
fileList[i++] = PARENT_DIR;
>

1st time that i just copy/paste sth and its work ! thanks a lot

I made a few tweaks, because the original method was a bit unreadable and called path.listFiles() twice for no apparent reason:

Oh and by the way, you should address the new permission issues with Android 6.0

have you got this in manifest?

Many thanks for this topic!

Ai uitat o acolada pisa-m-as pe mortii matii

Just had to say:

Thank you for sharing, helped me a lot.

Well, just to say thanks.

Simple and efficient

Hey @Robot Maxwell. Thanks for the patch. It looks like path.listFiles() is returning null in your case. The javadoc says «The array will be empty if the directory is empty. Returns null if this abstract pathname does not denote a directory, or if an I/O error occurs.»

So I think this code should work if the directory is empty, but will probably crash if Environment.getExternalStorageDirectory() does not return a valid directory. What happens if you change:

Roger you have a nasty error in your code, when the sdcard is «empty» it will crash. I had to bolster it up with a bit of checking thus:

Really Useful code for many Android Developers.

Great step by step solution, thanks for the help!

Great! Thanks alot you save my time!

Marthono, it gave the same error to me. Just substitute this line:

and it worked for me.

06-15 03:43:31.038 24606-24606/on4shop.androidapp E/AndroidRuntime: FATAL EXCEPTION: main
Process: on4shop.androidapp, PID: 24606
java.lang.IllegalStateException: Could not execute method for android:onClick
at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:293)
at android.view.View.performClick(View.java:4438)
at android.view.View$PerformClick.run(View.java:18422)
at android.os.Handler.handleCallback(Handler.java:733)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5001)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.reflect.InvocationTargetException
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:288)
at android.view.View.performClick(View.java:4438)
at android.view.View$PerformClick.run(View.java:18422)
at android.os.Handler.handleCallback(Handler.java:733)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5001)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.NullPointerException
at on4shop.androidapp.DialogClassCollection.clsSaveFileDialog.refresh(clsSaveFileDialog.java:99)
at on4shop.androidapp.DialogClassCollection.clsSaveFileDialog. (clsSaveFileDialog.java:62)
at on4shop.androidapp.frm_file_act.WriteExternalFile(frm_file_act.java:67)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:288)
at android.view.View.performClick(View.java:4438)
at android.view.View$PerformClick.run(View.java:18422)
at android.os.Handler.handleCallback(Handler.java:733)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5001)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)
at dalvik.system.NativeStart.main(Native Method)

Hey Brian, the stack trace might tell you if this.getParent() is the cause of the problem. Couldn’t you just use ‘this’?

I’m trying to use your file picker to pick a file for the XML parser to parse. I have the FileChooser Class and everything compiling, but my APP blows up when I include this code to present the file chooser. I only pick an XML file to parse on the initial startup of the app. It’s likely the «this.getParent()» to get the activity, but I cannot be sure.

public class XMLPullParserActivity extends Activity <
.

@Override
protected void onCreate(Bundle savedInstanceState) <
super.onCreate(savedInstanceState);

.
if (savedInstanceState != null) <
.
> else <

new FileChooser(this.getParent()).setFileListener(new FileChooser.FileSelectedListener() <
@Override public void fileSelected(final File file) <
// do something with the file
Application application=(Application)CBA_Application.getContext();
CBA_Application app = (CBA_Application)application;
Context context=getApplicationContext();
CharSequence mytext;
Integer myduration;
Toast mytoast;
mytext = «Root Directory for selected File » + file.getAbsolutePath();
myduration = Toast.LENGTH_LONG;
mytoast = Toast.makeText(context,mytext,myduration);
mytoast.show();
>>).showDialog();
.

Thanks .. that made my life easy .. Made a few minor tweaks.. but I had some issues with the extensions. So, since I know what the extension is ahead of time, I just added it to the construction methods. I could add multiple extension filters on. your skeleton was what I really needed.. So, I use it like

Hello, i already have a button in main activity to access this class, how i implement my button actionListener with this class?

Thank you. This is absolutely brilliant and saved me a lot of time.

I noticed one issue with the processing order. When using «setExtension», the «refresh» method is not called. This results in the first screen displaying all file formats not just directories and the designated extension.

Thank you once again

I don’t understand with this part:

can you give me an example what i can do with that line?

How do i implement the class within a button click of another class

Thank you so much for this code. I am so thankful that you allow this code to be used on our projects.

Источник

Читайте также:  Усиление микрофона android 10
Оцените статью