Сканирование SD-карты Android для новых файлов

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

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

Ответ 1

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

Ответ 2

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

SendBroadcast

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

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

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


MediaScannerWrapper

Как указано здесь (за ответ @Brian), он состоит в завершении экземпляра 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. Это потому, что благодаря Justin обнаружена ошибка и выдается официальный трекер. Это означает, что до тех пор, пока ошибка не будет устранена, мы не остаемся без поддержки KitKat.

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

Ответ 3

Использовать 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)

Ответ 4

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

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) {


    }
});

Ответ 5

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

Ответ 6

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

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);

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

public static final Строка ACTION_MEDIA_SCANNER_SCAN_FILE

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

и

public static final Строка ACTION_MEDIA_SCANNER_FINISHED

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