ContentResolver не содержит только что созданное изображение в непосредственном запросе после создания файла

Я использую этот код для копирования изображения с помощью documentFile.createFile()

private void newcopyFile(File fileInput, String outputParentPath,
                            String mimeType, String newFileName) {

        DocumentFile documentFileGoal = DocumentFile.fromTreeUri(this, treeUri);

        String[] parts = outputParentPath.split("\\/");
        for (int i = 3; i < parts.length; i++) {
            if (documentFileGoal != null) {
                documentFileGoal = documentFileGoal.findFile(parts[i]);
            }
        }
        if (documentFileGoal == null) {
            Toast.makeText(MainActivity.this, "Directory not found", Toast.LENGTH_SHORT).show();
            return;
        }

        DocumentFile documentFileNewFile = documentFileGoal.createFile(mimeType, newFileName);

        InputStream inputStream = null;
        OutputStream outputStream = null;
        try {
            outputStream = getContentResolver().openOutputStream(documentFileNewFile.getUri());
            inputStream = new FileInputStream(fileInput);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        try {
            if (outputStream != null) {
                byte[] buffer = new byte[1024];
                int read;
                if (inputStream != null) {
                    while ((read = inputStream.read(buffer)) != -1) {
                        outputStream.write(buffer, 0, read);
                    }
                }
                if (inputStream != null) {
                    inputStream.close();
                }
                inputStream = null;
                outputStream.flush();
                outputStream.close();
                outputStream = null;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

И вот как я запрашиваю ContentResolver после создания изображения, чтобы немедленно обновить мою галерею изображений с результатом запроса, который должен содержать информацию о вновь созданном изображении.

cursorPhotos = MainActivity.this.getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                    projectionsImages,
                    null,
                    null,
                    MediaStore.Images.Media.DATE_TAKEN + " DESC"
            );

Но немедленный запрос не смог найти вновь созданное изображение. И если я снова запущу запрос через мгновение, в результате появится вновь созданное изображение.

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

Есть ли какой-либо метод или прослушиватель, чтобы узнать, когда вновь созданное изображение зарегистрировано ContentResolver?


comment
Вы копируете изображения внутри асинхронной задачи или в основном потоке пользовательского интерфейса?   -  person Rahulrr2602    schedule 21.07.2017
comment
@ Rahulrr2602 Да, смотрите ответ.   -  person Eftekhari    schedule 21.07.2017
comment
Большое спасибо. Если я много раз зацикливаю метод newcopyFile, то иногда documentFileGoal имеет значение null.   -  person Rahulrr2602    schedule 21.07.2017
comment
Пожалуйста. Скопируйте и вставьте свой код в новый вопрос, а затем направьте меня по ссылке на ваш вопрос.   -  person Eftekhari    schedule 21.07.2017
comment
Извините за задержку. Я задал новый вопрос. Это ссылка на вопрос stackoverflow.com/q/45263806/7317019. Любая помощь будет очень признательна.   -  person Rahulrr2602    schedule 23.07.2017
comment
Извините за задержку. Я задал новый вопрос. Это ссылка на вопрос stackoverflow.com/q/45263806/7317019. Любая помощь будет очень признательна.   -  person Rahulrr2602    schedule 23.07.2017


Ответы (2)


Вы можете использовать это или вот как я реализован прослушиватель (наблюдатель) для ContentResolver изменений, используя ContentObserver, чтобы узнать, когда настало подходящее время для запуска запроса для получения вновь созданного изображения из ContentResolver.

Сначала создайте ContentObserver класс:

Этот класс, как говорит нам его имя, наблюдает за любыми изменениями содержимого в нашем желаемом Uri.

class MyObserver extends ContentObserver {
    public MyObserver(android.os.Handler handler) {
        super(handler);
    }

    @Override
    public void onChange(boolean selfChange) {
        this.onChange(selfChange, null);
    }

    @Override
    public void onChange(boolean selfChange, Uri uri) {
        //(SDK>=16)
        // do s.th.
        // depending on the handler you might be on the UI
        // thread, so be cautious!

        // This is my AsyncTask that queries ContentResolver which now
        // is aware of newly created media file.
        // You implement your own query here in whatever way you like
        // This query will contain info for newly created image
        asyncTaskGetPhotosVideos = new AsyncTaskGetPhotosVideos();
        asyncTaskGetPhotosVideos.execute();
    }
}

и в конце вашего метода копирования вы можете установить ContentObserver на свой ContentResolver для определенного Uri.

 getContentResolver().registerContentObserver(
         MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
         true,
         myObserver);

и не забудьте отменить регистрацию своего наблюдателя, иначе вы столкнетесь с утечкой памяти. Я бы предпочел сделать это в конце моей AsyncTask (onPostExecute).

getContentResolver().unregisterContentObserver(myObserver);

Вы можете выбрать ContentObserver для нужного Uri на протяжении всего жизненного цикла приложения, чтобы получать уведомления всякий раз, когда медиафайл изменяется, удаляется или вставляется извне или внутри вашего приложения.

Для этого подхода вы можете зарегистрировать своего наблюдателя в методе жизненного цикла onResume() и отменить его регистрацию в методе onPause().

person Eftekhari    schedule 25.07.2016

Извините, я разместил неправильный код

Когда вы добавляете файлы в файловую систему Android, эти файлы не обнаруживаются MedaScanner автоматически. Но часто они должны быть.

Итак, чтобы добавить файл в контент-провайдер вручную

Так что используйте этот код: -

Intent intent =
      new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
intent.setData(Uri.fromFile(file));
sendBroadcast(intent);

Для получения дополнительных способов сделать это и для справки посетите этот сайт: -

http://www.grokkingandroid.com/adding-files-to-androids-media-library-using-the-mediascanner/

person Ankesh kumar Jaisansaria    schedule 24.07.2016
comment
Зачем мне удалять элемент из медиа-магазина? Мне просто нужен слушатель для ContentResolver обновления. - person Eftekhari; 24.07.2016
comment
Файл был добавлен, но ContentProvider не знал об этом, и я предполагаю, что он активен (вероятно, ищет все медиафайлы и прочее), чтобы предоставить информацию для вновь созданных медиафайлов. Поэтому мне просто нужен наблюдатель (ContentObserver), чтобы узнать, когда ContentResolver будет сделано с получением вновь созданного изображения. Смотрите мой ответ и предоставленную ссылку. Кстати, спасибо. - person Eftekhari; 25.07.2016