Obraz zapisany na karcie SD nie pojawia się w aplikacji Galeria Androida

93

Zapisuję obraz na karcie SD i nie pojawia się on w aplikacji Galeria, dopóki nie wyciągnę karty sd i nie zwrócę jej.

Czy masz pojęcie, dlaczego tak jest?

Wygląda na to, że aplikacja Galeria ma pamięć podręczną, która nie jest aktualizowana podczas zapisywania pliku ...

Właściwie to też chcę otworzyć właśnie zapisany obraz w aplikacji Galeria i bez powodzenia
to jest moje pytanie w tej sprawie.

Michael Kessler
źródło
1
Na to pytanie udzielono odpowiedzi krok po kroku w tym samouczku: stackoverflow.com/questions/30506301/…
Takermania

Odpowiedzi:

45

System skanuje kartę SD po jej zamontowaniu, aby znaleźć nowe pliki obrazu (i inne). Jeśli programowo dodajesz plik, możesz użyć tej klasy:

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

hackbod
źródło
4
Uwaga dodatkowa: chociaż pytanie dotyczy dodawania plików, MediaScannerConnection nie zapewnia rozwiązania do usuwania plików - nawet w przypadku żądania przeskanowania folderu nadrzędnego usuniętego pliku.
AlikElzin-kilaka
86

Prostszym rozwiązaniem jest użycie statycznej wygodnej metody scanFile () :

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

gdzie thisjest twoja aktywność (lub w jakimkolwiek kontekście), typ MIME jest potrzebny tylko wtedy, gdy używasz niestandardowych rozszerzeń plików, a nulljest dla opcjonalnego wywołania zwrotnego (którego nie potrzebujemy w tak prostym przypadku).

darrenp
źródło
2
Doskonale, metoda nadawania, którą oferują inni (i Google), bardzo rzadko działa).
Chris.Jenkins
2
To działało dla mnie we wcześniejszych wersjach Androida ~ 4.0, ale teraz w 4.3+ nie wydaje się działać. Obrazy nie pojawiają się w aplikacji Galeria.
hooby3dfx
Idealny ! Możesz uzyskać kontekst za pomocą: Android.App.Application.Context
dzban
Pracował w ptasie mleczko
Hitesh Sahu
66

Moja odpowiedź na pierwotne pytanie i dla każdego, kto może mieć ten problem:

Miałem ten sam problem, obrazy w mojej aplikacji, które ludzie zapisywali na karcie SD, nie pojawiały się natychmiast w ich Galerii. Po kilku poszukiwaniach znalazłem ten jeden wiersz kodu wstawiony po moim kodzie `` zapisz na sdcard '', który rozwiązał problem:

sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://"+ Environment.getExternalStorageDirectory())));
ShadowGod
źródło
czy musimy używać skanera multimediów, aby móc korzystać z tej transmisji? używam innej metody wyświetlania obrazów w mojej galerii. Kiedy używam powyższego przycisku sendBroadcast przy zapisywaniu kliknij, moja galeria nie jest aktualizowana o nowy obraz!
zmiana
4
Jest stary, ale może komuś pomóc - bardziej szczegółowa ścieżka: sendBroadcast (new Intent (Intent.ACTION_MEDIA_MOUNTED, Uri.parse ("file: //" + Environment.getExternalStoragePublicDirectory (Environment.DIRECTORY_PICTURES)))); Ta metoda (ta odpowiedź, nie tylko mój komentarz) nie działa na emulatorze. Przetestuj na prawdziwym urządzeniu.
Uważam, że zaakceptowana odpowiedź to właściwy sposób. Ale jeśli próbujesz obsługiwać API <= 7, jest to miła opcja zastępcza.
Amr Mostafa
Twoja odpowiedź jest pomocna w przypadku innych urządzeń. Nie działa na HTC, kiedy próbuję przeskanować folder aplikacji. Nie wyświetla nowo dodanego obrazu.
MobileEvangelist
6
Wygląda na to, że nie jest już obsługiwane w systemie Android 4.4 lub nowszym. W takim przypadku zostanie zgłoszony wyjątek dotyczący uprawnień.
rsp1984
13

Możesz również dodać obraz do galerii multimediów celowo, spójrz na przykładowy kod, aby zobaczyć, jak to się robi:

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);
Janusz
źródło
Cześć. Ta metoda dodaje obraz do MediaStore, potwierdziłem to, sprawdzając zwrócony, Uriale problem polega na tym, że wstawiony obraz nie jest wyświetlany w galerii. Sprawdziłem zarówno na początku, jak i na końcu galerii. Czy może Pan zaproponować jakąś metodę, aby wstawiony obraz od razu pojawił się w galerii?
Shajeel Afzal
12

Odświeżenie galerii, w tym 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())));
}
AtanuCSE
źródło
Kod znajdujący się w pierwszym warunku z wyrażeniem „IF” działa dobrze dla mnie w KitKat (Android 4.4.4, API 19).
Alex
8

Oto kod MediaScannerConnection:

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

nowy plik to obiekt File nowego / zapisanego pliku.

3dmg
źródło
2
Dziękuję za Twoją odpowiedź. Właściwie to już dawno skończyłem ten projekt ... Nawet nie pamiętam, jakie rozwiązanie zastosowałem. Inni użytkownicy mogą znaleźć swoje rozwiązanie pomocne, jeśli chcesz również zapewnić realizację MyMediaConnectorClient...
Michael Kessler
tak - w tej chwili mam z tym prawdziwy ból głowy. Proszę pisać :)
Steve
Tak, nie bardzo wiem, jak powinien wyglądać przepływ -Popraw mnie tam, gdzie się mylę Mogę użyć MediaScannerConnection do zaktualizowania informacji SDCAARD, więc robię zdjęcie aparatem i przekazuję nowy plik do MSC i teraz mam dostęp do pliku z klientem skanera połączeń?
Steve
Przepływ jest następujący: robisz zdjęcie, zapisujesz je na karcie sd, a następnie aktualizujesz skaner, aby system plików został zaktualizowany, aby zobaczyć zapisane zdjęcie w galerii urządzeń. Jeśli nie zrobisz tego za pomocą skanera, zobaczysz swoje zdjęcie po ponownym uruchomieniu urządzenia w galerii.
3dmg
7

w emulatorze jest aplikacja z napisem „Dev Tools”

kliknij na to i wybierz „Skanowanie multimediów”. Wszystkie obrazy zostaną zeskanowane

Abhishek Susarla
źródło
wspaniale wiedzieć, jedyny sposób, w jaki wiedziałem, zanim powiedziałeś, to ponowne uruchomienie telefonu :)
mishkin
6

Pozwól swojej aktywności zaimplementować 'MediaScannerConnectionClient' i dodaj to do swojej aktywności:

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(); 
} 
TOMKA
źródło
Cześć! A co jeśli znamy Urizdjęcie, na przykład:content://media/external/images/media/1231778
Shajeel Afzal
6

ta praca ze mną

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

context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(file)));
user3245604
źródło
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);
                        }
                    });
Khyati Fatania
źródło
Chcę zapisać animowany plik gif, który znajduje się w pamięci zewnętrznej i mam ścieżkę tj. / Storage / emulated / 0 / Android / data / <PackageName> / files / <FolderName> /xyz.gif. Teraz chcę zapisać / skopiować ten plik do galerii obrazów i pokazać tam. Jak to zrobić.
Zia Ur Rahman
3

Tutaj udostępniam kod, który może załadować obraz w postaci mapy bitowej z i zapisać ten obraz w galerii sdcard w folderze nazwy aplikacji. Powinieneś wykonać następujące kroki

  1. Najpierw pobierz obraz bitmapowy



     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. Podaj również następujące uprawnienia w pliku AndroidManifest.xml.


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


  1. Oto cały kod napisany w Activty, w którym chcemy wykonać to zadanie.



     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. Mam nadzieję, że może rozwiązać cały twój problem.
VISHNU GARG
źródło
3
sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://"+ Environment.getExternalStorageDirectory())));

Wydaje się, że nie działa na KITKAT. Zgłasza wyjątek odmowy uprawnień i powoduje awarię aplikacji. W tym celu wykonałem następujące czynności:

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

Mam nadzieję, że to pomoże.

Muhammad Riyaz
źródło
2

Użyj tego po zapisaniu obrazu

sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://"+ Environment.getExternalStorageDirectory())));
Deepu
źródło
3
To działa, ale nie jest to najlepsze rozwiązanie. Oszukasz system, myśląc, że karta SD zostanie (ponownie) zamontowana i prawdopodobnie wymusisz ponowne przeskanowanie całej karty SD. MediaScanner.scanFile (..) jest najlepszym rozwiązaniem w przypadku pliku, który chcesz dodać.
pocmo
1
To wyszukiwanie wszystkich obrazów. I wiąże się z dużą ilością niepotrzebnego przetwarzania danych, które mogą być nieistotne, gdy mamy tylko jeden obraz do pokazania w galerii.
Rahul Rastogi
2

Mój kod dla 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();
    }
}
Marian
źródło
0

Musisz nadać uprawnienia aplikacji Galeria. Po prostu naciśnij i przytrzymaj ikonę aplikacji galerii na ekranie głównym i dotknij opcji „INFORMACJE O APLIKACJI”, która pojawi się u góry ekranu. Spowoduje to wyświetlenie ustawień aplikacji Galeria. Teraz przejdź do zakładki Uprawnienia i włącz przechowywanie, uprawnienia kamery, przełączając je. Teraz przejdź do swojej natywnej aplikacji galerii, a otrzymasz zapisane obrazy.

Devanshu Jain
źródło
0

To również rozwiąże problem, jeśli obraz w galerii nie jest wyświetlany, zamiast tego może wyświetlać bitmapę typu 404 w środku. dodaj tagi, które są w moim kodzie z twoim obrazem, ponieważ muszą istnieć metadane, aby wyświetlić obraz w galerii.

      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;
Mubashir Murtaza
źródło
0

Wypróbuj ten, będzie emitować informacje o utworzonym nowym obrazie, dzięki czemu Twój obraz będzie widoczny. wewnątrz galerii. PhotoFile zastąp rzeczywistą ścieżką pliku nowo utworzonego obrazu

private void galleryAddPicBroadCast() {
        Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
        Uri contentUri = Uri.fromFile(photoFile);
        mediaScanIntent.setData(contentUri);
        this.sendBroadcast(mediaScanIntent);
    }
Anand Saggam
źródło