Cela a commencé comme une question générale des utilisateurs sur les forums Android. Cependant, c'est devenu, par nécessité, une question de programmation. Voici mon problème.
Android a un service - MediaScanner - qui s'exécute en arrière-plan à chaque fois (je crois) que la carte SD est démontée et remontée. 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 associée à la numérisation de la carte SD.
Depuis que j'ai commencé à utiliser Android, j'ai toujours eu un problème où les listes de lecture M3U synchronisées avec l'appareil 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 listes de lecture qui apparaissent dans n'importe quelle application musicale que j'utilise, bien qu'il n'y ait que 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 un meilleur moyen de supprimer ces listes de lecture fantômes.
Il existe deux applications sur le Android Market - SDRescan et Music Scanner, qui supposément font exactement cela, mais aucune ne fonctionne.
J'ai décidé d'é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 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 moyen de numériser la carte SD, mais je n'ai aucune chance avec elle. 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())));
}
}
Ok, je l'ai fait.
Plutôt que de réanalyser la carte, l'application parcourt toutes les listes de lecture dans 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 s'agissait juste de trouver le code source de l'application musicale Android musique d'origine, de trouver la méthode de suppression et de l'utiliser pour supprimer toutes les listes de lecture d'une longueur de 0. J'ai renommé l'application PlaylistPurge (car il ne "réanalyse" plus) et je publie le code ci-dessous.
Je publierai probablement cela aussi quelque part, 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 article sur mon blog sur 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 reçu beaucoup de trafic sur mon blog à partir de ce message, et un grand nombre d'e-mails de personnes me remerciant pour cela. Heureux que cela ait aidé! Tous les utilisateurs potentiels doivent savoir que mon application merdique se bloque actuellement dès que vous l'exécutez, mais fait ce qu'elle est censée faire! J'ai toujours eu l'intention de revenir en arrière et de corriger ce comportement de plantage et de le mettre sur le marché, j'espère que 2013 sera l'année où je le ferai.
Voici une "solution basée sur un seul fichier":
Chaque fois que vous ajoutez un fichier, laissez MediaStore Content Provider le savoir en utilisant
sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(imageAdded)));
Pour suppression : utilisez simplement getContentResolver (). Delete (uri, null, null) (Le crédit revient à DDSports )
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é que les modifications apportées aux balises MP3 ID3 ne s'actualisaient pas correctement dans SQLite si j'utilisais "*/*", mais que l'utilisation de "audio/mp3" fonctionnait
MediaScannerConnection.scanFile(
context,
new String[]{ pathToFile1, pathToFile2 },
new String[]{ "audio/mp3", "*/*" },
new MediaScannerConnectionClient()
{
public void onMediaScannerConnected()
{
}
public void onScanCompleted(String path, Uri uri)
{
}
});