andbook!.pdf - Learning Android Get an anddev.org - Android-Shirt Back to index
anddev.org Header Logo
FAQ Search Top rated articles Browse Feeds anddev.org - Authors Contact Details Register Log in

Building an Android FileBrowser (list-based) !

Goto page 1, 2  Next
 
       anddev.org - Android Development Community | Android Tutorials | Index -> Novice Tutorials
Author Message
plusminus
Site Admin
Site Admin


Joined: 14 Nov 2007
Posts: 2655
Location: College Park, MD

PostPosted: Mon Nov 19, 2007 7:21 pm    Post subject: Building an Android FileBrowser (list-based) ! Reply with quote

John Lombard granted permission to write a tutorial based on his FileBrowser-Tutorial here. Thank you Smile
@His Source
Building an Android FileBrowser (list-based)


What is this: We create an really simple file browser using a ListView.

What this tutorial includes:
  • Browse the FileSystem
  • React on Clicks
  • Sending Intents to the System (Open clicked files)

See also: ListActivity - Functionality

Question Problems/Questions: post right below...

Difficulty: 1.75 of 5 Smile ( rumors say its just a: 1.74 of 5 )

What it will look like:
Mode: ABSOLUTE

Mode: RELATIVE



Description:
0. Create a new Project, you could use package names like the following...

1. Create a new layout called file_row.xml. It should look the same as below.
XML:
<?xml version="1.0" encoding="utf-8"?>
<TextView
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="fill_parent"
     android:layout_height="wrap_content"
/>

2. Modify the onCreate() function in AndroidFileBrowser.java so that it reads as the following:
Java:
     /** Called when the activity is first created. */
     @Override
     public void onCreate(Bundle icicle) {
          super.onCreate(icicle);
          // setContentView() gets called within the next line,
          // so we do not need it here.
          browseToRoot();
     }

We added a call to the browseToRoot() method. We haven't written browseToRoot() yet, but we'll get there in a second.

3. Change the class that AndroidFileBrowser extends from "Activity" to "ListActivity", because our files/directories will be listed in a list. It should look like this:

Java:
public class FileList extends ListActivity {


4. Create a private field, items, that holds the current directory and a list of the sub-Entries(Files/Dirs). This should go just under the "public class FileList" line. As we are planning to make Relative and Absolute Views available, we create a little enum and create a field of it. That part will look like the following:

Java:
//...
public class AndroidFileBrowser extends ListActivity {
     
     private enum DISPLAYMODE{ ABSOLUTE, RELATIVE; }

     private final DISPLAYMODE displayMode = DISPLAYMODE.ABSOLUTE;
     private List<String> directoryEntries = new ArrayList<String>();
     private File currentDirectory = new File("/");
     //...


5. Lets take a look at the browseToRoot()-Function we called in inCreate()...
As Android is Linux based, the filesystem-root-directory is called "/".
Java:
     /**
      * This function browses to the
      * root-directory of the file-system.
      */

     private void browseToRoot() {
          browseTo(new File("/"));
    }


6. Next is the browseTo-Function which determines, whether the passed parameter is a directory (calls "fill(aDirectory.listFiles());") or a File (calls "openFile(aDirectory);" if the user permitted.)
Java:
     private void browseTo(final File aDirectory){
          if (aDirectory.isDirectory()){
               this.currentDirectory = aDirectory;
               fill(aDirectory.listFiles());
          }else{
               OnClickListener okButtonListener = new OnClickListener(){
                    // @Override
                    public void onClick(DialogInterface arg0, int arg1) {
                              // Lets start an intent to View the file, that was clicked...
                              openFile(aDirectory);
                    }
               };
               OnClickListener cancelButtonListener = new OnClickListener(){
                    // @Override
                    public void onClick(DialogInterface arg0, int arg1) {
                         // Do nothing
                    }
               };
               AlertDialog.show(this,"Question", "Do you want to open that file?\n"
                                        + aDirectory.getName(),
                                        "OK", okButtonListener,
                                        "Cancel", cancelButtonListener, false, null);
          }
     }



7. The private fill() method takes a File[] array, and displays each file name on the screen in the list, including a switch on out Mode (Rel. or Abs.). It also displays two String for backward navigation (we define in strings.xml: 'up_one_level', ...)
XML:
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">Android File Browser - by anddev.org</string>
    <string name="up_one_level">..</string>
    <string name="current_dir">.</string>
</resources>

Java:
     private void fill(File[] files) {
          this.directoryEntries.clear();
          
          // Add the "." == "current directory"
          // and the ".." == 'Up one level'
          this.directoryEntries.add(getString(R.string.current_dir));      
          if(this.currentDirectory.getParent() != null)
               this.directoryEntries.add(getString(R.string.up_one_level));
          
          switch(this.displayMode){
               case ABSOLUTE:
                    for (File file : files){
                         this.directoryEntries.add(file.getPath());
                    }
                    break;
               case RELATIVE: // On relative Mode, we have to add the current-path to the beginning
                    int currentPathStringLenght = this.currentDirectory.getAbsolutePath().length();
                    for (File file : files){
                         this.directoryEntries.add(file.getAbsolutePath().substring(currentPathStringLenght));
                    }
                    break;
          }


8. The lines in each switch-case take the files[] array and fill the class-field "this.directoryEntries" of the type ArrayList<String> with all the file's name. "this.directoryEntries" is a class field because it will be used later when the user clicks on one of the files or directories.

9. The last two lines (see below) create an ArrayAdapter<String> out of the items using the file_row layout. This is what marries the list of List of files to the list on the screen.
Java:
          ArrayAdapter<String> directoryList = new ArrayAdapter<String>(this,
                    R.layout.file_row, this.directoryEntries);
          
          this.setListAdapter(directoryList);


10. Hit Shift-Control-O to Organize Imports, from time to time...

11. Save all your files and run. You should have a list of directories on your emulated Android phone.

12. Click on them and nothing happens -- next step fixes that.

Navigating the Directory Tree:

Now that we can see the root directory structure, we somehow need to get 'into' the FileSystem...

1. When the user clicks on a list item, we have the opportunity to intercept that click and do something interesting with it. To that end we override the onListItemClick(...) method of ListActivity
1.1. The only thing we need to do now is switching, which item we have clicked ('current_dir', 'up_one_level', or another File/Directory)

Note: that using the "getString(R.string.<name>)" is preferable to including the string as a final field within your class (or even worse, just putting the string in-line). Moving all of your strings to the resource directory goes a long way toward internationalizing your code if you ever need to do so.

The Full Source:
res/layout/file_row.xml
XML:
<?xml version="1.0" encoding="utf-8"?>
<TextView
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="fill_parent"
     android:layout_height="wrap_content"
/>


res/values/strings.xml
XML:
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">Android File Browser - by anddev.org</string>
    <string name="up_one_level">..</string>
    <string name="current_dir">.</string>
</resources>


sry/your_package_strcuture/AndroidFileBrowser.java
Java:
package org.anddev.android.filebrowser;

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

import android.app.AlertDialog;
import android.app.ListActivity;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.DialogInterface.OnClickListener;
import android.net.ContentURI;
import android.os.Bundle;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.ListView;

public class AndroidFileBrowser extends ListActivity {
     
     private enum DISPLAYMODE{ ABSOLUTE, RELATIVE; }

     private final DISPLAYMODE displayMode = DISPLAYMODE.ABSOLUTE;
     private List<String> directoryEntries = new ArrayList<String>();
     private File currentDirectory = new File("/");

     /** Called when the activity is first created. */
     @Override
     public void onCreate(Bundle icicle) {
          super.onCreate(icicle);
          // setContentView() gets called within the next line,
          // so we do not need it here.
          browseToRoot();
     }
     
     /**
      * This function browses to the
      * root-directory of the file-system.
      */

     private void browseToRoot() {
          browseTo(new File("/"));
    }
     
     /**
      * This function browses up one level
      * according to the field: currentDirectory
      */

     private void upOneLevel(){
          if(this.currentDirectory.getParent() != null)
               this.browseTo(this.currentDirectory.getParentFile());
     }
     
     private void browseTo(final File aDirectory){
          if (aDirectory.isDirectory()){
               this.currentDirectory = aDirectory;
               fill(aDirectory.listFiles());
          }else{
               OnClickListener okButtonListener = new OnClickListener(){
                    // @Override
                    public void onClick(DialogInterface arg0, int arg1) {
                         try {
                              // Lets start an intent to View the file, that was clicked...
                              Intent myIntent = new Intent(android.content.Intent.VIEW_ACTION,
                                        new ContentURI("file://"
                                                  + aDirectory.getAbsolutePath()));
                              startActivity(myIntent);
                         } catch (URISyntaxException e) {
                              e.printStackTrace();
                         }
                    }
               };
               OnClickListener cancelButtonListener = new OnClickListener(){
                    // @Override
                    public void onClick(DialogInterface arg0, int arg1) {
                         // Do nothing
                    }
               };
               AlertDialog.show(this,"Question", "Do you want to open that file?\n"
                                        + aDirectory.getName(),
                                        "OK", okButtonListener,
                                        "Cancel", cancelButtonListener, false, null);
          }
     }

     private void fill(File[] files) {
          this.directoryEntries.clear();
          
          // Add the "." and the ".." == 'Up one level'
          try {
               Thread.sleep(10);
          } catch (InterruptedException e1) {
               // TODO Auto-generated catch block
               e1.printStackTrace();
          }
          this.directoryEntries.add(".");
          
          if(this.currentDirectory.getParent() != null)
               this.directoryEntries.add("..");
          
          switch(this.displayMode){
               case ABSOLUTE:
                    for (File file : files){
                         this.directoryEntries.add(file.getPath());
                    }
                    break;
               case RELATIVE: // On relative Mode, we have to add the current-path to the beginning
                    int currentPathStringLenght = this.currentDirectory.getAbsolutePath().length();
                    for (File file : files){
                         this.directoryEntries.add(file.getAbsolutePath().substring(currentPathStringLenght));
                    }
                    break;
          }
          
          ArrayAdapter<String> directoryList = new ArrayAdapter<String>(this,
                    R.layout.file_row, this.directoryEntries);
          
          this.setListAdapter(directoryList);
     }

     @Override
     protected void onListItemClick(ListView l, View v, int position, long id) {
          int selectionRowID = (int) this.getSelectionRowID();
          String selectedFileString = this.directoryEntries.get(selectionRowID);
          if (selectedFileString.equals(".")) {
               // Refresh
               this.browseTo(this.currentDirectory);
          } else if(selectedFileString.equals("..")){
               this.upOneLevel();
          } else {
               File clickedFile = null;
               switch(this.displayMode){
                    case RELATIVE:
                         clickedFile = new File(this.currentDirectory.getAbsolutePath()
                                                            + this.directoryEntries.get(selectionRowID));
                         break;
                    case ABSOLUTE:
                         clickedFile = new File(this.directoryEntries.get(selectionRowID));
                         break;
               }
               if(clickedFile != null)
                    this.browseTo(clickedFile);
          }
     }
}


Regards,
plusminus

_________________
Download my apps Idea
Please remember, that this board is give & take Smile


| Android Development Community / Tutorials


Last edited by plusminus on Fri Jan 04, 2008 10:27 am; edited 3 times in total
Back to top
View user's profile Send private message Send e-mail Visit poster's website
atr
Junior Developer
Junior Developer


Joined: 19 Nov 2007
Posts: 14
Location: Singapore

PostPosted: Tue Nov 20, 2007 2:01 pm    Post subject: FileList class? Reply with quote

Hi there,

Step 3: about FileList class, there is no such class right? Did you misstype or something? The only class is AndroidFileBrowser.

Thank you!
Back to top
View user's profile Send private message Visit poster's website
atr
Junior Developer
Junior Developer


Joined: 19 Nov 2007
Posts: 14
Location: Singapore

PostPosted: Tue Nov 20, 2007 2:17 pm    Post subject: DirectoryList Reply with quote

Hi,

and the other failure is within onCreate():
Code:
setContentView(R.layout.directory_list);


that line has to be removed! Thats all... really nice tutorial, anyway! Thanks Razz
Back to top
View user's profile Send private message Visit poster's website
plusminus
Site Admin
Site Admin


Joined: 14 Nov 2007
Posts: 2655
Location: College Park, MD

PostPosted: Tue Nov 20, 2007 3:12 pm    Post subject: Reply with quote

Huh yes,
that tut was a lot of copy-pasting from eclipse... Razz

Thx for the info Exclamation , fixed it.

Regards,
plusminus

_________________
Download my apps Idea
Please remember, that this board is give & take Smile


| Android Development Community / Tutorials
Back to top
View user's profile Send private message Send e-mail Visit poster's website
plusminus
Site Admin
Site Admin


Joined: 14 Nov 2007
Posts: 2655
Location: College Park, MD

PostPosted: Thu Jan 03, 2008 2:51 pm    Post subject: Reply with quote

Hey guys,

Note: The application runs with application privileges. I.e. the data folder requires system privileges. When you start adb you run as root. But this application runs only with application-privileges. I imagine that Android will implement something, at some point, that allows the user to override security if necessary.

Regards,
plusminus

_________________
Download my apps Idea
Please remember, that this board is give & take Smile


| Android Development Community / Tutorials
Back to top
View user's profile Send private message Send e-mail Visit poster's website
hiro
Freshman
Freshman


Joined: 02 Jan 2008
Posts: 4
Location: Tucson

PostPosted: Thu Jan 03, 2008 8:53 pm    Post subject: Reply with quote

Thank you for this tutorial! It was exactly what I was looking for. (working on a silly little mp3 player)
Back to top
View user's profile Send private message Visit poster's website
blackice
Freshman
Freshman


Joined: 03 Jan 2008
Posts: 2

PostPosted: Thu Jan 03, 2008 9:49 pm    Post subject: Reply with quote

I am new to the platform and may be mistaken Embarassed but I think the following method is missing.

Java:
private void openFile(File aFile){
        try {
             Intent myIntent = new Intent(android.content.Intent.VIEW_ACTION,
                  new ContentURI("file://" + aFile.getAbsolutePath()));
             startActivity(myIntent);
        } catch (URISyntaxException e) {
             e.printStackTrace();
        }
   }

Thank-you very much for the tutorials.
Back to top
View user's profile Send private message
plusminus
Site Admin
Site Admin


Joined: 14 Nov 2007
Posts: 2655
Location: College Park, MD

PostPosted: Fri Jan 04, 2008 10:55 am    Post subject: Reply with quote

Hello blackice,

yes, that is missing. But as far as I remember it didn't work as good as expected Sad

Regards,
plusminus

_________________
Download my apps Idea
Please remember, that this board is give & take Smile


| Android Development Community / Tutorials
Back to top
View user's profile Send private message Send e-mail Visit poster's website
rmeph
Senior Developer
Senior Developer


Joined: 10 Dec 2007
Posts: 120
Location: India

PostPosted: Fri Jan 04, 2008 3:11 pm    Post subject: Reply with quote

there

Java:
                             Intent myIntent = new Intent(android.content.Intent.VIEW_ACTION,
                                        new ContentURI("file://"
                                                  + aDirectory.getAbsolutePath()));
                              startActivity(myIntent);

u get file in ContentURL................can we it get in string(string[] or inputstream) ??????if that is possible that how do it???
Back to top
View user's profile Send private message
inter
Junior Developer
Junior Developer


Joined: 21 Feb 2008
Posts: 23

PostPosted: Thu Feb 28, 2008 2:58 pm    Post subject: Reply with quote

Hii

I use new platform .

Intent i=new Intent(android.content.Intent.VIEW_ACTION,Uri.parse("file://"+aDirectory.getAbsolutePath()));
this.startActivity(i);


it's so OK
Back to top
View user's profile Send private message
manojo
Freshman
Freshman


Joined: 21 Mar 2008
Posts: 4

PostPosted: Tue Mar 25, 2008 3:02 pm    Post subject: Reply with quote

I don't have the android.net.ContentURI class. Has there been a modification in the specs?

Manojo
Back to top
View user's profile Send private message
bhushank_vit
Freshman
Freshman


Joined: 19 Feb 2008
Posts: 2
Location: india

PostPosted: Mon Mar 31, 2008 7:22 am    Post subject: Reply with quote

[quote="manojo"]I don't have the android.net.ContentURI class. Has there been a modification in the specs?

Manojo[/quote]

hi Manojo,
Please refer this link..
http://code.google.com/android/migrating/m3-to-m5/m5-api-changes.html#sql

u can use Uri.parse("//....") Instead of new Contenturi()

...Bhushan
Back to top
View user's profile Send private message Yahoo Messenger
bhushank_vit
Freshman
Freshman


Joined: 19 Feb 2008
Posts: 2
Location: india

PostPosted: Mon Mar 31, 2008 7:52 am    Post subject: Reply with quote

hi,
m getting this error....

Application Error:
com.google.android.fileBrowser
An Error has occured in com.google.android.fileBrowser.
No activity found to handle Intent{action = android.intent.action.VIEW data=/ }.

please suggest something..
thanks'
Back to top
View user's profile Send private message Yahoo Messenger
bjreddi
Junior Developer
Junior Developer


Joined: 03 Apr 2008
Posts: 17

PostPosted: Wed Apr 09, 2008 1:02 pm    Post subject: Re: Building an Android FileBrowser (list-based) ! Reply with quote

Hi plusminus,

In your filebrowser application.

In browseTo() function call , you have used this AlertDialog.show () function. I get the error on the line, When i checked it.. there were less number of arguments than expected.

i think correct one is:
AlertDialog.show(this,"Question","Do you want to open that file?\n"
+ aDirectory.getName(),
"OK", okButtonListener,
"Cancel", cancelButtonListener, false, null);

Thank you for the application.

Regards,
Jo
Back to top
View user's profile Send private message
bjreddi
Junior Developer
Junior Developer


Joined: 03 Apr 2008
Posts: 17

PostPosted: Wed Apr 09, 2008 2:00 pm    Post subject: Reply with quote

Hi,

Yes.. That works in previous versions of Android.
Now in m5 android release.. Network API has been changed.

Instead of contentURI you can use..

Uri.parse("");

and import android.net.Uri;

That works fine.
Back to top
View user's profile Send private message
Display posts from previous:   
       anddev.org - Android Development Community | Android Tutorials | Index -> Novice Tutorials All times are GMT + 1 Hour
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


© 2007, Android Development Community
All rights reserved.
Powered by phpBB.