0

I want to show the list of music files available in SD card in my app. Here is the java code. Code is working without any error but no MP3 Files are shown instead ListView is being populated with the Names of folders in phone's internal memory.

MainActivity.java

final String MEDIA_PATH = Environment.getExternalStorageDirectory().getAbsolutePath();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        ListView listsong =(ListView)findViewById(R.id.songslistView);

        ArrayList<String> mp3list = new ArrayList<String>();
        mp3list=mp3select();
        Toast.makeText(this, "mp3files" + mp3list,                Toast.LENGTH_LONG).show();

        ArrayAdapter<String> listAdapter=new ArrayAdapter<String>(MainActivity.this,android.R.layout.simple_list_item_1,mp3list);
        listsong.setAdapter(listAdapter);

    }

    public ArrayList<String> mp3select(){
        File home = new File(MEDIA_PATH);
        ArrayList<String> list = new ArrayList<String>();
        //if (home.isDirectory())

        if (home.listFiles(new AudioFileFilter()).length > 0)
        {
            for (File file : home.listFiles(new AudioFileFilter()))
            {
                list.add(file.getName());
            }
        }
        return list;
    }

AudioFileFilter.java

public class AudioFileFilter implements FileFilter {

    protected static final String TAG = "AudioFileFilter";
    /**
     * allows Directories
     */
    private final boolean allowDirectories;

    public AudioFileFilter( boolean allowDirectories) {
        this.allowDirectories = allowDirectories;
    }

    public AudioFileFilter() {
        this(true);
    }

    @Override
    public boolean accept(File f) {
        if ( f.isHidden() || !f.canRead() ) {
            return false;
        }

        if ( f.isDirectory() ) {
            return allowDirectories;
        }
        String ext = getFileExtension(f);
        if ( ext == null) return false;
        try {
            if ( SupportedFileFormat.valueOf(ext.toUpperCase()) != null ) {
                return true;
            }
        } catch(IllegalArgumentException e) {
            //Not known enum value
            return false;
        }
        return false;
    }

    public String getFileExtension( File f ) {
        int i = f.getName().lastIndexOf('.');
        if (i > 0) {
            return f.getName().substring(i+1);
        } else
            return null;
    }

    /**
     * Files formats currently supported by Library
     */
    public enum SupportedFileFormat
    {
        _3GP("3gp"),
        MP4("mp4"),
        M4A("m4a"),
        AAC("aac"),
        TS("ts"),
        FLAC("flac"),
        MP3("mp3"),
        MID("mid"),
        XMF("xmf"),
        MXMF("mxmf"),
        RTTTL("rtttl"),
        RTX("rtx"),
        OTA("ota"),
        IMY("imy"),
        OGG("ogg"),
        MKV("mkv"),
        WAV("wav");

        private String filesuffix;

        SupportedFileFormat( String filesuffix ) {
            this.filesuffix = filesuffix;
        }

        public String getFilesuffix() {
            return filesuffix;
        }
    }

}

I have gone through few questions related to the topic. I am not able to identify the problem. Any help is appreciated. Thanks in Advance.

gautamprajapati
  • 2,055
  • 5
  • 16
  • 31
  • Do you have the correct permissions set in your manifest? That is http://developer.android.com/reference/android/Manifest.permission.html#READ_EXTERNAL_STORAGE – Matt Wolfe Oct 10 '15 at 16:46
  • Also one thing to note is that it seems highly innefficient to create a new AudioFilter for every single file you find. It seems like a simple recursive function would be much more appropriate. Some examples here: http://stackoverflow.com/questions/2056221/recursively-list-files-in-java – Matt Wolfe Oct 10 '15 at 16:48
  • Did you figure out the problem? – Matt Wolfe Oct 12 '15 at 05:38

1 Answers1

1

You aren't recursing through the directories, instead you're just showing the directory names if you've passed in allowDirectories to your AudioFilter, which you have since you are passing in a no argument constructor which defaults to true. What you want to do scan a directory for files matching your filter, and when you find a subdirectory, you want to add that to a list of directories to scan. You can do this a number of ways. One way is recursion. When you find a directory you call the same function with that directory as the input parameter. Another way is you could keep a list of directories to scan and each time you find a directory, append that to the list. When you are done scanning files in a directory, pop a directory off the list of directories and continue until you've got no directories to scan.

Here is the idea for the recursive way:

 private FileFilter mFileFilter;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);
    mFileFilter = new AudioFilter();

    ListView listsong =(ListView)findViewById(R.id.songslistView);

    ArrayList<String> mp3list = new ArrayList<String>();
    ArrayList<File> fileList = new ArrayList<File>();
    File home = new File(MEDIA_PATH);
    mp3select(home, fileList);
    //now you need to map your ArrayList<File> to ArrayList<String>.  Personally I would use a different kind of adapter and just return the name of the file while keeping the entire file reference


    ArrayAdapter<String> listAdapter=new ArrayAdapter<String>(MainActivity.this,android.R.layout.simple_list_item_1,mp3list);
    listsong.setAdapter(listAdapter);

}

public void mp3select(File dir, ArrayList<File> fileList){  
    if (!home.isDirectory()) {
        return;
    }
    for (File file : home.listFiles(mAudioFilter))
    {
        if (file.isDirectory()) {
           mp3List(file, fileList);
        } else {
           fileList.add(file);
        }
    }
}
Matt Wolfe
  • 8,924
  • 8
  • 60
  • 77
  • I think you should test your code before posting it as an answer. There are many things in your code you should see like correct return type of `mp3select()` function , proper use of variable names in functions(How are you using `home` in function `mp3select()` ?). Please edit the answer. Its not working. – gautamprajapati Oct 12 '15 at 17:06
  • Sorry, I posted this answer but somehow stack overflow put up 2 posts for it and the one I had been editing I deleted... I had fixed those. But honestly you shouldn't bite the hand that feeds you, Do you understand the concept of recursion? – Matt Wolfe Oct 12 '15 at 18:13
  • My answer was meant as an example not a cut and paste solution. If you don't get the concept of what I was trying to convey then I did a poor job conveying it or you were just expecting someone to do your work for you. I've updated the answer with some more information on how it should work but you shouldn't expect code on here to be production ready, – Matt Wolfe Oct 12 '15 at 18:22
  • I am sorry, didn't wanted to offend you. You really did a good job conveying your way of solving the problem. I figured out this problem by using your method only. I just identified the errors in solution so that if someone tries to read or copy it, he/she should not face the problem. BTW after edit it is more understandable. Also can you please explain how should I change my `MEDIA_PATH` variable to search the directories in my External SD card, right now it is recursing only through phone's Internal Memory. – gautamprajapati Oct 13 '15 at 16:55
  • Also I need the help regarding mapping you mentioned in a comment in the code. How to map my ArrayList to ArrayList and return only the file name. – gautamprajapati Oct 13 '15 at 17:29
  • Are you going to use the list for anything other than just displaying it? If you just show the name without the path then how would you use this to say play to file later? If it's just a list and you don't need the file references you can just save to the mp3List (List) data structure by getting the name of the file, so you'd change fileList.add(file) to mp3List.add(file.getName()); – Matt Wolfe Oct 13 '15 at 17:52
  • All right but I will use the list to play the mp3 too. I will need the reference to the path then, how should I combine the both? any suggestions? I want to show just the file name and play the music too on click of an item. Also how can I modify my media path so that I can display files from External SD card not just internal memory of phone? – gautamprajapati Oct 14 '15 at 09:29
  • I would create a custom adapter personally. See the second example here for an idea how to do that.. https://github.com/codepath/android_guides/wiki/Using-an-ArrayAdapter-with-ListView – Matt Wolfe Oct 14 '15 at 16:26