Получить список фотогалерей на Android

Я ищу: Список существующих названий фотогалерей (надеюсь, также их верхний эскиз) Содержимое галереи (затем я могу загрузить эскизы и полный размер по мере необходимости)

Как мне получить список «Галереи» (не знаю, является ли это правильным термином в Android для групп изображений, видимых в приложении «Галерея» …) и их содержимое? Мне нужен доступ к галерее в ее структуре без использования существующего отображения галереи (я создаю совершенно новый, а не дополнительный слой для запрашивающего фото и т. д.)

Я предполагаю, что MediaStore.Images - это то место, где мне нужно быть, но я не вижу ничего, что могло бы дать мне группировку...


person ima747    schedule 16.11.2010    source источник


Ответы (5)


Группы определяются MediaStore.Images.Media.BUCKET_DISPLAY_NAME. Вот пример кода для перечисления изображений и регистрации имени их корзины и date_taken:

// which image properties are we querying
String[] projection = new String[] {
        MediaStore.Images.Media._ID,
        MediaStore.Images.Media.BUCKET_DISPLAY_NAME,
        MediaStore.Images.Media.DATE_TAKEN
};

// content:// style URI for the "primary" external storage volume
Uri images = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;

// Make the query.
Cursor cur = managedQuery(images,
        projection, // Which columns to return
        null,       // Which rows to return (all rows)
        null,       // Selection arguments (none)
        null        // Ordering
        );

Log.i("ListingImages"," query count=" + cur.getCount());

if (cur.moveToFirst()) {
    String bucket;
    String date;
    int bucketColumn = cur.getColumnIndex(
        MediaStore.Images.Media.BUCKET_DISPLAY_NAME);

    int dateColumn = cur.getColumnIndex(
        MediaStore.Images.Media.DATE_TAKEN);

    do {
        // Get the field values
        bucket = cur.getString(bucketColumn);
        date = cur.getString(dateColumn);

        // Do something with the values.
        Log.i("ListingImages", " bucket=" + bucket 
               + "  date_taken=" + date);
    } while (cur.moveToNext());

}
person Peter Knego    schedule 16.11.2010
comment
А! он работает как необработанный запрос к базе данных. отличный пример кода спасибо! - person ima747; 16.11.2010
comment
как получить путь к изображению? для каждого dateToken? - person Abdul Wahab; 08.05.2014
comment
manageQuery устарел, используйте context.getContentResolver().query, см.: stackoverflow.com/a/12714830/3324388 - person Aggressor; 11.05.2015
comment
@Peter Knego ... Это прекрасно работает, но немного медленно, когда количество изображений › 1000. Любое решение этого вопроса будет высоко оценено - person Saeed Jassani; 13.06.2016
comment
›= android.os.Build.VERSION_CODES.Q (Печальная история!) - person Mr. Lemon; 14.02.2020
comment
@Mr.Lemon Что тебе грустная история для Android Q? У меня проблема, когда cursor.getColumnIndex(MediaStore.Images.Media.BUCKET_DISPLAY_NAME) возвращает значение null на Android Q - person Azlan Jamal; 24.07.2020
comment
Привет, кто-нибудь знает, почему это решение не работает для Android Q? - person Azlan Jamal; 26.07.2020

Вот полное решение за несколько простых шагов:

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

  1. Создайте объект, который будет содержать изображения после их извлечения из хранилища. Мы назовем его PhoneAlbum. Вот как это будет выглядеть:

    public class PhoneAlbum {
    
        private int id;
        private String name;
        private String coverUri;
        private Vector<PhonePhoto> albumPhotos;
    
        public int getId() {
            return id;
        }
    
        public void setId( int id ) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName( String name ) {
            this.name = name;
        }
    
        public String getCoverUri() {
            return coverUri;
        }
    
        public void setCoverUri( String albumCoverUri ) {
            this.coverUri = albumCoverUri;
        }
    
        public Vector< PhonePhoto > getAlbumPhotos() {
            if ( albumPhotos == null ) {
                albumPhotos = new Vector<>();
            }
            return albumPhotos;
        }
    
        public void setAlbumPhotos( Vector< PhonePhoto > albumPhotos ) {
            this.albumPhotos = albumPhotos;
        }
    }
    
  2. Создайте объект, который будет содержать изображения в альбоме с именем: PhonePhoto

    public class PhonePhoto {
    
        private int id;
        private String albumName;
        private String photoUri;
    
        public int getId() {
            return id;
        }
    
        public void setId( int id ) {
            this.id = id;
        }
    
        public String getAlbumName() {
            return albumName;
        }
    
        public void setAlbumName( String name ) {
            this.albumName = name;
        }
    
        public String getPhotoUri() {
            return photoUri;
        }
    
        public void setPhotoUri( String photoUri ) {
            this.photoUri = photoUri;
        }
    }
    
  3. Создайте интерфейс для обработки извлеченных изображений после завершения. Мы назовем его OnPhoneImagesObtained. Вот:

    public interface OnPhoneImagesObtained {
    
        void onComplete( Vector<PhoneAlbum> albums );
        void onError();
    
    }
    
  4. Создайте новый класс: DeviceImageManager

    public class DeviceImageManager {
    
    }
    
  5. После создания DeviceImageManager добавьте следующий метод:

    public static void getPhoneAlbums( Context context , OnPhoneImagesObtained listener ){
        // Creating vectors to hold the final albums objects and albums names
        Vector< PhoneAlbum > phoneAlbums = new Vector<>();
        Vector< String > albumsNames = new Vector<>();
    
        // which image properties are we querying
        String[] projection = new String[] {
                MediaStore.Images.Media.BUCKET_DISPLAY_NAME,
                MediaStore.Images.Media.DATA,
                MediaStore.Images.Media._ID
        };
    
        // content: style URI for the "primary" external storage volume
        Uri images = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
    
        // Make the query.
        Cursor cur = context.getContentResolver().query(images,
                projection, // Which columns to return
                null,       // Which rows to return (all rows)
                null,       // Selection arguments (none)
                null        // Ordering
        );
    
        if ( cur != null && cur.getCount() > 0 ) {
            Log.i("DeviceImageManager"," query count=" + cur.getCount());
    
            if (cur.moveToFirst()) {
                String bucketName;
                String data;
                String imageId;
                int bucketNameColumn = cur.getColumnIndex(
                    MediaStore.Images.Media.BUCKET_DISPLAY_NAME);
    
                int imageUriColumn = cur.getColumnIndex(
                    MediaStore.Images.Media.DATA);
    
                int imageIdColumn = cur.getColumnIndex(
                    MediaStore.Images.Media._ID );
    
                do {
                    // Get the field values
                    bucketName = cur.getString( bucketNameColumn );
                    data = cur.getString( imageUriColumn );
                    imageId = cur.getString( imageIdColumn );
    
                    // Adding a new PhonePhoto object to phonePhotos vector
                    PhonePhoto phonePhoto = new PhonePhoto();
                    phonePhoto.setAlbumName( bucketName );
                    phonePhoto.setPhotoUri( data );
                    phonePhoto.setId( Integer.valueOf( imageId ) );
    
                    if ( albumsNames.contains( bucketName ) ) {
                        for ( PhoneAlbum album : phoneAlbums ) {
                            if ( album.getName().equals( bucketName ) ) {
                                album.getAlbumPhotos().add( phonePhoto );
                                Log.i( "DeviceImageManager", "A photo was added to album => " + bucketName );
                                break;
                            }
                        }
                    } else {
                        PhoneAlbum album = new PhoneAlbum();
                        Log.i( "DeviceImageManager", "A new album was created => " + bucketName );
                        album.setId( phonePhoto.getId() );
                        album.setName( bucketName );
                        album.setCoverUri( phonePhoto.getPhotoUri() );
                        album.getAlbumPhotos().add( phonePhoto );
                        Log.i( "DeviceImageManager", "A photo was added to album => " + bucketName );
    
                        phoneAlbums.add( album );
                        albumsNames.add( bucketName );
                    }
    
                } while (cur.moveToNext());
            }
    
            cur.close();
            listener.onComplete( phoneAlbums );
        } else {
            listener.onError();
        }
    }
    
  6. Теперь все, что вам осталось, это вывести изображения на экран. В моем случае мне нравится использовать Picasso. Вот как я это делаю:

        Picasso.with( getActivity() )
                    .load( "file:" + mPhoneAlbums.get( i ).getCoverUri() )
                    .centerCrop()
                    .fit()
                    .placeholder( R.drawable.temp_image )
                    .into( mAlbumPreview );
    
  7. Не забудьте добавить в манифест разрешение на чтение внешнего хранилища:

    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    

Вот и все. Вы готовы идти! Удачи!

person Barakuda    schedule 11.08.2016
comment
Это очень полезно! - person Nikhil Solanki; 27.07.2018
comment
есть ли причина, по которой вы предпочитаете вектор, а не список? - person Rafsanjani; 21.01.2020
comment
Все методы Vector синхронизированы. Но методы ArrayList не синхронизируются. В проекте, в котором я это написал, это было необходимо. Вы также можете использовать ArrayList. - person Barakuda; 21.01.2020
comment
Ух ты!! большое спасибо, это сэкономило мне столько времени, оно на самом деле работает отлично - person ravid rinek; 31.03.2021

Я нашел способ получать альбомы, не перебирая каждую фотографию.

 String[] projection = new String[]{
                "COUNT(*) as count",
                MediaStore.Images.ImageColumns.BUCKET_DISPLAY_NAME,
                MediaStore.Images.ImageColumns.DATA,
                "MAX (" + MediaStore.Images.ImageColumns.DATE_TAKEN + ") as max"};

 Context context = ServiceProvider.getInstance().getApplicationContext();
 Cursor cursor = context.getContentResolver().query(
                MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                projection,
                "1) GROUP BY (" + MediaStore.Images.ImageColumns.BUCKET_DISPLAY_NAME,
                null,
                "max DESC");

курсор будет содержать столько элементов, сколько существует отдельного имени корзины, а также вы можете получить количество внутри каждой позиции курсора, чтобы получить количество изображений внутри альбома

вот пример:

if (cursor != null) {
            if (cursor.moveToFirst()) {
                do {
                //gets image path, it will always be a latest image because of sortOrdering by MAX date_taken
                String path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
                //gets count via alias ("as count" in projection)
                int count = cursor.getInt(cursor.getColumnIndex("count"));

                //do you logic here
                ...

                } while (cursor.moveToNext());
            }

            cursor.close();
        }

Некоторое объяснение параметра выбора:

contentResolver добавляет круглые скобки при компиляции результирующего запроса для sqlLite, поэтому, если мы сделаем выбор, например

"ГРУППИРОВАТЬ ПО" + MediaStore.Images.ImageColumns.BUCKET_DISPLAY_NAME

он будет скомпилирован как «WHERE (GROUP BY Bucket_display_name)» и вызовет исключение SQLiteException во время выполнения. В противном случае, если мы сделаем выбор, например

"1) СГРУППИРОВАТЬ ПО (" + MediaStore.Images.ImageColumns.BUCKET_DISPLAY_NAME

он будет скомпилирован как «WHERE (1) GROUP BY (bucket_display_name)», что правильно

person Nikita Fedrunov    schedule 19.09.2018

Загрузите исходный код отсюда (Получить все изображения из галереи в Android программно)

activity_main.xml

<RelativeLayout android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#ffffff"
    xmlns:android="http://schemas.android.com/apk/res/android">


    <GridView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/gv_folder"
        android:numColumns="2"
        android:layout_marginLeft="10dp"
        android:layout_marginRight="10dp"></GridView>


</RelativeLayout>

MainActivity.java

package galleryimages.galleryimages;

import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.net.Uri;
import android.provider.MediaStore;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.GridView;
import android.widget.Toast;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {
    public static ArrayList<Model_images> al_images = new ArrayList<>();
    boolean boolean_folder;
    Adapter_PhotosFolder obj_adapter;
    GridView gv_folder;
    private static final int REQUEST_PERMISSIONS = 100;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        gv_folder = (GridView)findViewById(R.id.gv_folder);

        gv_folder.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
                Intent intent = new Intent(getApplicationContext(), PhotosActivity.class);
                intent.putExtra("value",i);
                startActivity(intent);
            }
        });


        if ((ContextCompat.checkSelfPermission(getApplicationContext(),
                Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) && (ContextCompat.checkSelfPermission(getApplicationContext(),
                Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED)) {
            if ((ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this,
                    Manifest.permission.WRITE_EXTERNAL_STORAGE)) && (ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this,
                    Manifest.permission.READ_EXTERNAL_STORAGE))) {

            } else {
                ActivityCompat.requestPermissions(MainActivity.this,
                        new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE},
                        REQUEST_PERMISSIONS);
            }
        }else {
            Log.e("Else","Else");
            fn_imagespath();
        }



    }

    public ArrayList<Model_images> fn_imagespath() {
        al_images.clear();

        int int_position = 0;
        Uri uri;
        Cursor cursor;
        int column_index_data, column_index_folder_name;

        String absolutePathOfImage = null;
        uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;

        String[] projection = {MediaStore.MediaColumns.DATA, MediaStore.Images.Media.BUCKET_DISPLAY_NAME};

        final String orderBy = MediaStore.Images.Media.DATE_TAKEN;
        cursor = getApplicationContext().getContentResolver().query(uri, projection, null, null, orderBy + " DESC");

        column_index_data = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA);
        column_index_folder_name = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.BUCKET_DISPLAY_NAME);
        while (cursor.moveToNext()) {
            absolutePathOfImage = cursor.getString(column_index_data);
            Log.e("Column", absolutePathOfImage);
            Log.e("Folder", cursor.getString(column_index_folder_name));

            for (int i = 0; i < al_images.size(); i++) {
                if (al_images.get(i).getStr_folder().equals(cursor.getString(column_index_folder_name))) {
                    boolean_folder = true;
                    int_position = i;
                    break;
                } else {
                    boolean_folder = false;
                }
            }


            if (boolean_folder) {

                ArrayList<String> al_path = new ArrayList<>();
                al_path.addAll(al_images.get(int_position).getAl_imagepath());
                al_path.add(absolutePathOfImage);
                al_images.get(int_position).setAl_imagepath(al_path);

            } else {
                ArrayList<String> al_path = new ArrayList<>();
                al_path.add(absolutePathOfImage);
                Model_images obj_model = new Model_images();
                obj_model.setStr_folder(cursor.getString(column_index_folder_name));
                obj_model.setAl_imagepath(al_path);

                al_images.add(obj_model);


            }


        }


        for (int i = 0; i < al_images.size(); i++) {
            Log.e("FOLDER", al_images.get(i).getStr_folder());
            for (int j = 0; j < al_images.get(i).getAl_imagepath().size(); j++) {
                Log.e("FILE", al_images.get(i).getAl_imagepath().get(j));
            }
        }
        obj_adapter = new Adapter_PhotosFolder(getApplicationContext(),al_images);
        gv_folder.setAdapter(obj_adapter);
        return al_images;
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);

        switch (requestCode) {
            case REQUEST_PERMISSIONS: {
                for (int i = 0; i < grantResults.length; i++) {
                    if (grantResults.length > 0 && grantResults[i] == PackageManager.PERMISSION_GRANTED) {
                        fn_imagespath();
                    } else {
                        Toast.makeText(MainActivity.this, "The app was not allowed to read or write to your storage. Hence, it cannot function properly. Please consider granting it this permission", Toast.LENGTH_LONG).show();
                    }
                }
            }
        }
    }

}
person Deepshikha Puri    schedule 22.03.2017

person    schedule
comment
Не забудьте добавить ‹uses-permission android:name=android.permission.READ_EXTERNAL_STORAGE /› в свой манифест. - person Tony Wickham; 12.07.2014