Maison  >  Article  >  Java  >  Explication détaillée de l'analyse des fichiers multimédias sous Android

Explication détaillée de l'analyse des fichiers multimédias sous Android

高洛峰
高洛峰original
2017-01-16 17:26:201631parcourir

Cet article analyse le code source du système et explique comment ajouter des fichiers multimédias créés par le programme à la médiathèque du système, comment les supprimer de la médiathèque et les problèmes que la plupart des développeurs de programmes rencontrent souvent, comme l'impossibilité de le faire. pour les ajouter à la médiathèque. J'expliquerai ces problèmes un par un à travers l'analyse du code source.

Mécanisme d'analyse des fichiers multimédias dans Android

Android fournit un excellent programme pour gérer l'ajout de fichiers multimédias à la bibliothèque multimédia. Ce programme est MediaProvider. Examinons maintenant brièvement le programme suivant. Tout d'abord, jetez un œil à son récepteur

    <receiver android:name="MediaScannerReceiver">
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED" />
        </intent-filter>
        <intent-filter>
            <action android:name="android.intent.action.MEDIA_MOUNTED" />
            <data android:scheme="file" />
        </intent-filter>
        <intent-filter>
            <action android:name="android.intent.action.MEDIA_UNMOUNTED" />
            <data android:scheme="file" />
        </intent-filter>
        <intent-filter>
            <action android:name="android.intent.action.MEDIA_SCANNER_SCAN_FILE" />
            <data android:scheme="file" />
        </intent-filter>
    </receiver>

MediaScannerReceiver ne reçoit que l'intention correcte qui est conforme aux règles d'action et de données.

Comment MediaScannerReciever gère l'intention

1. Analyser le stockage interne (carte SD non intégrée et externe) si et seulement si l'action android.intent.action.BOOT_COMPLETED est reçue
2. Sauf que les intentions autres que android.intent.action.BOOT_COMPLETED doivent avoir des données transmises.
3. Lors de la réception de l'intention Intent.ACTION_MEDIA_MOUNTED, analysez la carte SD.
4. Lors de la réception de l'intention Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, il n'y a aucun problème de détection et un seul fichier sera analysé.

Comment fonctionne MediaScannerService

En fait, MediaScannerReceiver ne gère pas vraiment le travail d'analyse, il démarre un service appelé MediaScannerService. Continuons à examiner la partie service du manifeste de MediaProvider.

 <service android:name="MediaScannerService" android:exported="true">
        <intent-filter>
            <action android:name="android.media.IMediaScannerService" />
        </intent-filter>
    </service>

méthode scanFile dans MediaScannerService

private Uri scanFile(String path, String mimeType) {
    String volumeName = MediaProvider.EXTERNAL_VOLUME;
    openDatabase(volumeName);
    MediaScanner scanner = createMediaScanner();
    return scanner.scanSingleFile(path, volumeName, mimeType);
}

méthode scan dans MediaScannerService

private void scan(String[] directories, String volumeName) {
    // don&#39;t sleep while scanning
    mWakeLock.acquire();
    ContentValues values = new ContentValues();
    values.put(MediaStore.MEDIA_SCANNER_VOLUME, volumeName);
    Uri scanUri = getContentResolver().insert(MediaStore.getMediaScannerUri(), values);
    Uri uri = Uri.parse("file://" + directories[0]);
    sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_STARTED, uri));
    try {
        if (volumeName.equals(MediaProvider.EXTERNAL_VOLUME)) {
            openDatabase(volumeName);
        }
        MediaScanner scanner = createMediaScanner();
        scanner.scanDirectories(directories, volumeName);
    } catch (Exception e) {
        Log.e(TAG, "exception in MediaScanner.scan()", e);
    }
    getContentResolver().delete(scanUri, null, null);
    sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_FINISHED, uri));
    mWakeLock.release();
}

méthode createMediaScanner dans MediaScannerService

private MediaScanner createMediaScanner() {
        MediaScanner scanner = new MediaScanner(this);
        Locale locale = getResources().getConfiguration().locale;
        if (locale != null) {
            String language = locale.getLanguage();
            String country = locale.getCountry();
            String localeString = null;
            if (language != null) {
                if (country != null) {
                    scanner.setLocale(language + "_" + country);
                } else {
                    scanner.setLocale(language);
                }
            }
        }
        return scanner;
}

Comment analyser un fichier nouvellement créé

Voici deux façons d'ajouter des fichiers nouvellement créés à la médiathèque.

Le moyen le plus simple

Envoyez simplement une diffusion d'intention correcte au MediaScannerReceiver.

String saveAs = "Your_Created_File_Path"
Uri contentUri = Uri.fromFile(new File(saveAs));
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE,contentUri);
getContext().sendBroadcast(mediaScanIntent);

La méthode minimaliste ci-dessus fonctionne normalement dans la plupart des cas, mais elle ne fonctionnera pas dans certains cas, qui seront présentés dans une section ultérieure. Même si vous réussissez à utiliser la méthode ci-dessus, il est recommandé de continuer à lire la section suivante expliquant pourquoi la diffusion échoue.

Utiliser MediaScannerConnection

public void mediaScan(File file) {
    MediaScannerConnection.scanFile(getActivity(),
            new String[] { file.getAbsolutePath() }, null,
            new OnScanCompletedListener() {
                @Override
                public void onScanCompleted(String path, Uri uri) {
                    Log.v("MediaScanWork", "file " + path
                            + " was scanned seccessfully: " + uri);
                }
            });
}

La méthode scanFile de MediaScannerConnection a été introduite à partir de la version 2.2 (API 8).

Créez un objet MediaScannerConnection puis appelez la méthode scanFile

C'est très simple, référez-vous à http://developer.android.com/reference/android/media/MediaScannerConnection.html

Comment analyser plusieurs fichiers

1. Envoyez plusieurs diffusions Intent.ACTION_MEDIA_SCANNER_SCAN_FILE
2. Utilisez MediaScannerConnection et transmettez le tableau de chemins à ajouter.

Pourquoi l'envoi de la diffusion MEDIA_SCANNER_SCAN_FILE ne prend pas effet

Quant à la raison pour laquelle cela ne prend pas effet sur certains appareils, beaucoup de gens pensent que cela est dû à l'API. En fait, ce n'est pas le cas. est en fait lié au chemin du fichier que vous avez transmis. Jetez un œil au code onReceive du récepteur.

public void onReceive(Context context, Intent intent) {
    String action = intent.getAction();
    Uri uri = intent.getData();
    if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
        // scan internal storage
        scan(context, MediaProvider.INTERNAL_VOLUME);
    } else {
        if (uri.getScheme().equals("file")) {
            // handle intents related to external storage
            String path = uri.getPath();
            String externalStoragePath = Environment.getExternalStorageDirectory().getPath();
            Log.d(TAG, "action: " + action + " path: " + path);
            if (action.equals(Intent.ACTION_MEDIA_MOUNTED)) {
                // scan whenever any volume is mounted
                scan(context, MediaProvider.EXTERNAL_VOLUME);
            } else if (action.equals(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE) &&
                    path != null && path.startsWith(externalStoragePath + "/")) {
                scanFile(context, path);
            }
        }
    }
}

Tout est correct sauf le chemin entrant. Parce que vous avez peut-être codé en dur le chemin du fichier. Parce qu'il existe un tel jugement path.startsWith(externalStoragePath "/"), je vais donner ici un exemple simple.

final String saveAs = "/sdcard/" + System.currentTimeMillis() + "_add.png";
Uri contentUri = Uri.fromFile(new File(saveAs));
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE,contentUri);
getContext().sendBroadcast(mediaScanIntent);
Uri uri = mediaScanIntent.getData();
String path = uri.getPath();
String externalStoragePath = Environment.getExternalStorageDirectory().getPath();
Log.i("LOGTAG", "Androidyue onReceive intent= " + mediaScanIntent
                        + ";path=" + path + ";externalStoragePath=" +
                        externalStoragePath);

Jetons un coup d'œil au journal de sortie et analysons la raison.

LOGTAG Androidyue onReceive intent= Intent { act=android.intent.action.MEDIA_SCANNER_SCAN_FILE dat=file:///sdcard/1390136305831_add.png };path=/sdcard/1390136305831_add.png;externalStoragePath=/mnt/sdcard

L'analyse de sortie ci-dessus montre que la diffusion et l'action que vous avez envoyées sont correctes, que les règles de données sont également correctes et que votre chemin de fichier existe également. Cependant, le chemin de fichier /sdcard/1390136305831_add.png existe. n'existe pas. Ne démarre pas par le chemin racine du stockage externe /mnt/sdcard/. Par conséquent, l’opération d’analyse n’a pas démarré, ce qui a entraîné la non-ajout du fichier à la bibliothèque multimédia. Veuillez donc vérifier le chemin du fichier.

Comment supprimer de la médiathèque

Si nous supprimons un fichier multimédia, cela signifie que nous devons également supprimer le fichier de la médiathèque.

Pouvez-vous simplement envoyer une diffusion ?

Le simple fait d'envoyer une diffusion peut-il résoudre le problème ? J'aimerais que cela soit possible, mais cela ne fonctionne pas réellement. Vous pouvez le voir en regardant le code suivant.

// this function is used to scan a single file
public Uri scanSingleFile(String path, String volumeName, String mimeType) {
    try {
        initialize(volumeName);
        prescan(path, true);
        File file = new File(path);
        if (!file.exists()) {
            return null;
        }
        // lastModified is in milliseconds on Files.
        long lastModifiedSeconds = file.lastModified() / 1000;
        // always scan the file, so we can return the content://media Uri for existing files
        return mClient.doScanFile(path, mimeType, lastModifiedSeconds, file.length(),
                false, true, MediaScanner.isNoMediaPath(path));
    } catch (RemoteException e) {
        Log.e(TAG, "RemoteException in MediaScanner.scanFile()", e);
        return null;
    }
}

Tout comme le code ci-dessus, il vérifiera si le fichier existe. Si le fichier n'existe pas, l'exécution vers le bas sera directement arrêtée. Donc ça ne marchera pas. Ce qu'il faut faire?

public void testDeleteFile() {
    String existingFilePath = "/mnt/sdcard/1390116362913_add.png";
    File  existingFile = new File(existingFilePath);
    existingFile.delete();
    ContentResolver resolver = getActivity().getContentResolver();
    resolver.delete(Images.Media.EXTERNAL_CONTENT_URI, Images.Media.DATA + "=?", new String[]{existingFilePath});
    
    }

Le code ci-dessus peut fonctionner, il suffit de le supprimer directement du MediaProvider. Pour les codes de suppression spécifiques, veuillez vous référer à l'extrait de code pour les médias sur Android

One More Thing

Pour des explications plus détaillées sur les opérations d'analyse de fichiers multimédia sous Android, veuillez faire attention au site Web PHP chinois pour articles connexes!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn