Làm cách nào để chọn một hình ảnh từ thư viện (Thẻ SD) cho ứng dụng của tôi?


343

Câu hỏi này ban đầu được hỏi cho Android 1.6.

Tôi đang làm việc trên các tùy chọn hình ảnh trong ứng dụng của tôi.

Tôi có một nút và ImageView trong Hoạt động của mình. Khi tôi nhấp vào nút, nó sẽ chuyển hướng đến thư viện và tôi có thể chọn một hình ảnh. Hình ảnh được chọn sẽ xuất hiện trong ImageView của tôi.


1
Nhìn vào câu trả lời này, tôi đã đăng một mã được cải tiến ở đó để xử lý các lựa chọn từ người quản lý tệp cũng stackoverflow.com/questions/2169649/ Kẻ
điên

Câu trả lời:


418

Cập nhật câu trả lời, gần 5 năm sau:

Mã trong câu trả lời ban đầu không còn hoạt động đáng tin cậy nữa, vì hình ảnh từ nhiều nguồn khác nhau đôi khi trả về với một URI nội dung khác, tức là content://thay vì file://. Một giải pháp tốt hơn là chỉ cần sử dụngcontext.getContentResolver().openInputStream(intent.getData()) , vì điều đó sẽ trả về InputStream mà bạn có thể xử lý khi bạn chọn.

Ví dụ, BitmapFactory.decodeStream() hoạt động hoàn hảo trong tình huống này, vì sau đó bạn cũng có thể sử dụng trường Tùy chọn và inSampleSize để giảm mẫu hình ảnh lớn và tránh các vấn đề về bộ nhớ.

Tuy nhiên, những thứ như Google Drive trả lại URI cho hình ảnh chưa thực sự được tải xuống. Do đó, bạn cần thực hiện mã getContentResolver () trên một luồng nền.


Câu trả lời gốc:

Các câu trả lời khác giải thích cách gửi ý định, nhưng họ không giải thích tốt cách xử lý phản hồi. Đây là một số mã mẫu về cách làm điều đó:

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);
        }
    }
}

Sau này, bạn đã có hình ảnh đã chọn được lưu trữ trong "yourSelectedImage" để làm bất cứ điều gì bạn muốn. Mã này hoạt động bằng cách lấy vị trí của hình ảnh trong cơ sở dữ liệu ContentResolver, nhưng bản thân nó không đủ. Mỗi hình ảnh có khoảng 18 cột thông tin, từ filepath đến 'ngày sửa đổi lần cuối' đến tọa độ GPS của nơi bức ảnh được chụp, mặc dù nhiều trường không thực sự được sử dụng.

Để tiết kiệm thời gian vì bạn không thực sự cần các trường khác, tìm kiếm con trỏ được thực hiện bằng bộ lọc. Bộ lọc hoạt động bằng cách chỉ định tên của cột bạn muốn, MediaStore.Images.Media.DATA, là đường dẫn, sau đó đưa chuỗi đó [] cho truy vấn con trỏ. Truy vấn con trỏ trả về với đường dẫn, nhưng bạn không biết nó nằm trong cột nào cho đến khi bạn sử dụng columnIndexmã. Điều đó chỉ đơn giản là lấy số cột dựa trên tên của nó, cùng một cột được sử dụng trong quá trình lọc. Khi bạn đã có được điều đó, cuối cùng bạn cũng có thể giải mã hình ảnh thành một bitmap với dòng mã cuối cùng tôi đưa ra.


4
con trỏ.moveToFirst () cần được kiểm tra sự tồn tại: if (con trỏ.moveToFirst ()) {làm gì đó với dữ liệu con trỏ}
mishkin

14
Thay vì con trỏ, bạn nên lấy hình ảnh theo cách này: Bitmap b = MediaStore.Images.Media.getBitmap (this.getContentResolver (), chọnImage);
Luigi Agosti

4
Luigi, nếu Bitmap lớn MediaStore.Images.Media.getBitmap () có thể gây ra ngoại lệ OutOfMemory. Phương pháp của Steve cho phép thu nhỏ hình ảnh xuống trước khi tải nó vào bộ nhớ.
Frank Harper

9
điều này không hiệu quả với tôi, tôi nhận được null từ con trỏ.getString (cột Index);
Alexis Pautrot

9
Cẩn thận với phương pháp này: tên tệp sẽ là 'null' khi người dùng chọn ảnh từ album picasa hoặc từ ứng dụng Google+ Photos.
Ciske Boekelo

315
private static final int SELECT_PHOTO = 100;

Bắt đầu ý định

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

Kết quả quá trình

@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);
        }
    }
}

Ngoài ra, bạn cũng có thể giảm mẫu hình ảnh của mình để tránh các lỗi 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
đặt một jpeg 1,5 MB vào chế độ xem hình ảnh 100px x 100px nhỏ của tôi dẫn đến VM bị lỗi bộ nhớ. Downsampling đã khắc phục vấn đề đó :-)
Ai đó ở đâu đó vào

1
Chào. Không nên đóng cả hai luồng?
Denis Kniazhev

Xin chào @ siamii..Tôi đã theo dõi mã của bạn..nhưng nó hoạt động một phần đối với tôi .. :( khi hình ảnh được chọn từ thư viện trong phần hình ảnh được chụp, thì nó sẽ báo lỗi json, nhưng khi hình ảnh được chọn từ thư viện trong phần bluetooth hình ảnh được truy cập và gửi đến máy chủ..có thể bạn vui lòng kiểm tra liên kết này và đề nghị cho tôi bất kỳ giải pháp nào vui lòng ... stackoverflow.com/questions/29234409/image-is-not-uploaded
Mitchs

Phần tìm kiếm thang đo có thể được viết là:int scale = 1; for ( ; bfOptions.outWidth / scale > TARGET_SIZE && bfOptions.outWidth > TARGET_SIZE; scale*=2);
The_Rafi 22/03/2016

@siamii Ở đâu và làm thế nào để gọi phương thức này -------- decodeUri
Akshay Kumar

87

Bạn phải bắt đầu ý định thư viện cho một kết quả.

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

Sau đó onActivityForResult, gọi intent.getData()để lấy Uri của hình ảnh. Sau đó, bạn cần lấy Hình ảnh từ ContentProvider.


ACTION_PICK khác với ACTION_GET_CONTENT được sử dụng như thế nào trong hai câu trả lời khác?
chim cánh cụt359

4
Với ACTION_PICK, bạn chỉ định một URI cụ thể và với ACTION_GET_CONTENT, bạn chỉ định mime_type. Tôi đã sử dụng ACTION_PICK vì câu hỏi là hình ảnh cụ thể từ SDCARD chứ không phải tất cả hình ảnh.
Ao Robby

2
Mát mẻ. Đây chính xác là những gì tôi cần và hoạt động như một bùa mê :) Tự hỏi từ nơi các bạn tìm thấy thứ này :)
Jayshil Dave

@WilliamKinaan ACTIVITY_SELECT_IMAGE là bất kỳ giá trị int nào bạn chỉ định để xác định kết quả mà bạn mong muốn nhận được. Sau đó, nó được gửi lại trong onActivityResult (int requestCode, int resultCode, Intent data) dưới dạng 'requestCode'.
Fydo

@Fydo Tôi nhận ra rằng sau đó, Cảm ơn
William Kinaan

22

Đây là mã được thử nghiệm cho hình ảnh và video. Nó sẽ hoạt động cho tất cả các API nhỏ hơn 19 và lớn hơn 19.

Hình:

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);
                    }

Video:

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

Làm điều này để khởi chạy thư viện và cho phép người dùng chọn một hình ảnh:

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

Sau đó, khi bạn onActivityResult()sử dụng URI của hình ảnh được trả về để đặt hình ảnh trên ImageView của bạn.


3
Điều này sẽ không hoạt động cho các thiết bị Android 4.4. Nó sẽ khởi chạy màn hình tài liệu gần đây.
Noundla Sandeep

2
Đây là bản sửa lỗi cho KitKat: stackoverflow.com/a/26690628/860488
Morten Holmgaard

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

}

Đây là bản sửa lỗi cho KitKat: stackoverflow.com/a/26690628/860488
Morten Holmgaard

4

Vì một số lý do, tất cả các câu trả lời trong chuỗi này, onActivityResult()cố gắng xử lý hậu kỳ nhận được Uri, như lấy đường dẫn thực của hình ảnh và sau đó sử dụng BitmapFactory.decodeFile(path)để lấy Bitmap.

Bước này là không cần thiết. Các ImageViewlớp học có một phương pháp gọi là setImageURI(uri). Chuyển uri của bạn cho nó và bạn nên được thực hiện.

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

Để có một ví dụ hoạt động hoàn chỉnh, bạn có thể xem tại đây: http://androidbitmaps.blogspot.com/2015/04/loading-images-in-android-part-iii-pick.html

PS:
Lấy Bitmapmột biến riêng biệt sẽ có ý nghĩa trong trường hợp hình ảnh được tải quá lớn để phù hợp với bộ nhớ và cần phải thực hiện thao tác giảm tỷ lệ OurOfMemoryError, như thể hiện trong câu trả lời @siamii.


3

gọi phương thức selectImage như-

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);


}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.