Как воссоздать ListView в DialogFragment

Я пишу DialogFragment для просмотра файловой системы, которая сейчас работает очень хорошо. У меня только одна Проблема.

Файлы отображаются в ListView, и когда пользователь выбирает файл, это событие отправляется в действие, которое вызвало фрагмент через интерфейс OnFileSelectedListener-Interface. Это нормально для файлов, но кажется неправильным отправлять имена каталогов в действие, а затем уничтожать и воссоздавать фрагмент, когда все, что должно произойти, это то, что фрагмент должен показать новый каталог. Это также заставляет весь Фрагмент исчезать, а затем снова появляться, что не очень приятно и гладко.

Кроме того, каждое действие, использующее фрагмент, должно использовать логику для воссоздания фрагмента, которая далека от «не повторяйся».

Итак, вкратце, есть ли способ изменить представление списка внутри фрагмента? Вызов AlertDialog.Builder более одного раза, к сожалению, не работает.

Вот мой диалоговый фрагмент. Я надеюсь, что это нормально, чтобы опубликовать все это:

package de.fusionsystems.firmenlaufmonitor;

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

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;

public class FileChooserFragment extends DialogFragment {
    private OnFileSelectedListener mCallback;

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        return createDialog();
    }

    private AlertDialog createDialog(){
        // Create the AlertDialog object and return it
        SharedPreferences options = PreferenceManager.getDefaultSharedPreferences(getActivity());
        ArrayList<File> files = getFilesInDir(options.getString("BaseDir", ""));
        ArrayList<ListEntry> fileEntries = new ArrayList<ListEntry>();

        if (!isBaseDir(options.getString("BaseDir", ""))){
            fileEntries.add(new ListEntry("..", getResources().getDrawable( R.drawable.ic_folder)));
        }

        for (File file : files){            
            if (file.isDirectory()){
                fileEntries.add(new ListEntry(file.getName(),getResources().getDrawable(R.drawable.ic_folder)));
            }else{
                if (file.getName().endsWith(".kml")){
                    fileEntries.add(new ListEntry(file.getName(),getResources().getDrawable( R.drawable.ic_file)));
                }
            }   
        }

        final FileAdapter adapter = new FileAdapter(getActivity(), fileEntries);
        OnClickListener clickListener = new OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                String path;
                SharedPreferences options = PreferenceManager.getDefaultSharedPreferences(getActivity());
                if (adapter.getItem(which).name.equals("..")){
                    //navigate back
                    path = options.getString("BaseDir", "/");
                    path=path.substring(0, path.length());
                    path=path.substring(0,path.lastIndexOf("/"));
                    path = !path.equals("")?path:("/");
                }else {
                    path = options.getString("BaseDir", "");
                    path += ((path.equals("/"))?(""):("/"))+adapter.getItem(which).name;
                }
                Log.d("Path", path);
                Editor editor = options.edit();
                File dirTest = new File(path);
                if (dirTest.isDirectory()){
                    editor.putString("BaseDir", path);
                    editor.commit();
                    //mCallback.onFileSelected("");
                    //createDialog();
                    //*******************DO THE RIGHT THING HERE***********************
                }else{
                    mCallback.onFileSelected(path);
                }
            }
        };
        // Use the Builder class for convenient dialog construction
        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
        builder.setAdapter(adapter, clickListener)
               .setNegativeButton("Abbrechen", new DialogInterface.OnClickListener() {
                   public void onClick(DialogInterface dialog, int id) {
                       dismiss();
                   }
               });
        builder.setTitle("Datei wählen");
        return builder.create();
        }

    private ArrayList<File> getFilesInDir(String dir) {
        File folder = new File(dir);
        if (!folder.exists()){
            folder = new File("/");
            if (!folder.exists()){
                Log.e("FileBrowser","Something's really fishy");
            }
        }
        ArrayList<File> fileList = new ArrayList<File>(Arrays.asList(folder.listFiles()));
        return fileList;
    }

    private boolean isBaseDir(String dir) {
        File folder = new File(dir);
            if (!folder.exists()){
                folder = new File("/");
                if (!folder.exists()){
                    Log.e("FileBrowser","Something's really fishy");
                }
            }
        File baseDir = new File("/");
        if (folder.equals(baseDir)){
            return true;
        }else{
            return false;
        }
    }

    // Container Activity must implement this interface
    public interface OnFileSelectedListener {
        public void onFileSelected(String file);
    }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        // This makes sure that the container activity has implemented
        // the callback interface. If not, it throws an exception
        try { 
            mCallback = (OnFileSelectedListener) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString()
                    + " must implement OnHeadlineSelectedListener");
        }
    }

    class ListEntry {
        public String name;
        public Drawable item ;

        public ListEntry(String name, Drawable item) {
           this.name = name;
           this.item = item;
        }
    }

    class FileAdapter extends ArrayAdapter<ListEntry>{

        public FileAdapter(Context context, ArrayList<ListEntry> fileEntry) {
            super(context, R.layout.filechooser_list_item,fileEntry);
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent){
                ListEntry entry = getItem(position);    
               // Check if an existing view is being reused, otherwise inflate the view
               if (convertView == null) {
                  convertView = LayoutInflater.from(getContext()).inflate(R.layout.filechooser_list_item, parent, false);
               }
               // Lookup view for data population
               TextView filechooserEntry = (TextView) convertView.findViewById(R.id.filechooser_entry);
               // Populate the data into the template view using the data object
               filechooserEntry.setText(entry.name);
               filechooserEntry.setCompoundDrawablesWithIntrinsicBounds(entry.item, null, null, null);
               // Return the completed view to render on screen
               return convertView;
        }   
    }
}

person Kevin Gebhardt    schedule 05.09.2014    source источник
comment
может быть, это сработает для вас .. ((BaseAdapter) ListVIEW.getAdapter()).notifyDataSetChanged();   -  person bGorle    schedule 05.09.2014
comment
Не могли бы вы вместо этого иметь другой фрагмент, возможно, ListFragment, с ListView в xml ListFragment, который можно использовать для отображения списка? Скрыть фрагмент диалога в обработчике событий OnFileSelectedListener и заполнить список ListFragment, а затем показать его? Или, возможно, даже просто используйте ListView в DialogFragment, но лучше использовать фрагменты так, как они предназначены, будучи модульными, каждый фрагмент используется для одного, другой фрагмент используется для другого, что делает код простым и ремонтопригодный.   -  person Bryan    schedule 05.09.2014
comment
Оказывается, есть методы add(), remove() и clear() адаптера. Спасибо Bhr, чей комментарий направляет меня на правильный путь. Это работает сейчас. Настоящая сложная часть заключалась в том, чтобы предотвратить удаление фрагмента при нажатии на список.   -  person Kevin Gebhardt    schedule 08.09.2014
comment
@Bryan Hepburn Ваша идея также может сработать, но я не уверен, что это правильный путь, как мне кажется, файловый браузер - это один модуль, который не следует разделять. Я также не уверен в том, что кнопка «Назад» делает то, что должно, с фрагментом, присутствующим для каждого каталога, и в количестве накладных расходов, связанных с этим подходом.   -  person Kevin Gebhardt    schedule 08.09.2014


Ответы (1)


Вот мое решение для Filebrowser как DialogFragment. Оказывается, в адаптере есть методы add(), remove() и clean(), так что ответ на первоначальный вопрос был очень простым. Сложность заключалась в том, чтобы предотвратить закрытие диалогового окна после выбора элемента списка. Этот ответ очень помог: https://stackoverflow.com/a/15619098/3960095. Вот мой рабочий код для будущих посетителей:

package de.yourCompany.yourProject;

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

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.TextView;

public class FileChooserFragment extends DialogFragment{
    private OnFileSelectedListener mCallback;

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
         // Create the AlertDialog object and return it
        final FileAdapter adapter = new FileAdapter(getActivity(), new ArrayList<ListEntry>());             
        adapter.getFiles();     
        OnClickListener clickListener = new OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
            //do nothing here to prevent dismiss after click    
            }
        };
        // Use the Builder class for convenient dialog construction
        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
        builder.setAdapter(adapter, clickListener)
               .setNegativeButton("Abbrechen", new DialogInterface.OnClickListener() {
                   public void onClick(DialogInterface dialog, int id) {
                   }
               });
        builder.setTitle("Datei wählen");
        final AlertDialog theDialog = builder.show();
        theDialog.getListView().setOnItemClickListener(new OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                String path;
                SharedPreferences options = PreferenceManager.getDefaultSharedPreferences(getActivity());
                if (adapter.getItem(position).name.equals("..")){
                    //navigate back
                    path = options.getString("BaseDir", "/");
                    path=path.substring(0, path.length());
                    path=path.substring(0,path.lastIndexOf("/"));
                    path = !path.equals("")?path:("/");
                }else {
                    //get the Slashes right and navigate forward
                    path = options.getString("BaseDir", "");
                    path += ((path.equals("/"))?(""):("/"))+adapter.getItem(position).name;
                }
                Editor editor = options.edit();
                File dirTest = new File(path);
                if (dirTest.isDirectory()){
                    editor.putString("BaseDir", path);
                    editor.commit();
                    adapter.clear();
                    adapter.getFiles();
                }else{
                    mCallback.onFileSelected(path);
                    theDialog.dismiss();
                }

            }
        });
        return theDialog;
    }

    private boolean isBaseDir(String dir) {
        File folder = new File(dir);
            if (!folder.exists()){
                folder = new File("/");
                if (!folder.exists()){
                    Log.wtf("FileBrowser","Something's really fishy");
                }
            }
        File baseDir = new File("/");
        if (folder.equals(baseDir)){
            return true;
        }else{
            return false;
        }
    }

    // Container Activity must implement this interface
    public interface OnFileSelectedListener {
        public void onFileSelected(String file);
    }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        // This makes sure that the container activity has implemented
        // the callback interface. If not, it throws an exception
        try { 
            mCallback = (OnFileSelectedListener) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString()
                    + " must implement OnHeadlineSelectedListener");
        }
    }

    class ListEntry {
        public String name;
        public Drawable item ;

        public ListEntry(String name, Drawable item) {
           this.name = name;
           this.item = item;
        }
    }

    class FileAdapter extends ArrayAdapter<ListEntry>{

        //show only files with the suffix FILE_SUFFIX, use "*" to show all files;
        private static final String FILE_SUFFIX = ".kml";

        public FileAdapter(Context context, ArrayList<ListEntry> fileEntry) {
            super(context, R.layout.filechooser_list_item,fileEntry);
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent){
                ListEntry entry = getItem(position);    
               // Check if an existing view is being reused, otherwise inflate the view
               if (convertView == null) {
                  convertView = LayoutInflater.from(getContext()).inflate(R.layout.filechooser_list_item, parent, false);
               }
               // Lookup view for data population
               TextView filechooserEntry = (TextView) convertView.findViewById(R.id.filechooser_entry);
               // Populate the data into the template view using the data object
               filechooserEntry.setText(entry.name);
               filechooserEntry.setCompoundDrawablesWithIntrinsicBounds(entry.item, null, null, null);
               // Return the completed view to render on screen
               return convertView;
        }   

        private FileAdapter getFiles() {
            SharedPreferences options = PreferenceManager.getDefaultSharedPreferences(getActivity());
            ArrayList<File> files = getFilesInDir(options.getString("BaseDir", ""));

            if (!isBaseDir(options.getString("BaseDir", ""))){
                this.add(new ListEntry("..", getResources().getDrawable( R.drawable.ic_folder)));
            }

            for (File file : files){            
                if (file.isDirectory()){
                    this.add(new ListEntry(file.getName(),getResources().getDrawable(R.drawable.ic_folder)));
                }else{
                    if (file.getName().endsWith(FILE_SUFFIX)||FILE_SUFFIX.equals("*")){
                        this.add(new ListEntry(file.getName(),getResources().getDrawable(R.drawable.ic_file)));
                    }
                }   
            }
        return this;
        }

        private ArrayList<File> getFilesInDir(String dir) {
            File folder = new File(dir);
            if (!folder.exists()){
                folder = new File("/");
                if (!folder.exists()){
                    Log.wtf("FileBrowser","Something's really fishy");
                }
            }
            ArrayList<File> fileList;
            if (folder.listFiles()!=null){
                fileList = new ArrayList<File>(Arrays.asList(folder.listFiles()));
            }else{
                fileList = new ArrayList<File>();
            }
            return fileList;
        }
    }
}

и в вашей деятельности:

public class YourActivity extends Activity implements FileChooserFragment.OnFileSelectedListener{

@Override
public void onFileSelected(String file) {
//Do whatever you want to do with the files
}

// And whereever you want to start the Fragment: 
FileChooserFragment fileFragment = new FileChooserFragment();
fileFragment.show(getFragmentManager(), "fileChooser"); 
person Kevin Gebhardt    schedule 08.09.2014