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


32 comments:

Tobias Klein said...

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...

Android Er said...

Hello Tobias Klein,

You can download the files, manifest included.

tegleg records android said...

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

Android Er said...

hello tegleg records android,

something like this:
your_ListView.setAdapter(fileList);

Anand said...

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

Anand said...

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

Anand said...
This comment has been removed by the author.
tegleg records android said...

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

Android Er said...

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.

tegleg records android said...

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.

Android Er said...

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.

tegleg records android said...

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

Bruno Franchini said...

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.

Badboy said...

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 ;)

Andr.oid Eric said...

hello Badboy,

Please read Android File Explorer with JPG's Exif & Photo displayed.

Badboy said...

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 ?

Andr.oid Eric said...

Play "audio/mp3" with MediaPlayer

or

Start Intent to choice "audio/mp3" using installed app

Chidozie Ikpe said...

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);
}
}

Andr.oid Eric said...

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

Monica Ias said...

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

Andr.oid Eric said...

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.

Monica Ias said...

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.

Андрей Орлов said...

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

Kanika Khetawat said...

File closes unexpectedly

kormateusz said...

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.

Andr.oid Eric said...

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

kormateusz said...

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 :)

kormateusz said...

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

Anonymous said...

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?

Zarathas said...

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.

178º said...

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

Andr.oid Eric said...

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.