Como vimos en un tutorial pasado aprendimos a buscar y encontrar todas las rutas de almacenamiento interno o sd,en este caso aprenderemos como crear un explorador de archivos partiendo de eso.
Este explorador lo haremos en partes,en este tutorial aprenderemos a crear un explorador minimo,lo suficiente para navegar por directorios y ver archivos,no los podremos abrir ni nada solo ver,pero en otros tutoriales lo mejoraremos.
Bien,si ven el tutorial de como buscar las sd cards o almacenamientos,al final podemos ver una imagen donde se muestran las rutas de los almacenamientos con texto.
Justamente partiremos de eso,solo que usaremos diseño grafico,dicen que el diseño grafico hace que la programación se vea agradable y como no soy diseñador grafico vamos a usar iconos de:
Estos son los que yo ocupe:
Primero vamos a abrir eclipse y crear un nuevo proyecto android,le vamos a poner de nombre,por ejemplo:
Ahora vamos a crear un grid para elegir los posibles almacenamientos,pero para crear un grid necesitamos un Adaptador,pero primero vamos a crear un objeto donde guardar la informacion de cada archivo:
Ese archivo no se tiene que explicar mucho solo son getters y setters que es el objeto mínimo para guardar información,uno para el nombre otro para el path y también para ver si es un directorio,este se podría usar desde la clase File pero nos ahorramos usar mas de una llamada.
Bien ahora si el Adapter,lo explico en el codigo:
Ese seria un adaptador mínimo para usar un grid,ahora lo podríamos llamar definiendo lo necesario en MainActivity y quedaría así:
Bien aun no lo podemos usar primero tenemos que manejar el evento de clic sobre los elementos de almacenamiento que están en el grid,en mi caso 2,asi queda el MainActivity:
El menú no lo tocamos,tan solo trabajamos en el onCreate,vamos a definir los .xml que hasta ahora necesitamos:
sdcards.xml
El activity_main.xml:
Solo falta crear el explorador,para ello definiremos una activitad que se extienda de ListActivity y a la cual es la que llamamos cuando le damos clic a una ruta de almacenamiento:
También necesita de un xml llamado explorer.xml:
Por ultimo necesitamos Modificar el Manifiest,necesitamos añadir el Activity de exploración y añadir el permiso de leer la memoria:
También para que funcione necesitamos tener soporte para ActionBarActivity v7,esto es largo de explicar en este tutorial así que pueden pedir ayuda en google.
Y listo asi queda:
Eso es todo :D
Leer más...
Este explorador lo haremos en partes,en este tutorial aprenderemos a crear un explorador minimo,lo suficiente para navegar por directorios y ver archivos,no los podremos abrir ni nada solo ver,pero en otros tutoriales lo mejoraremos.
Bien,si ven el tutorial de como buscar las sd cards o almacenamientos,al final podemos ver una imagen donde se muestran las rutas de los almacenamientos con texto.
http://itimetux.blogspot.mx/2015/02/como-detectar-rutas-de-almacenamiento.html
Justamente partiremos de eso,solo que usaremos diseño grafico,dicen que el diseño grafico hace que la programación se vea agradable y como no soy diseñador grafico vamos a usar iconos de:
iconspedia.com
Estos son los que yo ocupe:
http://www.iconspedia.com/icon/generic-folder-icon-27678.html
http://www.iconspedia.com/icon/file-blank-icon-47723.html
http://www.iconspedia.com/icon/explorer-icon-25475.html
http://www.iconspedia.com/icon/hdd-usb-icon-23267.html
Primero vamos a abrir eclipse y crear un nuevo proyecto android,le vamos a poner de nombre,por ejemplo:
Timeexplorer
Ahora vamos a crear un grid para elegir los posibles almacenamientos,pero para crear un grid necesitamos un Adaptador,pero primero vamos a crear un objeto donde guardar la informacion de cada archivo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | package com.itimetux.timeexplorer; public class Archivo { private String Path; private String Name; private boolean isDir; public Archivo(String Name,String Path,boolean dir){ this.Name = Name; this.Path = Path; this.isDir = dir; } public void setName(String Name) { this.Name = Name; } public void setPath(String Path){ this.Path = Path; } public void setIsDir(boolean dir){ this.isDir = dir; } public String getName() { return this.Name; } public String getPath() { return this.Path; } public boolean isDirectory() { return this.isDir; } } |
Ese archivo no se tiene que explicar mucho solo son getters y setters que es el objeto mínimo para guardar información,uno para el nombre otro para el path y también para ver si es un directorio,este se podría usar desde la clase File pero nos ahorramos usar mas de una llamada.
Bien ahora si el Adapter,lo explico en el codigo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | package com.itimetux.timeexplorer; import java.util.ArrayList; import android.content.Context; import android.graphics.drawable.Drawable; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.ImageView; import android.widget.TextView; public class Adapter extends ArrayAdapter<Archivo> { private Context c; // Contexto private int id; // Id del resource (layout) private ArrayList<Archivo> Archivos; // Todos los archivos public Adapter(Context context, int id, ArrayList<Archivo> archivos) { super(context, id, archivos); c = context; // Definimos las variables globales this.id = id; Archivos = archivos; } public Archivo getArchivo(int i) { return Archivos.get(i); // Esta funcion regresa un Archivo basado en el // index que le pasemos } @Override public View getView(int position, View convertView, ViewGroup parent) { View layout = convertView; if (layout == null) { LayoutInflater Linflated = (LayoutInflater) c .getSystemService(Context.LAYOUT_INFLATER_SERVICE); layout = Linflated.inflate(id, null); // Inflamos la layout } final Archivo file = Archivos.get(position); // Guardamos el archivo // actual en un objeto if (file != null) { // Vemos si no hay un error TextView Name = (TextView) layout.findViewById(R.id.textViewName); // El // nombre TextView Path = (TextView) layout.findViewById(R.id.textViewPath); // El // path // o // ruta /* * Para el nombre y el path vemos si hay un error y si no es asi le * ponemos el texto */ if (Name != null) Name.setText(file.getName()); if (Path != null) Path.setText(file.getPath()); // Vemos si es un directorio if (file.isDirectory()) { ImageView folder = (ImageView) layout .findViewById(R.id.imageViewIcon); Drawable image = c.getResources().getDrawable( R.drawable.generic256); folder.setImageDrawable(image); // Si es asi le ponemos el icono // de directorio } if (!file.isDirectory()) { // Si no es directorio ImageView folder = (ImageView) layout .findViewById(R.id.imageViewIcon); Drawable image = c.getResources().getDrawable( R.drawable.fileblanc256); folder.setImageDrawable(image); // Le ponemos el icono de // archivo } } return layout; } } |
Ese seria un adaptador mínimo para usar un grid,ahora lo podríamos llamar definiendo lo necesario en MainActivity y quedaría así:
Se ve mejor con iconos :D
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | package com.itimetux.timeexplorer; import java.io.File; import java.io.IOException; import java.util.ArrayList; import android.content.Intent; import android.os.Bundle; import android.support.v7.app.ActionBarActivity; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.GridView; public class MainActivity extends ActionBarActivity { private GridView SDS; // Grid private ArrayList<String> SD_CARDS; // Rutas de almacenamiento @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Asignamos el layout principal SDS = (GridView) findViewById(R.id.sdcards); // Definimos el grid SD_CARDS = getAllsds(); // Definimos las rutas de almacenamiento final GridAdapter gadapter = new GridAdapter(this, R.layout.sdcards, SD_CARDS); // Creamos un adaptador SDS.setAdapter(gadapter); // Le asignamos el adaptador al grid SDS.setOnItemClickListener(new OnItemClickListener() { // Manejamos los clic sobre los elementos del grid @Override public void onItemClick(AdapterView<?> a, View v, final int position, long id) { // Vamos a iniciar una nueva actividad pasando como extra la ruta de almacenamiento Intent in = new Intent(MainActivity.this, Explorador.class); in.putExtra("SD", SD_CARDS.get(position)); startActivity(in); // Inicamos la actividad } }); } private ArrayList<String> getAllsds() { ArrayList<String> tmp = new ArrayList<String>(); // Array de todas las rutas String rutas[] = { "/mnt/", "/storage/" }; // Rutas posibles for (int i = 0; i < rutas.length; i++) { File file = new File(rutas[i]);// Ruta actual ( listamos de uno a uno ) if (!file.exists()) // Si no existe pasamos a la siguiente continue; System.out.println("Ruta : " + rutas[i]); // Imprimimos para "depurar" String f[] = file.list(); // Contenido de ruta actual for (int o = 0; o < f.length; o++) { // Recorremos el contenido de la ruta actual if (f[o].indexOf("sd") != -1) { // Vemos si contiene sd en el nombre si es asi es almacenamiento String ruta = rutas[i] + f[o]; // Creamos una Ruta,esta ruta es la original File fd = new File(ruta); // Creamos un nuevo File para evitar rutas repetidas basadas en symlinks String toAdd; try { System.out.println("Canocial :" + fd.getCanonicalPath().toString()); // Esta seria la ruta original toAdd = fd.getCanonicalPath().toString(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); toAdd = null; continue; } if (!tmp.contains(toAdd)) { // Si se repitiera no lo añadimos System.out.println("A añadir :" + toAdd); tmp.add(toAdd); } } } } return tmp; // Regresamos el Array de almacenamientos } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } } |
El menú no lo tocamos,tan solo trabajamos en el onCreate,vamos a definir los .xml que hasta ahora necesitamos:
sdcards.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="200dp" android:layout_height="200dp" android:orientation="horizontal" > <ImageView android:id="@+id/tarjeta" android:layout_width="100dp" android:layout_height="100sp" android:gravity="center" android:src="@drawable/hddusb256" /> <TextView android:id="@+id/nombretarjeta" android:layout_width="match_parent" android:layout_height="wrap_content" android:textColor="#000" android:textStyle="bold" /> </LinearLayout> |
El activity_main.xml:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <RelativeLayout 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" tools:context="com.itimetux.timeexplorer.MainActivity" > <GridView android:id="@+id/sdcards" android:layout_width="fill_parent" android:layout_height="fill_parent" android:gravity="center" android:numColumns="auto_fit" android:stretchMode="columnWidth" > </GridView> </RelativeLayout> |
Solo falta crear el explorador,para ello definiremos una activitad que se extienda de ListActivity y a la cual es la que llamamos cuando le damos clic a una ruta de almacenamiento:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 | package com.itimetux.timeexplorer; import java.io.File; import java.util.ArrayList; import android.app.ListActivity; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.widget.ListView; import android.widget.Toast; public class Explorador extends ListActivity { private Adapter adapter; private File FullDir; private String SDCARD_PATH = ""; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Intent intent = getIntent(); Bundle extras = intent.getExtras(); // Llamamos los extras SDCARD_PATH = extras.getString("SD"); // Llamamos la ruta de // almacenamiento que mandamos // en el main File Directorio = new File(SDCARD_PATH); // Creamos un objeto File con // la ruta de almacenamiento if (Directorio.exists()) { // Primero vemos si existe,por si algo // saliera mal try { // Iniciamos un try,por si algo saliera mal de nuevo startList(Directorio); // Mandamos la ruta inicial a la funcion // que creara la vista } catch (Exception e) { e.printStackTrace(); Toast.makeText( getApplicationContext(), "No puedes acceder en este momento a " + " " + SDCARD_PATH, Toast.LENGTH_LONG).show(); // Sino podemos acceder lo mostramos } } } private void startList(File Directorio) { String titulo = Directorio.getName(); // Obtenemos el nombre de la ruta actual this.setTitle(titulo); // Colocamos el titulo a la vista FullDir = Directorio; // Asignamos esta variable extra que usaremos despues File Allfiles[] = Directorio.listFiles(); // Listamos todos los archivos del directorio actual if (Directorio.listFiles() == null) { // Si es null,esta vacio y lo mostramos Toast.makeText(getApplicationContext(), "Carpeta vacia", Toast.LENGTH_SHORT).show(); return; } // Creamos un Array para los directorios ArrayList<File> Dirs = new ArrayList<File>(); // Creamos un Array para los archivos ArrayList<File> Files = new ArrayList<File>(); //Creamos un array para guardar Archivos y Directorios //Esto servira para ordenarlos ArrayList<File> AllFilesGood = new ArrayList<File>(); // Creamos un Array de Archivos que guardara la informacion de archivos y directorios ArrayList<Archivo> Archivos = new ArrayList<Archivo>(); for (int i = 0; i < Allfiles.length; i++) { // Recorremos la ruta actual // Si es .android_secure no la usamos ya que no nos deja Android if (Allfiles[i].getName().equals(".android_secure")) continue; // Si es un directorio lo ponemos en Dirs if (Allfiles[i].isDirectory()) { Dirs.add(Allfiles[i]); // Si es un Archivo lo ponemos en Files } else if (Allfiles[i].isFile()) { Files.add(Allfiles[i]); } else { // Si no es directorio ni archivo // Continuamos(podemos omitir esta linea de codigo) continue; } } // Podemos poner directorios y luego archivos,o viceversa AllFilesGood.addAll(Dirs); // Ponemos directorios primero AllFilesGood.addAll(Files); // Pondemos Archivos despues // Vemos si es la raiz(la ruta del almacenamiento) if (!Directorio.getAbsolutePath().equals(SDCARD_PATH)) Archivos.add(new Archivo("...", "", true)); // Si no es la raiz agregamos una forma de regresar for (int i = 0; i < AllFilesGood.size(); i++) { // Recorremos Todos los archivos File tmp = AllFilesGood.get(i); // Creamos un objeto que se destruira muy rapidamente boolean flag = false; // Usamos esta variable para ver si es un directorio if (tmp.isDirectory()) // Vemos is es un directorio flag = true; Archivos.add(new Archivo(tmp.getName(), tmp.getPath(), flag)); // Agregamos un nuevo objeto } // Asignamos al adaptador el context,el layout y un array de archivos adapter = new Adapter(Explorador.this, R.layout.explorer, Archivos); this.setListAdapter(adapter); // Asignamos el adaptador } @Override protected void onListItemClick(ListView l, View v, int position, long id) { // Manejamos los clic super.onListItemClick(l, v, position, id); Archivo archivo = adapter.getArchivo(position); // Creamos un archivo temporal if (archivo.isDirectory()) { // Vemos si es directorio if (archivo.getName().equals("...")) { // Si es el regreso regresamos al path anterior // Con estas lineas de codigo obtenemos el path anterior String[] segments = FullDir.getAbsolutePath().split("/"); String lastPath = ""; for (int i = 1; i < segments.length; i++) { if (i != segments.length - 1) { lastPath = lastPath + "/" + segments[i]; } } startList(new File(lastPath)); // Recargamos la vista return; } File Directorio = new File(archivo.getPath()); // Obtenemos el path startList(Directorio); // Recargamos la vista } // Aqui manejariamos los archivos } } |
También necesita de un xml llamado explorer.xml:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" > <ImageView android:id="@+id/imageViewIcon" android:layout_width="50dp" android:layout_height="50dp" android:layout_alignParentLeft="true" android:layout_alignParentTop="true" android:layout_marginTop="10dp" android:maxHeight="5dp" android:maxWidth="5dp" android:src="@drawable/generic256" /> <TextView android:id="@+id/textViewName" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignTop="@+id/imageViewIcon" android:layout_toRightOf="@+id/imageViewIcon" android:lines="1" android:textStyle="bold" /> <TextView android:id="@+id/textViewPath" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignBottom="@+id/imageViewIcon" android:layout_alignLeft="@+id/textViewName" android:lines="1" /> </RelativeLayout> |
Por ultimo necesitamos Modificar el Manifiest,necesitamos añadir el Activity de exploración y añadir el permiso de leer la memoria:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.itimetux.timeexplorer" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="21" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name=".MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".Explorador" android:label="@string/app_name" > </activity> </application> </manifest> |
También para que funcione necesitamos tener soporte para ActionBarActivity v7,esto es largo de explicar en este tutorial así que pueden pedir ayuda en google.
Y listo asi queda: