> Java > java지도 시간 > Android에서 멀티미디어 파일을 검색하는 방법에 대한 자세한 설명

Android에서 멀티미디어 파일을 검색하는 방법에 대한 자세한 설명

高洛峰
풀어 주다: 2017-01-16 17:26:20
원래의
1653명이 탐색했습니다.

이 기사에서는 시스템 소스 코드를 분석하여 프로그램에서 생성된 멀티미디어 파일을 시스템의 미디어 라이브러리에 추가하는 방법과 이를 미디어 라이브러리에서 삭제하는 방법, 그리고 프로그램이 실행되지 않는 등 대부분의 프로그램 개발자가 자주 직면하는 문제에 대해 설명합니다. 미디어 라이브러리에 추가합니다. 이러한 문제에 대해서는 소스코드 분석을 통해 하나씩 설명하겠습니다.

Android의 멀티미디어 파일 검색 메커니즘

Android는 미디어 라이브러리에 멀티미디어 파일 추가를 처리하는 훌륭한 프로그램을 제공합니다. 이 프로그램은 MediaProvider 입니다. 이제 다음 프로그램을 간단히 살펴보겠습니다. 먼저 Receiver를 살펴보세요

    <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는 액션 및 데이터 규칙을 준수하는 올바른 인텐트만 수신합니다.

MediaScannerReciever가 인텐트를 처리하는 방법

1. android.intent.action.BOOT_COMPLETED 작업이 수신되는 경우에만 내부 저장소(내장 및 외부 sdcard)를 검색합니다.
2. android.intent.action.BOOT_COMPLETED 이외의 인텐트에는 데이터가 전달되어야 합니다.
3. Intent.ACTION_MEDIA_MOUNTED 인텐트를 수신하면 Sdcard를 스캔합니다.
4. Intent.ACTION_MEDIA_SCANNER_SCAN_FILE 인텐트를 수신하면 감지에 문제가 없으며 단일 파일이 스캔됩니다.

MediaScannerService 작동 방식

사실 MediaScannerReceiver는 스캔 작업을 실제로 처리하지 않고 MediaScannerService라는 서비스를 시작합니다. MediaProvider 매니페스트의 서비스 부분을 계속 살펴보겠습니다.

 <service android:name="MediaScannerService" android:exported="true">
        <intent-filter>
            <action android:name="android.media.IMediaScannerService" />
        </intent-filter>
    </service>
로그인 후 복사

MediaScannerService의 scanFile 메소드

private Uri scanFile(String path, String mimeType) {
    String volumeName = MediaProvider.EXTERNAL_VOLUME;
    openDatabase(volumeName);
    MediaScanner scanner = createMediaScanner();
    return scanner.scanSingleFile(path, volumeName, mimeType);
}
로그인 후 복사

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();
}
로그인 후 복사

MediaScannerService의 createMediaScanner 메소드

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;
}
로그인 후 복사

새로 생성된 파일을 스캔하는 방법

새로 생성된 파일을 미디어 라이브러리에 추가하는 방법에는 두 가지가 있습니다.

가장 간단한 방법

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);
로그인 후 복사

위의 미니멀리스트 방식은 대부분의 경우 정상적으로 작동하지만 작동하지 않는 경우도 있는데 이에 대해서는 이후 섹션에서 소개하겠습니다. 위 방법으로 성공하더라도 나중에 방송이 실패하는 이유를 계속해서 읽어보는 것이 좋습니다.

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);
                }
            });
}
로그인 후 복사

MediaScannerConnection의 scanFile 메소드는 2.2(API 8)부터 도입되었습니다.

MediaScannerConnection 객체를 생성한 후 scanFile 메소드를 호출하세요.

매우 간단합니다. http://developer.android.com/reference/android/media/MediaScannerConnection.html을 참조하세요

여러 파일을 스캔하는 방법

1. 여러 Intent.ACTION_MEDIA_SCANNER_SCAN_FILE 브로드캐스트를 보냅니다.
2. MediaScannerConnection을 사용하여 추가할 경로 배열을 전달합니다.

MEDIA_SCANNER_SCAN_FILE 브로드캐스트 전송이 적용되지 않는 이유

일부 기기에서는 적용되지 않는 이유에 대해 많은 사람들이 API 때문이라고 생각합니다. 실제로는 그렇지 않습니다. 실제로 전달한 파일 경로와 관련이 있습니다. 수신기 Receiver의 onReceive 코드를 살펴보세요.

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);
            }
        }
    }
}
로그인 후 복사

들어오는 경로를 제외하고 모든 것이 정확합니다. 파일 경로를 하드코딩했을 수 있기 때문입니다. 이런 판단이 있기 때문에 path.startsWith(externalStoragePath + "/") 여기서는 간단한 예를 들어보겠습니다.

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);
로그인 후 복사

출력 로그를 보고 이유를 분석해 보겠습니다.

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
로그인 후 복사

위 출력 분석을 보면 전송한 브로드캐스트와 액션이 정확하고 데이터 규칙도 정확하며 파일 경로도 존재하는 것으로 나타났습니다. 그러나 파일 경로 /sdcard/1390136305831_add.png가 다음으로 시작하지 않습니다. 외부 저장소 루트 경로는 /mnt/sdcard/로 시작됩니다. 따라서 스캔 작업이 시작되지 않아 파일이 미디어 라이브러리에 추가되지 않았습니다. 그러니 파일 경로를 꼭 확인해주세요.

멀티미디어 라이브러리에서 제거하는 방법

멀티미디어 파일을 삭제하면 미디어 라이브러리에서도 파일을 삭제해야 함을 의미합니다.

방송만 보내주실 수 있나요?

방송만 보내면 문제가 해결되나요? 그랬으면 좋겠지만 실제로는 작동하지 않습니다. 다음 코드를 보면 알 수 있습니다.

// 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;
    }
}
로그인 후 복사

위 코드와 마찬가지로 파일이 존재하는지 확인합니다. 파일이 존재하지 않으면 하향 실행이 바로 중지됩니다. 그래서 이것은 작동하지 않습니다. 무엇을 해야 할까요?

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});
    
    }
로그인 후 복사

위 코드는 작동할 수 있습니다. MediaProvider에서 직접 삭제하면 됩니다. 특정 삭제 코드에 대해서는 Android 미디어용 코드 조각

한 가지 더

Android의 멀티미디어 파일 검색 작업에 대한 자세한 설명을 보려면 PHP 중국어 웹사이트를 참고하세요. 관련 기사!

관련 라벨:
원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿