【问题标题】:How to pick an image from gallery (SD Card) for my app?如何为我的应用从图库(SD 卡)中选择图像?
【发布时间】:2011-01-31 06:18:08
【问题描述】:

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

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

我的 Activity 中有一个按钮和一个 ImageView。当我单击该按钮时,它会重定向到画廊,我将能够选择一个图像。选定的图像将出现在我的 ImageView 中。

【问题讨论】:

标签: android android-image android-gallery


【解决方案1】:

近 5 年后更新的答案:

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

例如,BitmapFactory.decodeStream() 在这种情况下完美运行,因为您还可以使用 Options 和 inSampleSize 字段对大图像进行下采样并避免内存问题。

但是,Google Drive 之类的东西会将 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,即路径,然后将该字符串 [] 提供给游标查询。游标查询返回路径,但在使用columnIndex 代码之前您不知道它在哪一列。这只是根据其名称获取列的编号,与过滤过程中使用的相同。完成后,您终于可以使用我提供的最后一行代码将图像解码为位图了。

【讨论】:

  • cursor.moveToFirst() 应该检查是否存在: if (cursor.moveToFirst()) {do something with cursor data}
  • 您应该以这种方式获取图像,而不是光标:Bitmap b = MediaStore.Images.Media.getBitmap(this.getContentResolver(), selectedImage);
  • Luigi,如果位图很大 MediaStore.Images.Media.getBitmap() 可能会导致 OutOfMemory 异常。 Steve 的方法允许在将图像加载到内存之前缩小图像。
  • 这对我不起作用,我从 cursor.getString(columnIndex); 得到一个空值;
  • 谨慎使用此方法:当用户从 picasa 相册或 Google+ 照片应用中选择照片时,文件名将为“null”。
【解决方案2】:
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);

    }

【讨论】:

  • 将 1.5MB jpeg 放入我的 100 x 100 像素的小图像视图中会导致 VM 内存不足错误。下采样解决了这个问题:-)
  • 嗨。不应该关闭两个流吗?
  • 您好@siamii ..我遵循了您的代码..但它对我来说部分工作.. :(当从捕获的图像部分下的图库中选择图像时,它会给出 json 错误,但是当图像是从蓝牙部分下的图库中选择的图像被访问并发送到服务器..您能否检查此链接并建议我任何解决方案...stackoverflow.com/questions/29234409/image-is-not-uploaded
  • 查找比例的部分可以写成:int scale = 1; for ( ; bfOptions.outWidth / scale &gt; TARGET_SIZE &amp;&amp; bfOptions.outWidth &gt; TARGET_SIZE; scale*=2);
  • @siamii 在哪里以及如何调用这个方法-------- decodeUri
【解决方案3】:

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

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

然后在onActivityForResult,调用intent.getData()获取Image的Uri。然后你需要从 ContentProvider 中获取 Image。

【讨论】:

  • ACTION_PICK 与其他两个答案中使用的 ACTION_GET_CONTENT 有何不同?
  • 使用 ACTION_PICK 指定特定的 URI,使用 ACTION_GET_CONTENT 指定 mime_type。我使用 ACTION_PICK 是因为问题是 SDCARD 中的特定图像,而不是所有图像。
  • 酷。这正是我所需要的,并且像魅力一样工作 :) 想知道你们从哪里找到这些东西 :)
  • @WilliamKinaan ACTIVITY_SELECT_IMAGE 是您指定的任何 int 值,以识别您期望收到的结果。然后在 onActivityResult(int requestCode, int resultCode, Intent data) 作为“requestCode”发回。
  • @Fydo 后来我才意识到,谢谢
【解决方案4】:

这是一个经过测试的图像和视频代码。它适用于所有小于 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();
        }

【讨论】:

    【解决方案5】:

    执行此操作以启动图库并允许用户选择图像:

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

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

    【讨论】:

    • 这不适用于 Android 4.4 设备。它将启动最近的文档屏幕。
    • 这里是 KitKat 的修复:stackoverflow.com/a/26690628/860488
    【解决方案6】:
    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);
    }
    
    }
    

    【讨论】:

      【解决方案7】:
      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
      【解决方案8】:

      由于某些原因,此线程中的所有答案,在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 答案中所示。

      【讨论】:

        【解决方案9】:

        调用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();
            }
        }
        

        【讨论】:

          【解决方案10】:
          #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);
          
          
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2012-07-26
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多