Изображение, сохраненное на SD-карту, не отображается в приложении Галерея Android


93

Я сохраняю изображение на SD-карту, и оно не отображается в приложении Галерея, пока я не сниму SD-карту и не верну ее обратно.

Вы хоть представляете, почему это так?

Похоже, в приложении Галерея есть кеш, который не обновляется при сохранении файла ...

На самом деле, я также хочу открыть только что сохраненное изображение в приложении "Галерея", и мне это не удалось.
Это мой вопрос по этой проблеме.


1
На этот вопрос дан пошаговый ответ в этом руководстве: stackoverflow.com/questions/30506301/…
Takermania

Ответы:


45

Система сканирует SD-карту при ее подключении, чтобы найти новые файлы образов (и другие). Если вы добавляете файл программно, вы можете использовать этот класс:

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


4
Боковое примечание: хотя вопрос относится к добавлению файлов, MediaScannerConnection не предоставляет решения для удаления файлов - даже при запросе сканирования родительской папки удаленного файла.
AlikElzin-kilaka

86

Более простое решение - использовать удобный статический метод scanFile () :

File imageFile = ...
MediaScannerConnection.scanFile(this, new String[] { imageFile.getPath() }, new String[] { "image/jpeg" }, null);

где thisнаходится ваша активность (или какой-либо другой контекст), mime-тип необходим только в том случае, если вы используете нестандартные расширения файлов, а nullдля дополнительного обратного вызова (который нам не нужен в таком простом случае).


2
Обратите внимание, метод вещания, который предоставляют другие (и Google), очень редко срабатывает).
Chris.Jenkins

2
Это работало для меня в более ранних версиях Android ~ 4.0, но теперь в 4.3+, похоже, не работает. Изображения не отображаются в приложении галереи.
hooby3dfx 01

Отлично ! Вы можете получить контекст с помощью: Android.App.Application.Context
jug

Работал в зефира
Hitesh Sahu

66

Мой ответ на исходный вопрос и всем, у кого может быть эта проблема:

У меня была такая же проблема: изображения в моем приложении, которые люди сохранили на SD-карту, не сразу отображались в их галерее. После некоторого поиска я нашел эту одну строку кода, вставленную после моего кода «сохранить на SD-карту», ​​который устранил проблему:

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

нам нужно использовать медиа-сканер, чтобы иметь возможность использовать эту трансляцию? Я использую другой метод для отображения изображений в моей галерее. Когда я использую выше sendBroadcast при нажатии кнопки сохранения, моя галерея не обновляется новым изображением!
изменить

4
Он старый, но может кому-то помочь - более конкретный путь: sendBroadcast (new Intent (Intent.ACTION_MEDIA_MOUNTED, Uri.parse ("file: //" + Environment.getExternalStoragePublicDirectory (Environment.DIRECTORY_PICTURES)))); Этот метод (этот ответ, а не только мой комментарий) не работает на эмуляторе. Протестируйте на реальном устройстве.

Я считаю, что принятый ответ предлагает правильный способ сделать это. Но если вы пытаетесь поддерживать API <= 7, это хороший запасной вариант.
Амр Мостафа

Ваш ответ будет полезен для других устройств. Не работает в HTC, когда я пытаюсь просканировать папку с приложениями. Новое добавленное изображение не отображается.
MobileEvangelist

6
Похоже, это больше не поддерживается на Android 4.4 или выше. В этом случае будет выброшено исключение разрешения.
rsp1984

13

Вы также можете добавить изображение в галерею мультимедиа намеренно, посмотрите пример кода, чтобы увидеть, как это делается:

ContentValues image = new ContentValues();

image.put(Images.Media.TITLE, imageTitle);
image.put(Images.Media.DISPLAY_NAME, imageDisplayName);
image.put(Images.Media.DESCRIPTION, imageDescription);
image.put(Images.Media.DATE_ADDED, dateTaken);
image.put(Images.Media.DATE_TAKEN, dateTaken);
image.put(Images.Media.DATE_MODIFIED, dateTaken);
image.put(Images.Media.MIME_TYPE, "image/png");
image.put(Images.Media.ORIENTATION, 0);

 File parent = imageFile.getParentFile();
 String path = parent.toString().toLowerCase();
 String name = parent.getName().toLowerCase();
 image.put(Images.ImageColumns.BUCKET_ID, path.hashCode());
 image.put(Images.ImageColumns.BUCKET_DISPLAY_NAME, name);
 image.put(Images.Media.SIZE, imageFile.length());

 image.put(Images.Media.DATA, imageFile.getAbsolutePath());

 Uri result = context.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, image);

Здравствуй. Этот метод добавляет изображение в MediaStore, я подтвердил это, проверив возвращенное, Uriно проблема в том, что вставленное изображение не отображается в галерее. Проверял и в начале, и в конце галереи. Не могли бы вы предложить какой-либо метод, чтобы вставленное изображение сразу же появилось в галерее?
Шажил Афзал

12

Обновление галереи, включая Android KITKAT

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
{
        Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
        File f = new File("file://"+ Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES));
        Uri contentUri = Uri.fromFile(f);
        mediaScanIntent.setData(contentUri);
        this.sendBroadcast(mediaScanIntent);
}
else
{
        sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://" + Environment.getExternalStorageDirectory())));
}

Код, который находится внутри первого условия в операторе «IF», ​​отлично работает у меня в KitKat (Android 4.4.4, API 19).
Alex

8

Вот код для MediaScannerConnection:

MyMediaConnectorClient client = new MyMediaConnectorClient(newfile);
MediaScannerConnection scanner = new MediaScannerConnection(context, client);
client.setScanner(scanner);
scanner.connect();

newfile - это объект File вашего нового / сохраненного файла.


2
Спасибо за ваш ответ. Собственно, я уже давно закончил этот проект ... Даже не помню, какое решение я использовал. Другие пользователи могут найти ваше решение полезным, если вы также предоставите реализацию MyMediaConnectorClient...
Майкл Кесслер,

да - сейчас у меня настоящая головная боль. Пожалуйста, опубликуйте :)
Стив

Да, я не совсем понимаю, как должен быть поток - исправьте меня, где я ошибаюсь, я могу использовать MediaScannerConnection для обновления информации SDCAARD, поэтому я делаю снимок камерой и передаю новый файл в MSC, и теперь я могу получить доступ к файлу с клиентом сканера соединений?
Стив

Последовательность действий такова: вы делаете снимок, сохраняете его на SD-карту, а затем обновляете сканер, чтобы файловая система обновлялась, чтобы увидеть сохраненное изображение в галерее устройства. Если вы этого не сделаете со сканером, вы увидите свою картинку после следующего перезапуска устройства в галерее.
3dmg 01

7

в эмуляторе есть приложение с надписью "Dev Tools"

щелкните по нему и выберите «Сканирование мультимедиа» .. все изображения будут отсканированы


приятно знать, единственный способ, который я знал до того, как вы сказали, это перезагрузить телефон :)
мишкин

6

Разрешите вашей деятельности реализовать MediaScannerConnectionClient и добавьте это в свою деятельность:

private void startScan() 
{ 
    if(conn!=null) conn.disconnect();  
    conn = new MediaScannerConnection(YourActivity.this,YourActivity.this); 
    conn.connect(); 
} 

@Override 
public void onMediaScannerConnected() { 
    try{
        conn.scanFile(yourImagePath, "image/*");
       } catch (java.lang.IllegalStateException e){
       }
}

@Override 
public void onScanCompleted(String path, Uri uri) { 
    conn.disconnect(); 
} 

Здравствуй! Что, если мы знаем Uriизображение, например:content://media/external/images/media/1231778
Шажил Афзал

6

эта работа со мной

File file = ..... // Save file

context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(file)));

4
 File folderGIF = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) + "/newgif2");    //path where gif will be stored
success = folderGIF.mkdir();    //make directory
 String finalPath = folderGIF + "/test1.gif";  //path of file
.....
/* changes in gallery app if any changes in done*/
 MediaScannerConnection.scanFile(this,
                    new String[]{finalPath}, null,
                    new MediaScannerConnection.OnScanCompletedListener() {
                        public void onScanCompleted(String path, Uri uri) {
                            Log.i("ExternalStorage", "Scanned " + path + ":");
                            Log.i("ExternalStorage", "-> uri=" + uri);
                        }
                    });

Я хочу сохранить анимированный файл gif, который находится во внешнем хранилище, и у меня есть путь, т.е. / storage / emulated / 0 / Android / data / <PackageName> / files / <FolderName> /xyz.gif. Теперь я хочу сохранить / скопировать этот файл в галерею изображений и показать там. Как это сделать.
Зия Ур Рахман

3

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

  1. Сначала загрузите растровое изображение



     private Bitmap loadBitmap(String url) {
        try {
            InputStream in = new java.net.URL(url).openStream();
            return BitmapFactory.decodeStream(in);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
       }


  1. Пожалуйста, также предоставьте следующее разрешение в вашем файле AndroidManifest.xml.


    uses-permission android:name="android.permission.INTERNET" 
    uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"


  1. Вот весь код, написанный в Activty, в котором мы хотим выполнить эту задачу.



     void saveMyImage(String appName, String imageUrl, String imageName) {

            Bitmap bmImg = loadBitmap(imageUrl);
            File filename;
            try {
                String path1 = android.os.Environment.getExternalStorageDirectory()
                        .toString();
                File file = new File(path1 + "/" + appName);
                if (!file.exists())
                    file.mkdirs();
                filename = new File(file.getAbsolutePath() + "/" + imageName
                        + ".jpg");
                FileOutputStream out = new FileOutputStream(filename);
                bmImg.compress(Bitmap.CompressFormat.JPEG, 90, out);
                out.flush();
                out.close();
                ContentValues image = new ContentValues();
                image.put(Images.Media.TITLE, appName);
                image.put(Images.Media.DISPLAY_NAME, imageName);
                image.put(Images.Media.DESCRIPTION, "App Image");
                image.put(Images.Media.DATE_ADDED, System.currentTimeMillis());
                image.put(Images.Media.MIME_TYPE, "image/jpg");
                image.put(Images.Media.ORIENTATION, 0);
                File parent = filename.getParentFile();
                image.put(Images.ImageColumns.BUCKET_ID, parent.toString()
                        .toLowerCase().hashCode());
                image.put(Images.ImageColumns.BUCKET_DISPLAY_NAME, parent.getName()
                        .toLowerCase());
                image.put(Images.Media.SIZE, filename.length());
                image.put(Images.Media.DATA, filename.getAbsolutePath());
                Uri result = getContentResolver().insert(
                        MediaStore.Images.Media.EXTERNAL_CONTENT_URI, image);
                Toast.makeText(getApplicationContext(),
                        "File is Saved in  " + filename, Toast.LENGTH_SHORT).show();
            } catch (Exception e) {
                e.printStackTrace();
            }

        }


  1. Надеюсь, что это может решить всю вашу проблему.

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

На KITKAT вроде не работает. Это вызывает исключение отказа в разрешении и приводит к сбою приложения. Для этого я сделал следующее:

String path = mediaStorageDir.getPath() + File.separator
                    + "IMG_Some_name.jpg";
CameraActivity.this.sendBroadcast(new Intent(
                             Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri
                            .parse("file://" + path)));

Надеюсь, это поможет.


2

Используйте это после сохранения изображения

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

3
Это работает, но это не лучшее решение. Вы обманываете систему, думая, что SD-карта будет (повторно) смонтирована, и, возможно, принудительно пересканируете всю SD-карту. MediaScanner.scanFile (..) - лучшее решение, когда вы сейчас нуждаетесь в файле, который хотите добавить.
pocmo 04

1
Это поиск всех изображений. И это включает в себя много ненужной обработки данных, которая может быть неактуальной, когда у нас есть только одно изображение, которое нужно показать в галерее.
Рахул Растоги

2

Мой код для MyMediaConnectorClient:

public class MyMediaConnectorClient implements MediaScannerConnectionClient {

    String _fisier;
    MediaScannerConnection MEDIA_SCANNER_CONNECTION;

    public MyMediaConnectorClient(String nume) {
        _fisier = nume;
    }

    public void setScanner(MediaScannerConnection msc){
        MEDIA_SCANNER_CONNECTION = msc;
    }

    @Override
    public void onMediaScannerConnected() {
        MEDIA_SCANNER_CONNECTION.scanFile(_fisier, null);
    }

    @Override
    public void onScanCompleted(String path, Uri uri) {
        if(path.equals(_fisier))
            MEDIA_SCANNER_CONNECTION.disconnect();
    }
}

0

Вам необходимо предоставить разрешения приложению Галерея. Просто нажмите и удерживайте значок приложения галереи на главном экране и нажмите «ИНФОРМАЦИЯ О ПРИЛОЖЕНИИ», которая появляется в верхней части экрана. Откроются настройки приложения галереи. Теперь перейдите на вкладку «Разрешения» и включите хранилище, разрешения камеры, переключив его. Теперь перейдите в свое собственное приложение галереи, и вы получите сохраненные изображения.


0

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

      String resultPath = getExternalFilesDir(Environment.DIRECTORY_PICTURES)+ 
      getString(R.string.directory) + System.currentTimeMillis() + ".jpg";

       new File(resultPath).getParentFile().mkdir();

        try {
            OutputStream fileOutputStream = new FileOutputStream(resultPath);
            savedBitmap.compress(CompressFormat.JPEG, 100, fileOutputStream);
            fileOutputStream.flush();
            fileOutputStream.close();
        } catch (IOException e2) {
            e2.printStackTrace();
        }
        savedBitmap.recycle();

        File file = new File(resultPath);
        ContentValues values = new ContentValues();
        values.put(MediaStore.Images.Media.TITLE, "Photo");
        values.put(MediaStore.Images.Media.DESCRIPTION, "Edited");
        values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
        values.put(MediaStore.Images.Media.DATE_TAKEN, System.currentTimeMillis ());
        values.put(MediaStore.Images.Media.DATE_ADDED, System.currentTimeMillis());
        values.put(MediaStore.Images.ImageColumns.BUCKET_ID, file.toString().toLowerCase(Locale.US).hashCode());
        values.put(MediaStore.Images.ImageColumns.BUCKET_DISPLAY_NAME, file.getName().toLowerCase(Locale.US));
        values.put("_data", resultPath);

        ContentResolver cr = getContentResolver();
        cr.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);




        return  resultPath;

0

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

private void galleryAddPicBroadCast() {
        Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
        Uri contentUri = Uri.fromFile(photoFile);
        mediaScanIntent.setData(contentUri);
        this.sendBroadcast(mediaScanIntent);
    }
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.