2010-07-21 7 views
44

Cela a commencé comme une question d'utilisateur générale sur les forums Android. Cependant, il est devenu, par nécessité, une question de programmation. Voici mon problème.Comment puis-je actualiser MediaStore sur Android?

Android a un service - MediaScanner - qui fonctionne en arrière-plan à tout moment (je crois) la carte SD est non monté et re-monté. Ce service collecte des données sur tous les fichiers multimédias de la carte et fournit une base de données SQLite qui peut être interrogée par les applications musicales. La plupart des applications musicales utilisent ce service, car il permet d'économiser la batterie lors de la numérisation de la carte SD.

Depuis que j'ai commencé à utiliser Android, j'ai toujours eu un problème avec les listes de lecture M3U synchronisées avec l'appareil qui restent dans cette base de données SQLite même après avoir été supprimées de la carte SD. C'est arrivé au point où j'ai maintenant une collection d'environ 40 playlists apparaissant dans n'importe quelle application musicale que j'utilise, bien qu'il y ait seulement environ 10 fichiers m3u sur la carte. Les listes de lecture restantes ne sont pas lues et sont vides. Je peux les supprimer manuellement en les supprimant de l'application musicale, mais j'en ai marre de le faire. Il doit y avoir une meilleure façon de supprimer ces playlists fantômes.

Il existe deux applications sur l'Android Market - SDRescan et Music Scanner, qui font exactement cela, mais aucun d'entre eux ne fonctionne.

J'ai commencé à écrire ma propre application pour actualiser ou supprimer la base de données MediaStore et recommencer à zéro, mais je ne vais pas très loin. J'ai une application Android qui exécute le code suivant:

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

J'ai trouvé quelques exemples de ce code en ligne comme un moyen de scanner la carte SD mais je ne suis pas avoir de chance avec ce que ce soit . Des conseils?

CODE COMPLET:

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

Salut, Savez-vous si sendBroadcast (nouvelle intention (Intent.ACTION_MEDIA_MOUNTED, Uri.parse ("file: //" + Environment.getExternalStorageDirectory()))); travaillera pour sdcard qui sont des cartes supplémentaires? en d'autres termes, getExternalStorageDirectory() renvoie un chemin vers la carte SD interne, mais il peut y avoir une carte externe fournie par le fabricant? Comment peut-on appeler un scanner de médias pour de telles cartes? – Ahmed

+0

il ne semble pas être un moyen de le faire pour le moment. voir ce fil: http://stackoverflow.com/questions/5453708/android-how-to-use-environment-getexternalstoragedirectory – roryok

Répondre

18

Ok, je l'ai fait.

Plutôt que de rescanner la carte, l'application parcourt toutes les listes de lecture de mediastore et vérifie la longueur du champ _data. J'ai découvert que pour toutes les listes sans fichier M3U associé, ce champ était toujours vide. Ensuite, il était juste un cas de trouver le code source de l'application originale de musique Android, trouver la méthode de suppression et l'utiliser pour supprimer toutes les playlists avec une longueur de 0. J'ai renommé l'application PlaylistPurge (car il ne «rescan» 'plus) et je poste le code ci-dessous.

Je vais probablement publier aussi cela quelque part, que ce soit sur le marché ou sur mon propre site, 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; 
    } 
} 

MISE À JOUR:

Voici un lien vers un post sur mon blog à propos de l'application http://roryok.com/blog/index.php/2010/07/23/clearing-out-deleted-playlists-in-android/

MISE à JOUR 2 mardi 9 Avril, 2013

J'ai eu beaucoup de trafic sur mon blog à partir de ce poste, et un grand nombre de courriels de personnes me remerciant pour cela. Heureux que ça a aidé! Tous les utilisateurs potentiels devraient savoir que mon application merdique se bloque actuellement dès que vous l'exécutez, mais fait ce qu'il est censé faire! J'ai toujours eu l'intention de revenir en arrière et de réparer ce comportement fracassant et de le mettre sur le marché, j'espère que 2013 sera l'année où je le ferai.

+0

Est-ce que cela va supprimer les playlists qui n'ont pas été supprimées mais n'ont pas de chansons aussi? –

+0

Bonjour vinay. Non, il ne supprimera que les entrées des listes de lecture qui ont été supprimées. Les playlists avec 0 entrées ne seront pas affectées – roryok

+0

Merci! Bonne solution –

10

Vous pouvez demander une nouvelle analyse de fichiers spécifiques à l'aide du code suivant.

REMARQUE: Le type MIME transmis est important. J'ai remarqué les modifications apportées aux balises ID3 MP3 ne se régénère pas correctement dans le SQLite si je « */* », mais en utilisant « audio/mp3 » travaillé

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

Vous n'avez vraiment pas à passer le type mime du tout. Si le fichier est correctement nommé (* .mp3, * .m4a, etc.), le scanner déterminera le type mime de l'extension. Ainsi, au lieu de new String [] {** mime types **}, passez simplement null. – Baron

+0

Cela a fonctionné pour moi de détecter la suppression des fichiers supprimés et déplacés. Pour mon cas, je communique sur MTP (Media Transfer Protocol) et sans scanner les fichiers, ils semblent toujours être là jusqu'à ce que le redémarrage, etc – egfconnor

+0

autant que je sais que cela n'affectera toujours pas _playlists_ qui référence médias supprimés, seul le Références de la bibliothèque – roryok

42

Voici une «solution à base de fichier unique facile :

Chaque fois que vous ajoutez un fichier, laissez MediaStore fournisseur de contenu est au courant en utilisant

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

Pour suppression:. il suffit d'utiliser getContentResolver() supprimer (uri , Null, null) (crédit va à DDSports)

+0

est probablement censé être une solution au problème des fichiers orphelins qui apparaissent en premier lieu. Mon application était de nettoyer le désordre laissé par _autres_ applications qui ne le font PAS – roryok

+1

J'ai donné un upvote parce que, même si cela ne résout pas le problème exact mentionné, c'est une information très précieuse que je pense est pertinent. – Matt

+2

Cela ne fonctionne réellement que lors de l'ajout d'un fichier. Cela ne fonctionne pas lorsqu'un fichier doit être supprimé. Vous avez besoin de getContentResolver(). Delete (uri, null, null); méthode pour cela. – DDSports

Questions connexes