2010-07-21 19 views
44

Esto comenzó como una pregunta general del usuario en los foros de Android. Sin embargo, se ha convertido, por necesidad, en una pregunta de programación. Aquí está mi problema.¿Cómo puedo actualizar MediaStore en Android?

Android tiene un servicio - MediaScanner - que se ejecuta en segundo plano en cualquier momento (creo) que la tarjeta SD no está montada y montada nuevamente. Este servicio recopila datos en todos los archivos multimedia de la tarjeta y proporciona una base de datos SQLite que las aplicaciones de música pueden consultar. La mayoría de las aplicaciones de música usan este servicio ya que ahorra en el consumo de batería asociado con el escaneo de la tarjeta SD.

Desde que comencé a usar Android, siempre he tenido un problema por el cual las listas de reproducción M3U sincronizadas con el dispositivo permanecen en este DB SQLite incluso después de ser eliminadas de la tarjeta SD. Ha llegado al punto en el que ahora tengo una colección de aproximadamente 40 listas de reproducción en cualquier aplicación de música que utilizo, a pesar de que solo hay alrededor de 10 archivos m3u en la tarjeta. Las listas de reproducción restantes no se reproducen y están vacías. Puedo eliminarlos manualmente eliminándolos de la aplicación de música, pero estoy cansado de hacer esto. Tiene que haber una mejor manera de eliminar estas listas de reproducción fantasmas.

Hay dos aplicaciones en Android Market: SDRescan y Music Scanner, que supuestamente hacen exactamente esto pero ninguna de ellas funciona.

Me puse a escribir mi propia aplicación para actualizar o eliminar la base de datos de MediaStore y comenzar de cero, pero no estoy llegando muy lejos. Tengo una aplicación para Android que se ejecuta el siguiente código:

sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, 
     Uri.parse("file://" + Environment.getExternalStorageDirectory()))); 

que he encontrado algunos ejemplos de este código en línea como una forma de escanear la tarjeta SD, pero no estoy teniendo ninguna suerte con él en absoluto . ¿Algun consejo?

código completo:

package com.roryok.MediaRescan; 

import android.app.Activity; 
import android.content.Intent; 
import android.content.IntentFilter; 
import android.net.Uri; 
import android.os.Bundle; 
import android.os.Environment; 

public class MediaRescan extends Activity { 
    /** Called when the activity is first created. */ 
    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, 
       Uri.parse("file://" + Environment.getExternalStorageDirectory()))); 
     setContentView(R.layout.main); 
    } 

    //Rescan the sdcard after copy the file 
    private void rescanSdcard() throws Exception{  
     Intent scanIntent = new Intent(Intent.ACTION_MEDIA_MOUNTED, 
       Uri.parse("file://" + Environment.getExternalStorageDirectory())); 
     IntentFilter intentFilter = new IntentFilter(Intent.ACTION_MEDIA_SCANNER_STARTED); 
     intentFilter.addDataScheme("file");  
     sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, 
       Uri.parse("file://" + Environment.getExternalStorageDirectory())));  
    } 
} 
+0

Hola, ¿Usted sabe (si sendBroadcast (nueva Intención (Intent.ACTION_MEDIA_MOUNTED, Uri.parse "file: //" + Environment.getExternalStorageDirectory()))); funcionará para sdcard que son tarjetas extra de tragamonedas? en otras palabras getExternalStorageDirectory() devuelve una ruta a sdcard que es interna pero puede haber una tarjeta externa proporcionada por el fabricante? ¿Cómo se puede invocar el escáner de medios para tales tarjetas? – Ahmed

+0

no parece haber una manera de hacer esto en este momento. ver este hilo: http://stackoverflow.com/questions/5453708/android-how-to-use-environment-getexternalstoragedirectory – roryok

Respuesta

18

Ok, lo he hecho.

En lugar de volver a examinar la tarjeta, la aplicación itera a través de todas las listas de reproducción en mediastore y comprueba la longitud del campo _data. Descubrí que para todas las listas sin archivo M3U asociado, este campo siempre estaba vacío. Luego fue solo el caso de encontrar el código fuente para la aplicación de música original de Android, encontrar el método de eliminación y usarlo para eliminar cualquier lista de reproducción con una longitud de 0. He cambiado el nombre de la aplicación PlaylistPurge (ya que no 'vuelve a escanear 'más) y estoy publicando el código a continuación.

que probablemente también publican esto en alguna parte, ya sea en el mercado o en mi propio sitio, http://roryok.com

package com.roryok.PlaylistPurge; 

import java.util.ArrayList; 
import java.util.List; 

import android.app.ListActivity; 
import android.content.ContentUris; 
import android.database.Cursor; 
import android.net.Uri; 
import android.os.Bundle; 
import android.provider.MediaStore; 
import android.widget.ArrayAdapter; 
import android.widget.ListAdapter; 

public class PlaylistPurge extends ListActivity { 

    private List<String> list = new ArrayList<String>(); 
    private final String [] STAR= {"*"}; 

    /** Called when the activity is first created. */ 
    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 

     ListAdapter adapter = createAdapter(); 
     setListAdapter(adapter); 
    } 

    /** 
    * Creates and returns a list adapter for the current list activity 
    * @return 
    */ 
    protected ListAdapter createAdapter() 
    { 
     // return play-lists 
     Uri playlist_uri= MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI;  
     Cursor cursor= managedQuery(playlist_uri, STAR, null,null,null); 
     cursor.moveToFirst(); 
     for(int r= 0; r<cursor.getCount(); r++, cursor.moveToNext()){ 
      int i = cursor.getInt(0); 
      int l = cursor.getString(1).length(); 
      if(l>0){ 
       // keep any playlists with a valid data field, and let me know 
       list.add("Keeping : " + cursor.getString(2) + " : id(" + i + ")"); 
      }else{ 
       // delete any play-lists with a data length of '0' 
       Uri uri = ContentUris.withAppendedId(MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI, i); 
       getContentResolver().delete(uri, null, null); 
       list.add("Deleted : " + cursor.getString(2) + " : id(" + i + ")"); 
      } 
     }  
     cursor.close(); 
     // publish list of retained/deleted playlists 
     ListAdapter adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, list); 

     return adapter; 
    } 
} 

ACTUALIZACIÓN:

Aquí hay un enlace a un post en mi blog sobre la aplicación http://roryok.com/blog/index.php/2010/07/23/clearing-out-deleted-playlists-in-android/

ACTUALIZACIÓN 2: Martes, 9 de abril de, 2013

he conseguido una gran cantidad de tráfico a mi blog desde este puesto, y una gran cantidad de correos electrónicos de personas que me lo agradecen. Me alegro de que ayudó! ¡Cualquier usuario potencial debería saber que mi aplicación de mierda actualmente se cuelga tan pronto como la ejecutas, pero en realidad hace lo que se supone que debe hacer! Siempre he tenido la intención de volver atrás y corregir este comportamiento estrepitoso y ponerlo en el mercado, con suerte 2013 será el año en que lo haga.

+0

¿Esto eliminará las listas de reproducción que no se han eliminado pero que tampoco tienen canciones? –

+0

Hola vinay. No, solo eliminará las entradas de las listas de reproducción que se hayan eliminado. Las listas de reproducción con 0 entradas no se verán afectadas – roryok

+0

¡Gracias! Buena solución –

10

Puede solicitar un re-escaneo de archivos específicos usando el siguiente código.

NOTA: El TIPO MIME pasado es importante. Me di cuenta de los cambios realizados en las etiquetas ID3 de MP3 no se renueve correctamente en el SQLite si utilicé "*/*", sin embargo el uso de "audio/mp3" trabajé

MediaScannerConnection.scanFile(
    context, 
    new String[]{ pathToFile1, pathToFile2 }, 
    new String[]{ "audio/mp3", "*/*" }, 
    new MediaScannerConnectionClient() 
    { 
     public void onMediaScannerConnected() 
     { 
     } 
     public void onScanCompleted(String path, Uri uri) 
     { 
     } 
    }); 
+1

Realmente no tiene que pasar el tipo de mimo en absoluto. Si el archivo se llama correctamente (* .mp3, * .m4a, etc.), el escáner determinará el tipo de mime de la extensión. Por lo tanto, en lugar de nuevos String [] {** tipos de mime **}, solo pase null. – Baron

+0

Esto funcionó para detectar la eliminación de archivos eliminados y movidos. En mi caso me estoy comunicando a través de MTP (Protocolo de transferencia de medios) y sin volver a escanear los archivos todavía aparecen allí hasta reiniciar, etc. – egfconnor

+0

por lo que yo sé, esto no afectará _playlists_ que hacen referencia a los medios eliminados, solo el referencias de biblioteca – roryok

42

Aquí es una 'solución basada en fila de a uno' fácil :

Cada vez que se agrega un archivo, deja MediaStore Proveedor de contenido sabe sobre él usando

sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(imageAdded))); 

Para eliminación:. sólo tiene que utilizar getContentResolver() borrar (URI , Null, null) (El crédito va a DDSports)

+0

, presumiblemente, eso es una solución al problema de los archivos huérfanos que aparecen en primer lugar. Mi aplicación era para limpiar el lío dejado por _otras aplicaciones que NO hacen esto – roryok

+1

. Le di un voto positivo porque si bien no resuelve el problema exacto mencionado, es una información muy valiosa que creo que es relevante. – Matt

+2

Esto realmente solo funciona cuando se agrega un archivo. No funciona cuando se va a eliminar un archivo. Necesita getContentResolver(). Delete (uri, null, null); método para eso. – DDSports

Cuestiones relacionadas