Сканирование Android SD-карты на наличие новых файлов - PullRequest
11 голосов
/ 21 января 2011

Мое приложение позволяет пользователю сохранить изображение на свою SD-карту.Но я не уверен, как заставить его появляться в галерее, пока вы не размонтируете и не перемонтируете SD-карту.Я несколько дней гуглял с этой проблемой, но не уверен, как заставить ее появиться автоматически.Я нашел эту ссылку, но я не уверен, как использовать класс.Это то, что я использую, чтобы сохранить файл.В нижней части блока try catch я хочу отсканировать SD-карту на наличие новых носителей.

    FileOutputStream outStream = null;
    File file = new File(dirPath, fileName);
    try {
        outStream = new FileOutputStream(file);
        bm.compress(Bitmap.CompressFormat.JPEG, 100, outStream);
        outStream.flush();
        outStream.close();
    } catch {
         ...
    }

Если бы кто-нибудь мог указать мне правильное направление, я был бы признателен.

Ответы [ 6 ]

9 голосов
/ 15 апреля 2014

Я пробовал множество различных методов для запуска MediaScanner, и это мои результаты.

SendBroadcast

Самое простое и наивное решение.Он состоит в выполнении следующей инструкции из вашего кода:

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

Однако этот больше не работает на устройствах KitKat из-за отсутствия необходимых разрешений.


MediaScannerWrapper

Как опубликовано здесь (за ответ @ Брайана), он заключается в переносе экземпляра MediaScannerConnection для запуска метода scan()по конкретному каталогу.Этот метод хорошо себя зарекомендовал для 4.3 и ниже, но все же не повезло с KitKat (4.4 +).


FileWalker

Один из многихПриложения Play Store, которые пытаются преодолеть отсутствие обязательств MediaStore по обновлению своей базы данных: ReScan SD .Он отправляет множество разных широковещательных сообщений:

  sendBroadcast(new Intent("android.intent.action.MEDIA_MOUNTED", Uri.parse("file://" + Environment.getExternalStorageDirectory())));
  sendBroadcast(new Intent("android.intent.action.MEDIA_MOUNTED", Uri.parse("file:///Removable")));
  sendBroadcast(new Intent("android.intent.action.MEDIA_MOUNTED", Uri.parse("file:///Removable/SD")));
  sendBroadcast(new Intent("android.intent.action.MEDIA_MOUNTED", Uri.parse("file:///Removable/MicroSD")));
  sendBroadcast(new Intent("android.intent.action.MEDIA_MOUNTED", Uri.parse("file:///mnt/Removable/MicroSD")));
  sendBroadcast(new Intent("android.intent.action.MEDIA_MOUNTED", Uri.parse("file:///mnt")));
  sendBroadcast(new Intent("android.intent.action.MEDIA_MOUNTED", Uri.parse("file:///storage")));
  sendBroadcast(new Intent("android.intent.action.MEDIA_MOUNTED", Uri.parse("file:///Removable")));

и пытается поддерживать KitKat, вручную вызывая метод scan() для каждого файла базового каталога.К сожалению, это очень сильно загружает процессор и отнимает много времени, поэтому не очень рекомендуется.


"Способ оболочки"

ЕдинственноеПохоже, что в некоторых случаях он работает с KitKat - отправляет трансляцию через adb shell.Итак, этот фрагмент кода позволяет вам делать это программно:

Runtime.getRuntime().exec("am broadcast -a android.intent.action.MEDIA_MOUNTED -d file://" + Environment.getExternalStorageDirectory());

Это скорее хакерский способ сделать это, но на данный момент это лучшее, что я мог придумать.


Итог

Каждое из вышеперечисленных решений действительно работает для всего, что не является KitKat.Это связано с тем, что благодаря Джастину была обнаружена ошибка, выданная официальному трекеру .Это означает, что до тех пор, пока ошибка не будет устранена, у нас не останется настоящей поддержки KitKat.

Какой использовать?Среди них я бы использовал решение MediaScannerWrapper вместе с подходом shell-ish (последним).

5 голосов
/ 25 января 2011

Поскольку последний ответ, который я разместил, по-видимому, был неподходящим методом, я нашел другой метод здесь Вы в основном создаете класс-оболочку, инициализируете его, а затем вызываете метод scan ().Очень полезный пост.Дайте мне знать, если это не подходит.

3 голосов
/ 21 января 2011

Использовать MediaScannerConnection:

http://developer.android.com/reference/android/media/MediaScannerConnection.html

Это может быть немного болезненно из-за нескольких уровней асинхронных вызовов, поэтому в API 8 (Froyo) есть вспомогательная функция:

http://developer.android.com/reference/android/media/MediaScannerConnection.html#scanFile(android.content.Context, java.lang.String [], java.lang.String [], android.media.MediaScannerConnection.OnScanCompletedListener)

2 голосов
/ 20 августа 2013

Вы также можете явно вызвать медиа-сканер, отправив широковещательную рассылку.

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

Редактировать

Это был старый пост.Обновление до новых версий

Android предпринимает шаги для предотвращения подмены приложений большим количеством системных трансляций, подобных этой.

Если вы хотите указать Android индексировать файл, который вы поместили на внешнее хранилище, либо используйте MediaScannerConnection или ACTION_MEDIA_SCANNER_SCAN_FILE

Ссылка: Этот пост

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
    final Intent scanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
    final Uri contentUri = Uri.fromFile(outputFile); 
    scanIntent.setData(contentUri);
    sendBroadcast(scanIntent);
} else {
    final Intent intent = new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://" + Environment.getExternalStorageDirectory()));
    sendBroadcast(intent);
}

Если вышеуказанный фрагмент кода не работает, вы можете попробовать следующее:

MediaScannerConnection.scanFile(this, new String[] {
    file.getAbsolutePath()
}, null, new MediaScannerConnection.OnScanCompletedListener() {

    @Override
    public void onScanCompleted(String path, Uri uri) {


    }
});
0 голосов
/ 25 февраля 2014

Здесь - еще один способ принудительного сканирования:

context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE,"uri to file"));

И тогда система запустит трансляцию ACTION_MEDIA_SCANNER_FINISHED, чтобы вы могли реагировать на нее с BroadcastReceiver

Чтобы иметь возможность получать трансляцию ACTION_MEDIA_SCANNER_FINISHED, фильтр намерений должен содержать схему данных:

IntentFilter intentFilter = new IntentFilter(Intent.ACTION_MEDIA_SCANNER_FINISHED);
intentFilter.addDataScheme("file");
context.registerReceiver(mMediaScannerFinishReceiver, intentFilter);

из документа:

общедоступная статическая конечная строка ACTION_MEDIA_SCANNER_SCAN_FILE

Добавлено в API Уровень 1 Broadcast Action: Запросить сканер мультимедиа на отсканируйте файл и добавьте его в базу данных мультимедиа. Путь к файлу содержится в поле Intent.mData.

и

общедоступная статическая конечная строка ACTION_MEDIA_SCANNER_FINISHED

Добавлено в API уровень 1 Broadcast Action: Сканер мультимедиа завершен сканирование каталога. Путь к проверенному каталогу содержится в поле Intent.mData.

0 голосов
/ 21 января 2011

Вы можете использовать MediaStore.Images.Media.insertImage, чтобы вставить элемент в галерею.

...