如何从图库(SD卡)中为我的应用程序选择图像?


343

该问题最初是针对Android 1.6提出的。

我正在我的应用程序中处理照片选项。

我的活动中有一个按钮和一个ImageView。当我单击按钮时,它将重定向到图库,并且我可以选择图像。所选图像将出现在我的ImageView中。


1
看看这个答案,我在那儿发布了一个改进的代码来处理文件管理器的选择stackoverflow.com/questions/2169649/…–
疯狂

Answers:


418

更新答案,将近5年后:

原始答案中的代码不再可靠运行,因为来自各种来源的图像有时会返回不同的内容URI,content://而不是file://。更好的解决方案是简单地使用context.getContentResolver().openInputStream(intent.getData()),因为这将返回一个InputStream,您可以根据自己的选择进行处理。

例如,BitmapFactory.decodeStream()在这种情况下可以很好地工作,因为您还可以使用“选项”和“ inSampleSize”字段对大图像进行降采样并避免内存问题。

但是,诸如Google云端硬盘之类的东西会将URI返回到尚未实际下载的图像。因此,您需要在后台线程上执行getContentResolver()代码。


原始答案:

其他答案解释了如何发送意图,但没有很好地解释如何处理响应。以下是一些有关如何执行此操作的示例代码:

protected void onActivityResult(int requestCode, int resultCode, 
       Intent imageReturnedIntent) {
    super.onActivityResult(requestCode, resultCode, imageReturnedIntent); 

    switch(requestCode) { 
    case REQ_CODE_PICK_IMAGE:
        if(resultCode == RESULT_OK){  
            Uri selectedImage = imageReturnedIntent.getData();
            String[] filePathColumn = {MediaStore.Images.Media.DATA};

            Cursor cursor = getContentResolver().query(
                               selectedImage, filePathColumn, null, null, null);
            cursor.moveToFirst();

            int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
            String filePath = cursor.getString(columnIndex);
            cursor.close();


            Bitmap yourSelectedImage = BitmapFactory.decodeFile(filePath);
        }
    }
}

之后,您将选择的图像存储在“ yourSelectedImage”中,以进行所需的操作。这段代码通过获取图像在ContentResolver数据库中的位置来工作,但仅靠它是不够的。每个图像大约有18列信息,从文件路径到“最后修改日期”再到照片拍摄地的GPS坐标,尽管实际上并未使用许多字段。

为了节省时间,因为您实际上不需要其他字段,所以使用过滤器来进行光标搜索。筛选器的工作方式是指定所需的列名称MediaStore.Images.Media.DATA(即路径),然后将该string []赋予光标查询。游标查询返回路径,但是直到使用columnIndex代码,您才知道它位于哪一列。这只是根据其名称获取列号,该名称与过滤过程中使用的相同。一旦知道了这一点,您就可以使用我给出的最后一行代码将图像解码为位图。


4
应该检查cursor.moveToFirst()是否存在:if(cursor.moveToFirst()){用游标数据做某事}
mishkin 2011年

14
而不是光标,您应该通过这种方式获取图像:位图b = MediaStore.Images.Media.getBitmap(this.getContentResolver(),selectedImage);
路易吉·阿戈斯蒂

4
Luigi,如果位图较大,则MediaStore.Images.Media.getBitmap()可能导致OutOfMemory异常。史蒂夫(Steve)的方法允许将图像缩小后再加载到内存中。
弗兰克·哈珀

9
这对我不起作用,我从cursor.getString(columnIndex);中得到一个null。
Alexis Pautrot 2013年

9
请谨慎使用此方法:当用户从picasa相册或Google+相册应用中选择照片时,文件名将为“ null”。
Ciske Boekelo 2014年

315
private static final int SELECT_PHOTO = 100;

开始意图

Intent photoPickerIntent = new Intent(Intent.ACTION_PICK);
photoPickerIntent.setType("image/*");
startActivityForResult(photoPickerIntent, SELECT_PHOTO);    

处理结果

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent imageReturnedIntent) { 
    super.onActivityResult(requestCode, resultCode, imageReturnedIntent); 

    switch(requestCode) { 
    case SELECT_PHOTO:
        if(resultCode == RESULT_OK){  
            Uri selectedImage = imageReturnedIntent.getData();
            InputStream imageStream = getContentResolver().openInputStream(selectedImage);
            Bitmap yourSelectedImage = BitmapFactory.decodeStream(imageStream);
        }
    }
}

或者,您也可以降低图像的采样率,以避免OutOfMemory错误。

private Bitmap decodeUri(Uri selectedImage) throws FileNotFoundException {

        // Decode image size
        BitmapFactory.Options o = new BitmapFactory.Options();
        o.inJustDecodeBounds = true;
        BitmapFactory.decodeStream(getContentResolver().openInputStream(selectedImage), null, o);

        // The new size we want to scale to
        final int REQUIRED_SIZE = 140;

        // Find the correct scale value. It should be the power of 2.
        int width_tmp = o.outWidth, height_tmp = o.outHeight;
        int scale = 1;
        while (true) {
            if (width_tmp / 2 < REQUIRED_SIZE
               || height_tmp / 2 < REQUIRED_SIZE) {
                break;
            }
            width_tmp /= 2;
            height_tmp /= 2;
            scale *= 2;
        }

        // Decode with inSampleSize
        BitmapFactory.Options o2 = new BitmapFactory.Options();
        o2.inSampleSize = scale;
        return BitmapFactory.decodeStream(getContentResolver().openInputStream(selectedImage), null, o2);

    }

8
将1.5MB jpeg放入我的小100px x 100px imageview中会导致VM内存不足错误。下采样解决了该问题:-)
某处某人

1
你好 两个流都不应该关闭吗?
Denis Kniazhev 2014年

您好@siamii ..我遵循了您的代码..但是它对我来说部分有用..:((当从捕获的图像部分下的图库中选择图像时,它给出了json错误,但是当从蓝牙部分的画廊中选择了图像时图像已访问并发送到服务器..请您检查一下此链接并向我提出任何解决方案... stackoverflow.com/questions/29234409/image-is-not-uploaded
Prabs 2015年

有关查找音阶的部分可以写为:int scale = 1; for ( ; bfOptions.outWidth / scale > TARGET_SIZE && bfOptions.outWidth > TARGET_SIZE; scale*=2);
The_Rafi '16

@siamii在何处以及如何调用此方法-------- encodeUri
Akshay Kumar

87

您必须启动图库意图才能获得结果。

Intent i = new Intent(Intent.ACTION_PICK,
               android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(i, ACTIVITY_SELECT_IMAGE); 

然后在 onActivityForResult,调用intent.getData()获取图像的Uri。然后,您需要从ContentProvider获取图像。


ACTION_PICK与其他两个答案中使用的ACTION_GET_CONTENT有何不同?
penguin359

4
使用ACTION_PICK可以指定特定的URI,使用ACTION_GET_CONTENT可以指定mime_type。我使用ACTION_PICK,因为问题专门来自SDCARD的图像,而不是所有图像。
罗比·庞德

2
凉。这正是我需要的,并且像魅力一样起作用:)想知道你们从哪里找到这个东西的:)
Jayshil Dave 2011年

@WilliamKinaan ACTIVITY_SELECT_IMAGE是您指定的任何int值,以标识您期望接收的结果。然后将其作为“ requestCode”发送回onActivityResult(int requestCode,int resultCode,Intent data)中。
Fydo

@Fydo我意识到后来,谢谢
William Kinaan 2013年

22

这是一个经过测试的图像和视频代码,适用于所有小于19和大于19的API。

图片:

if (Build.VERSION.SDK_INT <= 19) {
                        Intent i = new Intent();
                        i.setType("image/*");
                        i.setAction(Intent.ACTION_GET_CONTENT);
                        i.addCategory(Intent.CATEGORY_OPENABLE);
                        startActivityForResult(i, 10);
                    } else if (Build.VERSION.SDK_INT > 19) {
                        Intent intent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
                        startActivityForResult(intent, 10);
                    }

视频:

if (Build.VERSION.SDK_INT <= 19) {
                        Intent i = new Intent();
                        i.setType("video/*");
                        i.setAction(Intent.ACTION_GET_CONTENT);
                        i.addCategory(Intent.CATEGORY_OPENABLE);
                        startActivityForResult(i, 20);
                    } else if (Build.VERSION.SDK_INT > 19) {
                        Intent intent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Video.Media.EXTERNAL_CONTENT_URI);
                        startActivityForResult(intent, 20);
                    }    

     @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode == Activity.RESULT_OK) {               
            if (requestCode == 10) {
                Uri selectedImageUri = data.getData();
                String selectedImagePath = getRealPathFromURI(selectedImageUri);
            } else if (requestCode == 20) {
                Uri selectedVideoUri = data.getData();
                String selectedVideoPath = getRealPathFromURI(selectedVideoUri);
            }
        }
     }

     public String getRealPathFromURI(Uri uri) {
            if (uri == null) {
                return null;
            }
            String[] projection = {MediaStore.Images.Media.DATA};
            Cursor cursor = getActivity().getContentResolver().query(uri, projection, null, null, null);
            if (cursor != null) {
                int column_index = cursor
                        .getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
                cursor.moveToFirst();
                return cursor.getString(column_index);
            }
            return uri.getPath();
        }

14

这样做以启动图库并允许用户选择图像:

Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
startActivityForResult(intent, IMAGE_PICK);

然后在您onActivityResult()使用返回的图像的URI来在ImageView上设置图像。


3
这不适用于Android 4.4设备。它将启动“最近文档”屏幕。
Noundla Sandeep

2
这是KitKat的修复程序:stackoverflow.com/a/26690628/860488
Morten Holmgaard,2014年

11
public class EMView extends Activity {
ImageView img,img1;
int column_index;
  Intent intent=null;
// Declare our Views, so we can access them later
String logo,imagePath,Logo;
Cursor cursor;
//YOU CAN EDIT THIS TO WHATEVER YOU WANT
private static final int SELECT_PICTURE = 1;

 String selectedImagePath;
//ADDED
 String filemanagerstring;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    img= (ImageView)findViewById(R.id.gimg1);



    ((Button) findViewById(R.id.Button01))
    .setOnClickListener(new OnClickListener() {

        public void onClick(View arg0) {

            // in onCreate or any event where your want the user to
            // select a file
            Intent intent = new Intent();
            intent.setType("image/*");
            intent.setAction(Intent.ACTION_GET_CONTENT);
            startActivityForResult(Intent.createChooser(intent,
                    "Select Picture"), SELECT_PICTURE);


        }
    });
}

//UPDATED
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (resultCode == Activity.RESULT_OK) {
        if (requestCode == SELECT_PICTURE) {
            Uri selectedImageUri = data.getData();

            //OI FILE Manager
            filemanagerstring = selectedImageUri.getPath();

            //MEDIA GALLERY
            selectedImagePath = getPath(selectedImageUri);


            img.setImageURI(selectedImageUri);

           imagePath.getBytes();
           TextView txt = (TextView)findViewById(R.id.title);
           txt.setText(imagePath.toString());


           Bitmap bm = BitmapFactory.decodeFile(imagePath);

          // img1.setImageBitmap(bm);



        }

    }

}

//UPDATED!
public String getPath(Uri uri) {
String[] projection = { MediaColumns.DATA };
Cursor cursor = managedQuery(uri, projection, null, null, null);
column_index = cursor
        .getColumnIndexOrThrow(MediaColumns.DATA);
cursor.moveToFirst();
 imagePath = cursor.getString(column_index);

return cursor.getString(column_index);
}

}

8
public class BrowsePictureActivity extends Activity {
private static final int SELECT_PICTURE = 1;

private String selectedImagePath;

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    ((Button) findViewById(R.id.Button01))
            .setOnClickListener(new OnClickListener() {

                public void onClick(View arg0) {

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

public void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (resultCode == RESULT_OK) {
        if (requestCode == SELECT_PICTURE) {
            Uri selectedImageUri = data.getData();
            selectedImagePath = getPath(selectedImageUri);
        }
    }
}

public String getPath(Uri uri) {

        if( uri == null ) {
            return null;
        }

        // this will only work for images selected from gallery
        String[] projection = { MediaStore.Images.Media.DATA };
        Cursor cursor = managedQuery(uri, projection, null, null, null);
        if( cursor != null ){
            int column_index = cursor
            .getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
            cursor.moveToFirst();
            return cursor.getString(column_index);
        }

        return uri.getPath();
}

}

这是KitKat的修复程序:stackoverflow.com/a/26690628/860488
Morten Holmgaard,2014年

4

由于某些原因,该线程中的所有答案都将onActivityResult()尝试对接收到的内容进行后处理Uri,例如获取图像的真实路径,然后使用BitmapFactory.decodeFile(path)来获取Bitmap

此步骤是不必要的。该ImageView班有一个叫方法setImageURI(uri)。将您的uri传递给它,您应该已完成。

Uri imageUri = data.getData();
imageView.setImageURI(imageUri);

对于完整的工作示例,您可以在此处查看:http : //androidbitmaps.blogspot.com/2015/04/loading-images-in-android-part-iii-pick.html

PS:如果要加载的图像太大而无法容纳在内存中,则必须
使用Bitmap单独的变量OurOfMemoryError,如@siamii答案所示,必须进行缩小操作以防止出现这种情况。


3

像这样调用chooseImage方法

public void chooseImage(ImageView v)
{
    Intent intent = new Intent(Intent.ACTION_PICK);
    intent.setType("image/*");
    startActivityForResult(intent, SELECT_PHOTO);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent imageReturnedIntent) {
    // TODO Auto-generated method stub
    super.onActivityResult(requestCode, resultCode, imageReturnedIntent);

    if(imageReturnedIntent != null)
    {
        Uri selectedImage = imageReturnedIntent.getData();
    switch(requestCode) { 
    case SELECT_PHOTO:
        if(resultCode == RESULT_OK)
        {
            Bitmap datifoto = null;
            temp.setImageBitmap(null);
            Uri picUri = null;
            picUri = imageReturnedIntent.getData();//<- get Uri here from data intent
             if(picUri !=null){
               try {
                   datifoto = android.provider.MediaStore.Images.Media.getBitmap(this.getContentResolver(),                                 picUri);
                   temp.setImageBitmap(datifoto);
               } catch (FileNotFoundException e) {
                  throw new RuntimeException(e);
               } catch (IOException e) {
                  throw new RuntimeException(e);
               } catch (OutOfMemoryError e) {
                Toast.makeText(getBaseContext(), "Image is too large. choose other", Toast.LENGTH_LONG).show();
            }

        }
        }
        break;

}
    }
    else
    {
        //Toast.makeText(getBaseContext(), "data null", Toast.LENGTH_SHORT).show();
    }
}

1
#initialize in main activity 
    path = Environment.getExternalStorageDirectory()
            + "/images/make_machine_example.jpg"; #
     ImageView image=(ImageView)findViewById(R.id.image);
 //--------------------------------------------------||

 public void FromCamera(View) {

    Log.i("camera", "startCameraActivity()");
    File file = new File(path);
    Uri outputFileUri = Uri.fromFile(file);
    Intent intent = new Intent(
            android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
    intent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);
    startActivityForResult(intent, 1);

}

public void FromCard() {
    Intent i = new Intent(Intent.ACTION_PICK,
            android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
    startActivityForResult(i, 2);
}

 protected void onActivityResult(int requestCode, int resultCode, Intent data) {

    super.onActivityResult(requestCode, resultCode, data);

    if (requestCode == 2 && resultCode == RESULT_OK
            && null != data) {

        Uri selectedImage = data.getData();
        String[] filePathColumn = { MediaStore.Images.Media.DATA };

        Cursor cursor = getContentResolver().query(selectedImage,
                filePathColumn, null, null, null);
        cursor.moveToFirst();

        int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
        String picturePath = cursor.getString(columnIndex);
        cursor.close();

        bitmap = BitmapFactory.decodeFile(picturePath);
        image.setImageBitmap(bitmap);

        if (bitmap != null) {
            ImageView rotate = (ImageView) findViewById(R.id.rotate);

        }

    } else {

        Log.i("SonaSys", "resultCode: " + resultCode);
        switch (resultCode) {
        case 0:
            Log.i("SonaSys", "User cancelled");
            break;
        case -1:
            onPhotoTaken();
            break;

        }

    }

}

protected void onPhotoTaken() {
    // Log message
    Log.i("SonaSys", "onPhotoTaken");
    taken = true;
    imgCapFlag = true;
    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inSampleSize = 4;
    bitmap = BitmapFactory.decodeFile(path, options);
    image.setImageBitmap(bitmap);


}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.