相册带有文件夹过滤器

9
我正在使用以下代码在我的应用程序中打开一个画廊。
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
startActivityForResult(intent, FIND_RESULT);

有可能限制图像列表只显示相机拍摄的图像吗?在我的2.1系统上查看画廊,图像被分组,因此必须有一个参数定义它属于哪个文件夹。
检查 MediaStore.Images.ImageColumns,我没有找到任何可以定义这种事情的列。
我可能错了吗?因为如果我能创建一个按文件夹筛选并创建自己的画廊视图的查询,那么我的问题就会得到解决。

@ FrEaKmAn:你找到答案了吗?如果是的话,请分享给我,我也需要。 - PiyushMishra
没有,我没有找到答案。 - FrEaKmAn
5个回答

8

您只需要在您的活动中实现MediaScannerConnectionClient, 然后将该文件夹中的一个文件的确切路径作为SCAN_PATH,并扫描该文件夹中包含的所有文件并在内置的相册中打开它。因此,只需给出您的文件夹名称,您将获得其中包括视频在内的所有文件。如果您只想打开图像,请更改FILE_TYPE="image/*"

public class SlideShow extends Activity implements MediaScannerConnectionClient {

        public String[] allFiles;
        private String SCAN_PATH ;
        private static final String FILE_TYPE = "*/*";
        private MediaScannerConnection conn;

        /** Called when the activity is first created. */
        @Override
        public void onCreate(Bundle savedInstanceState)
        {
            super.onCreate(savedInstanceState);

            setContentView(R.layout.main);

            File folder = new File("/sdcard/yourfoldername/");
            allFiles = folder.list();

            SCAN_PATH=Environment.getExternalStorageDirectory().toString()+"/yourfoldername/"+allFiles[0];

            Button scanBtn = (Button) findViewById(R.id.scanBtn);
            scanBtn.setOnClickListener(new OnClickListener()
            {
                public void onClick(View v)
                {
                    startScan();
                }
            });
        }

        private void startScan()
        {
            if(conn!=null)
            {
                conn.disconnect();
            }

            conn = new MediaScannerConnection(this, this);
            conn.connect();
        }


        public void onMediaScannerConnected()
        {
            conn.scanFile(SCAN_PATH, FILE_TYPE);    
        }


        public void onScanCompleted(String path, Uri uri)
        {
            try
            {
                if (uri != null) 
                {
                    Intent intent = new Intent(Intent.ACTION_VIEW);
                    intent.setData(uri);
                    startActivity(intent);
                }
            }
            finally 
            {
                conn.disconnect();
                conn = null;
            }
        }
    }

为什么它只显示一张图片?比如我有6张图片在文件夹里,如果我写allFiles[0],它会显示第1张图片,然后我写allFiles[1],它会显示第2张图片,以此类推。但是我想要同时显示所有的图片。 - Amandeep singh
你需要一个图库来一次性显示所有的图片。这个例子没有告诉你如何展示你的数据,它只是创建了一个包含该文件夹中所有文件路径的字符串数组。你可以在你的图库中使用这个字符串数组来展示你的图片。 - PiyushMishra
这将打开相册中特定的图片,而不是文件夹。 - Muhammad Hamza Shahid

5

以上答案都不正确,包括标记为正确的答案。

这是实际的正确解决方案:

秘密在于找到代表您文件夹的存储桶/相册。 存储桶出现在成功的MediaScan之后,因此请确保您想要显示的任何图像/视频首先按照上面多次演示的方式进行扫描。

假设我有一个索引文件夹位于 /sdcard/myapp/myappsmediafolder:

String bucketId = "";

final String[] projection = new String[] {"DISTINCT " + MediaStore.Images.Media.BUCKET_DISPLAY_NAME + ", " + MediaStore.Images.Media.BUCKET_ID};
final Cursor cur = getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, projection, null, null, null);

while (cur != null && cur.moveToNext()) {
    final String bucketName = cur.getString((cur.getColumnIndex(MediaStore.Images.ImageColumns.BUCKET_DISPLAY_NAME)));
    if (bucketName.equals("myappsmediafolder")) {
        bucketId = cur.getString((cur.getColumnIndex(MediaStore.Images.ImageColumns.BUCKET_ID)));
        break;
    }
}

现在我们已经得到了相册的bucketId,可以通过一个简单的意图打开它。
过滤视频文件:
Uri mediaUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;

筛选图片文件:

Uri mediaUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;

...

if (bucketId.length() > 0) {
    mediaUri = mediaUri.buildUpon()
            .authority("media")
            .appendQueryParameter("bucketId", bucketId)
            .build();
}

Intent intent = new Intent(Intent.ACTION_VIEW, mediaUri);
startActivity(intent);

我可以证实这个方法适用于内置的相册应用。对于其他应用,如Google相册,则可能效果不同。
我还没有找到如何取消过滤图像/视频的方法,即使在相册中您可以选择一个没有过滤器的特定相册。
我是通过查看AOSP源代码中的相册应用程序来解决这个问题的。

我已经点赞了。这个解决方案对API 5有效,但是对于API 6只显示1张照片。我必须滚动才能查看下一张照片。如何使其在API 6上工作?请告诉我。谢谢! - masiboo
有没有办法在同一个光标中获取图像和视频的组合文件夹名称? - Harsh Bhavsar
有没有想法如何在旧的API上实现它? Field requires API level 29: android.provider.MediaStore.MediaColumns#BUCKET_DISPLAY_NAME - Pat Lee

1
我没有足够的声望来点赞或评论他的答案,但是ShellDude的答案允许您在图库意图中放置一个目录URI。因此,当打开图库应用程序时,它会显示所有图像而不是一个。
对于我来说,像上面的答案一样扫描我的文件并不起作用。只有在使用ContentResolver向MediaStore.Images.Media.DATA表中插入新行后查询MediaStore.Images.Media.EXTERNAL_CONTENT_URI才起作用。
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.DATA, image.getPath());  
values.put(MediaStore.Images.Media.MIME_TYPE,"image/jpeg");
contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);

奇怪,我本来以为媒体扫描会为您完成上述操作。在您的文件夹路径中是否有.nomedia文件或类似文件? - ShellDude

0
这是一个简化版的。
private  MediaScannerConnection conn;
private void notifySystemWithImage(final File imageFile) {

        conn = new MediaScannerConnection(this, new MediaScannerConnectionClient() {

        @Override
        public void onScanCompleted(String path, Uri uri) {

            try {
                if (uri != null) {
                    Intent intent = new Intent(Intent.ACTION_VIEW);
                    intent.setDataAndType(uri, "image/*");
                    startActivity(intent);
                }
            } finally {
                conn.disconnect();
                conn = null;
            }
        }

        @Override
        public void onMediaScannerConnected() {
            conn.scanFile(imageFile.getAbsolutePath(), "*/*"); 

        }
    });

        conn.connect();
}

这会仅加载一个图像,而我需要给定文件夹中的所有图像。 - Farrakh Javed
它将在其文件夹中打开图像,您可以向右或向左滑动以查看其他图像。与画廊相同。 - Simon K. Gerges
我在 onScanCompleted 方法中得到了 null 的 Uri。 - Hanako

0

对于那些仍然遇到“未找到活动”异常的人:

您需要指定您内部应用程序文件夹的目录,而不是用户默认根目录,如果涉及到图片和其他内容。

public class SlideShow extends Activity implements MediaScannerConnectionClient {

        public String[] allFiles;
        private String SCAN_PATH ;
        private static final String FILE_TYPE = "*/*";
        private MediaScannerConnection conn;

        /** Called when the activity is first created. */
        @Override
        public void onCreate(Bundle savedInstanceState)
        {
            super.onCreate(savedInstanceState);

            setContentView(R.layout.main);

            File folder = new File(HistoryActivity.this.getExternalFilesDir(null)+"/a/");
            allFiles = folder.list();

            SCAN_PATH= HistoryActivity.this.getExternalFilesDir(null)+"/a/"+allFiles[0];

            Button scanBtn = (Button) findViewById(R.id.scanBtn);
            scanBtn.setOnClickListener(new OnClickListener()
            {
                public void onClick(View v)
                {
                    startScan();
                }
            });
        }

        private void startScan()
        {
            if(conn!=null)
            {
                conn.disconnect();
            }

            conn = new MediaScannerConnection(this, this);
            conn.connect();
        }


        public void onMediaScannerConnected()
        {
            conn.scanFile(SCAN_PATH, FILE_TYPE);    
        }


        public void onScanCompleted(String path, Uri uri)
        {
            try
            {
                if (uri != null) 
                {
                    Intent intent = new Intent(Intent.ACTION_VIEW);
                    intent.setData(uri);
                    startActivity(intent);
                }
            }
            finally 
            {
                conn.disconnect();
                conn = null;
            }
        }
    }

可以运行...但是KitKat只显示一张照片。我已经通过(在存储图像时更新画廊)来解决早期版本的问题:

public void savePhoto(Bitmap bmp)
{
    File imageFileFolder = new File(context.getExternalFilesDir(null)+"/a/") ;
    imageFileFolder.mkdir();
    FileOutputStream out = null;
    Calendar c = Calendar.getInstance();
    String date = fromInt(c.get(Calendar.MONTH))
            + fromInt(c.get(Calendar.DAY_OF_MONTH))
            + fromInt(c.get(Calendar.YEAR))
            + fromInt(c.get(Calendar.HOUR_OF_DAY))
            + fromInt(c.get(Calendar.MINUTE))
            + fromInt(c.get(Calendar.SECOND));
    File imageFileName = new File(imageFileFolder, date.toString() + ".jpg");
    try
    {
        out = new FileOutputStream(imageFileName);
        bmp.compress(Bitmap.CompressFormat.JPEG, 100, out);
        out.flush();
        out.close();
        scanPhoto(imageFileName.toString());
        out = null;
    } catch (Exception e)
    {
        e.printStackTrace();
    }
}


public String fromInt(int val)
{
    return String.valueOf(val);
}


public void scanPhoto(final String imageFileName)
{
    msConn = new MediaScannerConnection(context,new MediaScannerConnection.MediaScannerConnectionClient()
    {
        public void onMediaScannerConnected()
        {
            msConn.scanFile(imageFileName, null);
            Log.i("msClient obj  in Photo Utility", "connection established");
        }
        public void onScanCompleted(String path, Uri uri)
        {
            msConn.disconnect();
            Log.i("msClient obj in Photo Utility","scan completed");
        }
    });
    msConn.connect();
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接