从安卓图库中选择多张图片

138 人关注

所以基本上我想实现的是在Android中打开 Gallery ,让用户选择 multiple images 。现在这个问题已经被问到了 frequently 但我对这些答案并不满意。主要是因为我在IDE的文档中发现了一些有趣的东西(我稍后再来讨论这个问题),因此我不想使用自定义的适配器,而只是使用普通的适配器。

现在我选择一张图片的代码是。

Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent,"Select Picture"), 1);

现在SO和其他网站上的人们会告诉你,你有两个选择。

1) Do not use ACTION_GET_CONTENT but ACTION_SEND_MULTIPLE instead.
这个不起作用。根据文档,这个是针对sending的文件,而不是retrieving,这也正是它的作用。当使用ACTION_SEND_MULTIPLE时,我的设备上打开了一个窗口,我必须选择一个应用程序来发送我的数据。这不是我想要的,所以我想知道人们是如何通过这个解决方案达到这个目的的。我错过了什么吗?

2) 实现一个custom Gallery。这是我考虑的最后一个选项,因为我认为这不是我想要的,因为我必须自己设计它,而且为什么你不能在香草画廊中选择多张图片?

一定有这样的选项。现在,我发现的有趣的事情是这样的。
I found this in the docs description of ACTION_GET_CONTENT.

如果调用者可以处理多个返回的项目(用户进行了 多重选择),那么它可以指定EXTRA_ALLOW_MULTIPLE来表示。 表示这一点。

这相当有趣。在这里,他们指的是用户可以选择多个项目的用例?

后来他们在文件中说。

你可以使用EXTRA_ALLOW_MULTIPLE来允许用户选择多个

所以这是很明显的,对吗?这就是我所需要的。但我的问题是:我可以把这个EXTRA_ALLOW_MULTIPLE放在哪里?可悲的是,我在书中找不到这个东西。开发者.安卓指南而且这也没有被定义为INTENT类中的一个常量。

有谁能帮我解决这个问题EXTRA_ALLOW_MULTIPLE

3 个评论
@KyleShank的解决方案对我有用。设置 EXTRA_ALLOW_MULTIPLE 让你选择多个项目。通过在 onActivityResult 中调用 getClipData() 来获得URI。唯一的问题是,画廊小部件不允许多选。在这种情况下,点击任何图片都会完成选择,你可以通过调用 getData 来获取(单个项目的)URI。
android
image-gallery
Dion Segijn
Dion Segijn
发布于 2013-10-25
15 个回答
Kyle Shank
Kyle Shank
发布于 2021-11-18
已采纳
0 人赞同

EXTRA_ALLOW_MULTIPLE选项是通过Intent.putExtra()方法在意图上设置的。

intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);

你上面的代码应该是这样的。

Intent intent = new Intent();
intent.setType("image/*");
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent,"Select Picture"), 1);

注意:EXTRA_ALLOW_MULTIPLE选项仅在Android API 18及以上版本中可用。

我知道这一点,但正如我在答案中提到的。"可悲的是,我在developer.android指南中没有找到这一点,而且这一点在INTENT类中也没有定义为常量。"我的IDE不能识别Intent.EXTRA_ALLOW_MULTIPLE。我安装的是API级别18。我的IDE说:"EXTRA_ALLOW_MULTIPLE不能被解决或不是一个字段"
对我来说,我不得不长按一张图片来开始选择更多。
John
它选择了多张图片。但如何从活动结果中获得图片的网址????。
这就启动了图片选取器,并允许我选择多张图片,但我不知道如何在onActivityResult中获得Url。
你可以在结果中得到urls Intent.getClipData 。它有一个ClipData Item的数组。
Laith Mihyar
Laith Mihyar
发布于 2021-11-18
0 人赞同

在类中定义这些变量。

int PICK_IMAGE_MULTIPLE = 1; 
String imageEncoded;    
List<String> imagesEncodedList;

假设点击一个按钮,它应该打开画廊来选择图片。

 Intent intent = new Intent();
 intent.setType("image/*");
 intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
 intent.setAction(Intent.ACTION_GET_CONTENT);
 startActivityForResult(Intent.createChooser(intent,"Select Picture"), PICK_IMAGE_MULTIPLE);

那么你应该覆盖onActivityResult方法

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    try {
        // When an Image is picked
        if (requestCode == PICK_IMAGE_MULTIPLE && resultCode == RESULT_OK
                    && null != data) {
            // Get the Image from data
            String[] filePathColumn = { MediaStore.Images.Media.DATA };
            imagesEncodedList = new ArrayList<String>();
            if(data.getData()!=null){
                Uri mImageUri=data.getData();
                // Get the cursor
                Cursor cursor = getContentResolver().query(mImageUri,
                            filePathColumn, null, null, null);
                // Move to first row
                cursor.moveToFirst();
                int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
                imageEncoded  = cursor.getString(columnIndex);
                cursor.close();
            } else {
                if (data.getClipData() != null) {
                    ClipData mClipData = data.getClipData();
                    ArrayList<Uri> mArrayUri = new ArrayList<Uri>();
                    for (int i = 0; i < mClipData.getItemCount(); i++) {
                        ClipData.Item item = mClipData.getItemAt(i);
                        Uri uri = item.getUri();
                        mArrayUri.add(uri);
                        // Get the cursor
                        Cursor cursor = getContentResolver().query(uri, filePathColumn, null, null, null);
                        // Move to first row
                        cursor.moveToFirst();
                        int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
                        imageEncoded  = cursor.getString(columnIndex);
                        imagesEncodedList.add(imageEncoded);
                        cursor.close();
                    Log.v("LOG_TAG", "Selected Images" + mArrayUri.size());
        } else {
            Toast.makeText(this, "You haven't picked Image",
                        Toast.LENGTH_LONG).show();
    } catch (Exception e) {
        Toast.makeText(this, "Something went wrong", Toast.LENGTH_LONG)
                    .show();
    super.onActivityResult(requestCode, resultCode, data);
画廊没有给你选择多张图片的能力,所以我们在这里打开所有图片工作室,你可以从中选择多张图片。
不要忘记在你的清单中添加权限。

非常重要。 getData();来获得一个单一的图像,我把它存储在imageEncoded String中。 如果用户选择多张图片,那么 它们应该被存储在列表中

所以你必须检查哪个是空的,以使用另一个

祝你有一个良好的尝试,并祝愿其他人

我跳过了 "intent.setType("image/*");",它直接把用户送到了Photo,而不是给用户一个去Gallery的机会,因为Gallery不允许选择多张图片。 不知道是不是因为这个原因,我的getData()从不返回null,所以我最后只用getClipData来进行单张和多张图片的选择。
只要使用data.getClipData()部分就足够了,不需要检查data.getData()。
Uri uri = content://com.android.providers.media.document/document/image%3A772 uri有数据但cursor.getString返回null给我 imageEncoded = cursor.getString(columnIndex)。
这很有用,但我不得不用这些函数来补充getPath。 stackoverflow.com/a/20559175/6141959
你用null != data而不是data != null,这让我的大脑崩溃了。
Mira_Cole
Mira_Cole
发布于 2021-11-18
0 人赞同

很多答案都有相似之处,但都缺少最重要的部分,即在 onActivityResult 中,检查 data.getClipData 是否为空。 before checking data.getData

调用文件选择器的代码。

Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*"); //allows any image file type. Change * to specific extension to limit it
//**The following line is the important one!
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
startActivityForResult(Intent.createChooser(intent, "Select Picture"), SELECT_PICTURES); //SELECT_PICTURES is simply a global int used to check the calling intent in onActivityResult

The code to get 所有选择的图像的。

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if(requestCode == SELECT_PICTURES) {
        if(resultCode == Activity.RESULT_OK) {
            if(data.getClipData() != null) {
                int count = data.getClipData().getItemCount(); //evaluate the count before the for loop --- otherwise, the count is evaluated every loop.
                for(int i = 0; i < count; i++) {
                    Uri imageUri = data.getClipData().getItemAt(i).getUri();
                    //do something with the image (save it to some directory or whatever you need to do with it here)
        } else if(data.getData() != null) {
            String imagePath = data.getData().getPath();
            //do something with the image (save it to some directory or whatever you need to do with it here)

Note that Android's chooser has Photos and G所有ery available on some devices. Photos 所有ows multiple images to be selected. G所有ery 所有ows just one at a time.

adi
什么是getClipData()? data.getData还不够吗?
在一些三星设备中,结果会与非三星设备不同。如果用户选择了多个文件, getData() 有时不会是空的,而只会有 one Uri。如果你想处理当一个用户选择了 multiple 文件,在 getData() 之前检查 getClipData() 。-- 如果剪辑数据不是空的,用户可能已经选择了多张图片。在getData之前处理getClipData,但处理 both 案例对于支持不同的设备,同时仍然允许多个Uris是很重要的。
@Mira_Code 如何将选定的图像设置为不同的图像视图。
ductran
ductran
发布于 2021-11-18
0 人赞同

我希望这个答案不会太迟。因为画廊小组件默认不支持多选,但你可以自定义网格视图,接受你的多选意图。另一个选择是扩展画廊视图,并加入你自己的代码以允许多选。
这是一个简单的库可以做到的。 https://github.com/luminousman/MultipleImagePick

From @ilsy's comment, 自定义画廊活动(CustomGalleryActivity 在这个库中使用了 manageQuery ,这已经被废弃了,所以应该改成 getContentResolver().query() cursor.close() ,例如 这个答案

@R4j 是的,我写过:这个库还没有准备好在项目中使用。需要许多更新才能开始使用它。关于你的更新:不要在UI线程中使用 getContentResolver().query() 。请阅读关于加载器和支持库的内容。
.cacheOnDisc() 也被废弃了,所以将其改为 .cacheOnDisc(true) ,带布尔参数。
Sheikh Hasib
Sheikh Hasib
发布于 2021-11-18
0 人赞同

初始化实例。

private String imagePath;
private List<String> imagePathList;

In onActivityResult你必须这样写,If-else 2块。一个用于单张图片,另一个用于多张图片。

if (requestCode == GALLERY_CODE && resultCode == RESULT_OK  && data != null) {
    imagePathList = new ArrayList<>();
    if (data.getClipData() != null) {
        int count = data.getClipData().getItemCount();
        for (int i=0; i<count; i++) {
            Uri imageUri = data.getClipData().getItemAt(i).getUri();
            getImageFilePath(imageUri);
    else if (data.getData() != null) {
        Uri imgUri = data.getData();
        getImageFilePath(imgUri);

最重要的部分。从URI中获取图像路径:

public void getImageFilePath(Uri uri) {
    File file = new File(uri.getPath());
    String[] filePath = file.getPath().split(":");
    String image_id = filePath[filePath.length - 1];
    Cursor cursor = getContentResolver().query(android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI, null, MediaStore.Images.Media._ID + " = ? ", new String[]{image_id}, null);
    if (cursor!=null) {
        cursor.moveToFirst();
        imagePath = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
        imagePathList.add(imagePath);
        cursor.close();

希望这能帮助你。

Vince
Vince
发布于 2021-11-18
0 人赞同

2022 - The Android Jetpack Compose way

用于在图库中用Android Jetpack Compose选择多张图片。

val launcherMultipleImages = rememberLauncherForActivityResult(
    contract = ActivityResultContracts.GetMultipleContents(),
) { uriList: List<Uri> ->
    // TODO

然后使用launcherMultipleImages.launch("image/*")开始选择图像。

例如: :

Button(onClick = { launcherMultipleImages.launch("image/*") }) {
    Text(text = "Select images")
    
如何限制GetMultipleContents的选择数? 例如,最多50张照片。
如何限制GetMultipleContents的选择数? 例如,最多50张照片。
如何限制GetMultipleContents的选择数? 例如,最多50张照片。
doli
doli
发布于 2021-11-18
0 人赞同

这对多张图片的选择是有效的。在谷歌照片的API 29,30中也进行了测试。

private static final int PICK_IMAGE = 2;
Intent intent = new Intent(Intent.ACTION_PICK, 
    android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
                intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
                startActivityForResult(Intent.createChooser(intent, "Select 
    images"),PICK_IMAGE);
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
if (requestCode == PICK_IMAGE && resultCode == RESULT_OK) {
        if(data.getClipData() != null) {
            int count = data.getClipData().getItemCount();
            for(int i = 0; i < count; i++) {
            Uri imageUri = data.getClipData().getItemAt(i).getUri();
            //do what do you want to do
        else if(data.getData() != null) {
            Uri selectedImageUri = data.getData();
            //do what do you want to do
    
Ahmet B.
Ahmet B.
发布于 2021-11-18
0 人赞同

定义getContent如下。

val getContent = 
registerForActivityResult(ActivityResultContracts.GetMultipleContents()) 
{ uriList ->
    // todo

在你授予相关权限后,运行以下代码

getContent.launch("images/*")
    
Sudarshan
Sudarshan
发布于 2021-11-18
0 人赞同

我从 Cursor 中得到了空。 然后找到一个解决方案,将 Uri 转换为 Bitmap ,效果非常好。

以下是对我有用的解决方案。

@Override
public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
    if (resultCode == Activity.RESULT_OK) {
        if (requestCode == YOUR_REQUEST_CODE) {
            if (data != null) {
                if (data.getData() != null) {
                    Uri contentURI = data.getData();
                    ex_one.setImageURI(contentURI);
                    Log.d(TAG, "onActivityResult: " + contentURI.toString());
                    try {
                        Bitmap bitmap = MediaStore.Images.Media.getBitmap(context.getContentResolver(), contentURI);
                    } catch (IOException e) {
                        e.printStackTrace();
                } else {
                    if (data.getClipData() != null) {
                        ClipData mClipData = data.getClipData();
                        ArrayList<Uri> mArrayUri = new ArrayList<Uri>();
                        for (int i = 0; i < mClipData.getItemCount(); i++) {
                            ClipData.Item item = mClipData.getItemAt(i);
                            Uri uri = item.getUri();
                            try {
                                Bitmap bitmap = MediaStore.Images.Media.getBitmap(context.getContentResolver(), uri);
                            } catch (IOException e) {
                                e.printStackTrace();
    
Ramesh Thangaraj
Ramesh Thangaraj
发布于 2021-11-18
0 人赞同

Hi below code is working fine.

 Cursor imagecursor1 = managedQuery(
    MediaStore.Images.Media.EXTERNAL_CONTENT_URI, columns, null,
    null, orderBy + " DESC");
   this.imageUrls = new ArrayList<String>();
  imageUrls.size();
   for (int i = 0; i < imagecursor1.getCount(); i++) {
   imagecursor1.moveToPosition(i);
   int dataColumnIndex = imagecursor1
     .getColumnIndex(MediaStore.Images.Media.DATA);
   imageUrls.add(imagecursor1.getString(dataColumnIndex));
   options = new DisplayImageOptions.Builder()
  .showStubImage(R.drawable.stub_image)
  .showImageForEmptyUri(R.drawable.image_for_empty_url)
  .cacheInMemory().cacheOnDisc().build();
   imageAdapter = new ImageAdapter(this, imageUrls);
   gridView = (GridView) findViewById(R.id.PhoneImageGrid);
  gridView.setAdapter(imageAdapter);

你想要更多的澄清。 http://mylearnandroid.blogspot.in/2014/02/multiple-choose-custom-gallery.html

如果它能工作,那就没问题。指出废弃的代码是好的,但只要你使用它没有任何问题,它就可以使用。重要的是要知道它为什么被废弃,是否是安全问题,更新的代码是否更有效,等等。但是,由于安卓应用程序是向前兼容的,被废弃的代码在未来仍然可以使用。
Gil Julio
Gil Julio
发布于 2021-11-18
0 人赞同

我也有同样的问题。我还想让用户在从图库中挑选照片时可以轻松地拍照。由于找不到本地的方法,我决定做一个开源项目。它很像MultipleImagePick,只是实现的方式更好。

https://github.com/giljulio/android-multiple-image-picker

private static final RESULT_CODE_PICKER_IMAGES = 9000;
Intent intent = new Intent(this, SmartImagePicker.class);
startActivityForResult(intent, RESULT_CODE_PICKER_IMAGES);
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    switch (requestCode){
        case RESULT_CODE_PICKER_IMAGES:
            if(resultCode == Activity.RESULT_OK){
                Parcelable[] parcelableUris = data.getParcelableArrayExtra(ImagePickerActivity.TAG_IMAGE_URI);
                //Java doesn't allow array casting, this is a little hack
                Uri[] uris = new Uri[parcelableUris.length];
                System.arraycopy(parcelableUris, 0, uris, 0, parcelableUris.length);
                //Do something with the uris array
            break;
        default:
            super.onActivityResult(requestCode, resultCode, data);
            break;
    
Tuan Chau
Tuan Chau
发布于 2021-11-18
0 人赞同

Try this one IntentChooser .只需添加几行代码,其余的我都帮你做了。

private void startImageChooserActivity() {
    Intent intent = ImageChooserMaker.newChooser(MainActivity.this)
            .add(new ImageChooser(true))
            .create("Select Image");
    startActivityForResult(intent, REQUEST_IMAGE_CHOOSER);
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == REQUEST_IMAGE_CHOOSER && resultCode == RESULT_OK) {
        List<Uri> imageUris = ImageChooserMaker.getPickMultipleImageResultUris(this, data);

PS: as mentioned at the answers above, EXTRA_ALLOW_MULTIPLE is only available for API >= 18. And some gallery apps don't make this feature available (Google Photos and Documents (com.android.documentsui) work.

即使添加了多个图片也不让我选择 intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
Mahmood Hussain
Mahmood Hussain
发布于 2021-11-18
0 人赞同
     // for choosing multiple images declare variables
     int PICK_IMAGE_MULTIPLE = 2;
     String realImagePath;
     // After requesting FILE READ PERMISSION may be on button click
     Intent intent = new Intent();
     intent.setType("image/*");
     intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
     intent.setAction(Intent.ACTION_GET_CONTENT);
     startActivityForResult(Intent.createChooser(intent,"Select Images"), PICK_IMAGE_MULTIPLE);
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);// FOR CHOOSING MULTIPLE IMAGES
        try {
            // When an Image is picked
            if (requestCode == PICK_IMAGE_MULTIPLE && resultCode == RESULT_OK
                    && null != data) {
                if (data.getClipData() != null) {
                    int count = data.getClipData().getItemCount(); //evaluate the count before the for loop --- otherwise, the count is evaluated every loop.
                    for (int i = 0; i < count; i++) {
                        Uri imageUri = data.getClipData().getItemAt(i).getUri();
                        realImagePath = getPath(this, imageUri);
                        //do something with the image (save it to some directory or whatever you need to do with it here)
                        Log.e("ImagePath", "onActivityResult: " + realImagePath);
                } else if (data.getData() != null) {
                    Uri imageUri = data.getData();
                    realImagePath = getPath(this, imageUri);
                    //do something with the image (save it to some directory or whatever you need to do with it here)
                    Log.e("ImagePath", "onActivityResult: " + realImagePath);
        } catch (Exception e) {
            Toast.makeText(this, "Something went wrong", Toast.LENGTH_LONG)
                    .show();
    public static String getPath(final Context context, final Uri uri) {
        // DocumentProvider
        if (DocumentsContract.isDocumentUri(context, uri)) {
            // ExternalStorageProvider
            if (isExternalStorageDocument(uri)) {
                final String docId = DocumentsContract.getDocumentId(uri);
                final String[] split = docId.split(":");
                final String type = split[0];
                if ("primary".equalsIgnoreCase(type)) {
                    return Environment.getExternalStorageDirectory() + "/" + split[1];
                // TODO handle non-primary volumes
            // DownloadsProvider
            else if (isDownloadsDocument(uri)) {
                final String id = DocumentsContract.getDocumentId(uri);
                final Uri contentUri = ContentUris.withAppendedId(
                        Uri.parse("content://downloads/public_downloads"), Long.parseLong(id));
                return getDataColumn(context, contentUri, null, null);
            // MediaProvider
            else if (isMediaDocument(uri)) {
                final String docId = DocumentsContract.getDocumentId(uri);
                final String[] split = docId.split(":");
                final String type = split[0];
                Uri contentUri = null;
                if ("image".equals(type)) {
                    contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
                } else if ("video".equals(type)) {
                    contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
                } else if ("audio".equals(type)) {
                    contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
                final String selection = "_id=?";
                final String[] selectionArgs = new String[]{
                        split[1]
                return getDataColumn(context, contentUri, selection, selectionArgs);
        // MediaStore (and general)
        else if ("content".equalsIgnoreCase(uri.getScheme())) {
            return getDataColumn(context, uri, null, null);
        // File
        else if ("file".equalsIgnoreCase(uri.getScheme())) {
            return uri.getPath();
        return null;
     * Get the value of the data column for this Uri. This is useful for
     * MediaStore Uris, and other file-based ContentProviders.
     * @param context       The context.
     * @param uri           The Uri to query.
     * @param selection     (Optional) Filter used in the query.
     * @param selectionArgs (Optional) Selection arguments used in the query.
     * @return The value of the _data column, which is typically a file path.
    public static String getDataColumn(Context context, Uri uri, String selection,
                                       String[] selectionArgs) {
        Cursor cursor = null;
        final String column = "_data";
        final String[] projection = {
                column
        try {
            cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs,
                    null);
            if (cursor != null && cursor.moveToFirst()) {
                final int column_index = cursor.getColumnIndexOrThrow(column);
                return cursor.getString(column_index);
        } finally {
            if (cursor != null)
                cursor.close();
        return null;
     * @param uri The Uri to check.
     * @return Whether the Uri authority is ExternalStorageProvider.
    public static boolean isExternalStorageDocument(Uri uri) {
        return "com.android.externalstorage.documents".equals(uri.getAuthority());
     * @param uri The Uri to check.
     * @return Whether the Uri authority is DownloadsProvider.
    public static boolean isDownloadsDocument(Uri uri) {
        return "com.android.providers.downloads.documents".equals(uri.getAuthority());
     * @param uri The Uri to check.
     * @return Whether the Uri authority is MediaProvider.
    public static boolean isMediaDocument(Uri uri) {
        return "com.android.providers.media.documents".equals(uri.getAuthority());

this worked perfectly for me credits: 从URI获取真实路径,Android KitKat新的存储访问框架

Shah0651
Shah0651
发布于 2021-11-18
0 人赞同

用于从画廊中选择多张图片

i.putExtra(Intent.EXTRA_ALLOW_MULTIPLE,true);

一个带有相机选项的多张图片上传的终极解决方案,也适用于Android Lollipop到Android 10,SDK 30。

private static final int FILECHOOSER_RESULTCODE   = 1;
private ValueCallback<Uri> mUploadMessage;
private ValueCallback<Uri[]> mUploadMessages;
private Uri mCapturedImageURI = null;

将此添加到MainActivity的OnCreate中

mWebView.setWebChromeClient(new WebChromeClient() {
            // openFileChooser for Android 3.0+
            public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType){
                mUploadMessage = uploadMsg;
                openImageChooser();
            // For Lollipop 5.0+ Devices
            public boolean onShowFileChooser(WebView mWebView, ValueCallback<Uri[]> filePathCallback, WebChromeClient.FileChooserParams fileChooserParams) {
                mUploadMessages = filePathCallback;
                openImageChooser();
                return true;
            // openFileChooser for Android < 3.0
            public void openFileChooser(ValueCallback<Uri> uploadMsg){
                openFileChooser(uploadMsg, "");
            //openFileChooser for other Android versions
            public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
                openFileChooser(uploadMsg, acceptType);
private void openImageChooser() {
    try {
        File imageStorageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "FolderName");
        if (!imageStorageDir.exists()) {
            imageStorageDir.mkdirs();
        File file = new File(imageStorageDir + File.separator + "IMG_" + String.valueOf(System.currentTimeMillis()) + ".jpg");
        mCapturedImageURI = Uri.fromFile(file);
        final Intent captureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        captureIntent.putExtra(MediaStore.EXTRA_OUTPUT, mCapturedImageURI);
        Intent i = new Intent(Intent.ACTION_GET_CONTENT);
        i.addCategory(Intent.CATEGORY_OPENABLE);
        i.setType("image/*");
        i.putExtra(Intent.EXTRA_ALLOW_MULTIPLE,true);
        Intent chooserIntent = Intent.createChooser(i, "Image Chooser");
        chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, new Parcelable[]{captureIntent});
        startActivityForResult(chooserIntent, FILECHOOSER_RESULTCODE);
    } catch (Exception e) {
        e.printStackTrace();

onActivityResult

public void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == FILECHOOSER_RESULTCODE) {
            if (null == mUploadMessage && null == mUploadMessages) {
                return;
            if (null != mUploadMessage) {
                handleUploadMessage(requestCode, resultCode, data);
            } else if (mUploadMessages != null) {
                handleUploadMessages(requestCode, resultCode, data);
    private void handleUploadMessage(final int requestCode, final int resultCode, final Intent data) {
        Uri result = null;
        try {
            if (resultCode != RESULT_OK) {
                result = null;
            } else {
                // retrieve from the private variable if the intent is null
                result = data == null ? mCapturedImageURI : data.getData();
        } catch (Exception e) {
            e.printStackTrace();
        mUploadMessage.onReceiveValue(result);
        mUploadMessage = null;
        // code for all versions except of Lollipop
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
                result = null;
                try {
                    if (resultCode != RESULT_OK) {
                        result = null;
                    } else {
                        // retrieve from the private variable if the intent is null
                        result = data == null ? mCapturedImageURI : data.getData();
                } catch (Exception e) {
                    Toast.makeText(getApplicationContext(), "activity :" + e, Toast.LENGTH_LONG).show();
                mUploadMessage.onReceiveValue(result);
                mUploadMessage = null;
        } // end of code for all versions except of Lollipop
    private void handleUploadMessages(final int requestCode, final int resultCode, final Intent data) {
        Uri[] results = null;
        try {
            if (resultCode != RESULT_OK) {
                results = null;
            } else {
                if (data != null) {
                    String dataString = data.getDataString();
                    ClipData clipData = data.getClipData();
                    if (clipData != null) {
                        results = new Uri[clipData.getItemCount()];
                        for (int i = 0; i < clipData.getItemCount(); i++) {
                            ClipData.Item item = clipData.getItemAt(i);
                            results[i] = item.getUri();
                    if (dataString != null) {
                        results = new Uri[]{Uri.parse(dataString)};
                } else {
                    results = new Uri[]{mCapturedImageURI};
        } catch (Exception e) {
            e.printStackTrace();
        mUploadMessages.onReceiveValue(results);