Tuesday, July 10, 2012

Example of File Explorer in Android

I have a exercise of "Implement a simple File Explorer in Android" long time ago. As I gain more understanding on Android, I want to revise it with little bit update.

- First of all, as a user app, I think it should not access the root "/" directly. So I assign root to Environment.getExternalStorageDirectory(), it's the Android external storage directory.
- Secondly, if a file/directory is hidden or un-readable, it will not be display.

Example of File Explorer


Create /res/layout/row.xml, the layout of the rows in the list.
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/rowtext"
    android:layout_width="fill_parent"
    android:layout_height="30sp"
    android:textSize="25sp" />


The main layout with a ListView.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" 
    android:orientation="vertical">
    
    <TextView
        android:id="@+id/path"
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content" />
    <ListView
        android:id="@android:id/list"
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content" 
        />
    <TextView
        android:id="@android:id/empty"
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content" 
        android:text="No Data"
        />

</LinearLayout>


Main code.
package com.example.androidexplorer;

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

import android.os.Bundle;
import android.os.Environment;
import android.app.AlertDialog;
import android.app.ListActivity;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;

public class MainActivity extends ListActivity {
 
 private List<String> item = null;
 private List<String> path = null;
 private String root;
 private TextView myPath;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        myPath = (TextView)findViewById(R.id.path);
        
        root = Environment.getExternalStorageDirectory().getPath();
        
        getDir(root);
    }
    
    private void getDir(String dirPath)
    {
     myPath.setText("Location: " + dirPath);
     item = new ArrayList<String>();
     path = new ArrayList<String>();
     File f = new File(dirPath);
     File[] files = f.listFiles();
     
     if(!dirPath.equals(root))
     {
      item.add(root);
      path.add(root);
      item.add("../");
      path.add(f.getParent()); 
     }
     
     for(int i=0; i < files.length; i++)
     {
      File file = files[i];
      
      if(!file.isHidden() && file.canRead()){
       path.add(file.getPath());
          if(file.isDirectory()){
           item.add(file.getName() + "/");
          }else{
           item.add(file.getName());
          }
      } 
     }

     ArrayAdapter<String> fileList =
       new ArrayAdapter<String>(this, R.layout.row, item);
     setListAdapter(fileList); 
    }

 @Override
 protected void onListItemClick(ListView l, View v, int position, long id) {
  // TODO Auto-generated method stub
  File file = new File(path.get(position));
  
  if (file.isDirectory())
  {
   if(file.canRead()){
    getDir(path.get(position));
   }else{
    new AlertDialog.Builder(this)
     .setIcon(R.drawable.ic_launcher)
     .setTitle("[" + file.getName() + "] folder can't be read!")
     .setPositiveButton("OK", null).show(); 
   } 
  }else {
   new AlertDialog.Builder(this)
     .setIcon(R.drawable.ic_launcher)
     .setTitle("[" + file.getName() + "]")
     .setPositiveButton("OK", null).show();

    }
 }

}


Download the files.

Next:
- Sort directory/file in alphabetical order ignore case


39 comments:

  1. can you please post the manifest file as well? I don't seem to be able to run the code even though it shows no error. maybe i forgot to add a line in the manifest. there is nowhere a good tutorial which includes manifest file...

    ReplyDelete
  2. Hello Tobias Klein,

    You can download the files, manifest included.

    ReplyDelete
  3. this line gives an error because i extend Activity instead of ListActivity.
    setListAdapter(fileList);
    what could i do to fix it?
    thanks

    ReplyDelete
  4. hello tegleg records android,

    something like this:
    your_ListView.setAdapter(fileList);

    ReplyDelete
  5. You need to add the following permission to your Android Manifest file --

    ReplyDelete
  6. uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"

    ReplyDelete
  7. This comment has been removed by the author.

    ReplyDelete
  8. thanks, your_ListView.setAdapter(fileList); fixes the error but now the browser doesnt work, you cant open folders.

    ReplyDelete
  9. Hello tegleg records android,

    I don't know the exact reason of your case. But, if you target for minimum SDK of level 16, Android 4.1, you have to add permission of READ_EXTERNAL_STORAGE.

    New permission for Android 4.1, API Level: 16.

    ReplyDelete
  10. minimum level is 8.
    for testing i copied your code but changed it to extend Activity.
    then i changed setadapter.. stuff to your suggestion. it asked to remove the overide on onListItemClick() so i did that. on the phone i get the first level but clicking on anything doesnt bring up the dialog and also folders dont open. must be something to do with onListItemClick but i dont know what.
    thanks so much for taking the time to answer.

    ReplyDelete
  11. Hello tegleg records android,

    If you extends Activity, instead of ListActivity, tou cannot override onListItemClick() directltly; because there is no onListItemClick() in Activity class.

    You have to implement OnItemClickListener() and call myListView.setOnItemClickListener(...) to assign it to the ListView.

    Refer Implement ListView NOT extends ListActivity.

    ReplyDelete
  12. awesome, got it working now.
    thanks for sharing the code and for your support :)

    ReplyDelete
  13. I couldn't get this to work until I moved the initializations for the private members(item, path, etc.) to the onCreate
    method. So in onCreate I have item = null; path = null; , etc.

    ReplyDelete
  14. Hi everyone !
    I donwloaded your archive and it works ! Thanks !
    But now, I want to open files (for example, when I click on jpeg file, I want to display it, I don't know if you understand...)

    Thanks for your help ;)

    ReplyDelete
  15. Thanks for your help !
    I did it with jpeg image but if I want to play a music (mp3,wav or mid for example), have you got a idea ?

    ReplyDelete
  16. Thank you for your code. I want to add a back button but I don't know how to program it to do wht the "../" button does. This is what i have:

    @Override
    public boolean onOptionsItemSelected(MenuItem items){
    switch(items.getItemId()){
    case R.id.home:
    path.add(root);
    //myPath.invalidate();
    //f.invalidateViews();
    return true;

    case R.id.back:
    path.add(f.getParent());
    return true;

    default:
    return super.onOptionsItemSelected(items);
    }
    }

    ReplyDelete
  17. you can call
    getDir(root);
    getDir(f.getParent());

    ReplyDelete
  18. Hello,
    I've came across this nice example of yours as I am currently working on my diploma project for the university. I would like to ask you if it is ok to use it as i found no specifications regarding a license or so.
    Thank you,
    Monica

    ReplyDelete
  19. hello Monica Ias,

    It's only a common approach, and no any license. You can use it.

    And remind here, as I know, use Environment.getExternalStorageDirectory() in this case cannot access SD Card in Samsung devices.

    ReplyDelete
  20. Hey again :)

    I tried it on a Samsung Galaxy S3 Mini and it worked just fine. Though I don't have an SD card...

    Anyway, thank you.
    Have a nice day!
    Monica.

    ReplyDelete
  21. Very nice. It help me with my project. Thank you very much!

    ReplyDelete
  22. Hi, could you write tutorial how to add SU permission to this? I would be great because nowhere in the Internet there is such tutorial how to create a simple root file manager.

    ReplyDelete
  23. hello kormateusz,

    I don't know what you means "SU permission"? SU? as a app on un-rooted device, it should have no right as SU, as I know.

    root file manager? do you means file manager have right of root user? I have no idea. If you want file explorer for root directory, "/", here is another example: http://android-er.blogspot.com/2010/01/implement-simple-file-explorer-in.html

    ReplyDelete
  24. SU I mean Super User. Yes, I mean File Manager for rooted device. For example to view directories and files from "/data", "/cache" or "/config".

    I added such code:

    Process process;

    try {
    process = Runtime.getRuntime().exec(new String[] {"su", "-c", "ls /data"});
    BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()));

    String line;
    while ((line = in.readLine()) != null) {
    pathleft.add(line);
    }

    } catch (IOException e) {
    e.printStackTrace();
    Toast.makeText(getActivity(),
    "NOT ROOT",
    Toast.LENGTH_LONG).show();
    }


    And it display files from "/data" but I can't enter to the next directory or open a file from "/data". And even I can't sort these files.

    Maybe you know how to fix it?

    And sorry for my english, its not perfect :)

    ReplyDelete
  25. Oh, I have found the solution and it works pretty well. Really sorry for the problem.

    ReplyDelete
  26. Hello, thak you very much for this file manager tutorial. I made the possibility to select a file and then edit it in another activity of course (and this often requests a file name modification); so when I return to the activity filelist I make a refresh, calling getdir with the previous directory path, but the file name remains the same so I have to move to another directory and re-enter to the original again; have you got an idea to solve this, sir?

    ReplyDelete
  27. Hey thanks for the guide :D How would you go about opening a text file though? I looked at your open image guide but I dont think it covers opening a text files content and displaying it.

    ReplyDelete
  28. Eric, can you explain why you added a row.xml file and what is its purpose?

    ReplyDelete
  29. hello 178º,

    row.xml is the layout of individual row in ListView. It is passed to ArrayAdapter constructor.

    Because I want a bigger text in ListView, so I have to create a custom layout.

    ReplyDelete
  30. HI,
    I am trying to use this code inside an activity that is launched after click on the button inside the mainActivity.
    but i am getting error here when i am calling "getdir(root)" this is throwing the exception " couldn't execute method GETDIR(root)"

    Thanks
    Rishav

    ReplyDelete
  31. Thank you for your great downloable example! : )

    ReplyDelete
  32. works!

    but i cant find downloads folder anywhere in filebrowser.

    any ideas?

    ReplyDelete
  33. Actually, its ok now. Forgot that CCleaner had obliterated my Downloads folder, meaning it doesn't show (when it's empty). This newer code really does work!

    Now I just need to use the selected file with an Intent... Thanks.

    ReplyDelete
  34. Caused by: java.lang.NullPointerException: Attempt to get length of null array


    Is there anything else that I have to add?

    ReplyDelete
  35. how to filter folders based on specific file extension. for example if i want only folders that contain ".mp3", so how can i achieve this?

    ReplyDelete