【问题标题】:Working with camera in Android: Why is Cursor null when the picture is taken by camera and not selected from gallery?在 Android 中使用相机:当照片是由相机拍摄而不是从图库中选择时,为什么光标为空?
【发布时间】:2015-10-16 12:59:03
【问题描述】:

在我的应用中,用户可以从相机或图库中添加许多图像。 有一个 addPhoto 按钮,用户单击它,她可以选择相机或画廊,选择或拍照,然后将照片添加到页面中。这可以一直持续下去。

除了一件事之外,每件事都运行良好: 有些图像是纵向的,我需要旋转它们(因为 Android 会旋转它们并使它们变成横向,我必须将它们旋转回来)。但是我不能用相机图片来做,因为它们的光标是空的。

图像保存在设备上。 Uri 不是。我还应该检查什么? 我究竟做错了什么?奇怪的是,当从图库中选择图像时,一切都完美无缺!

这是处理图像的 Activity 的代码:

public class CreatePropertyActivity5 extends ActionBarActivity {
    protected static final int SELECT_PICTURE = 1;
    private static final int ACTIVITY_REQUEST_CODE_IMAGE = 100;
    private static final int IMAGE_DESCRIPTION = 200;

    private static List<File> cameraImageFiles;
    private static Bitmap selectedImageBitmap;
    private static LinearLayout ll; 
    private static int id = 0;
    private static int password = 0;

    private static JSONRequestForCreatePropertyListing propertyListing;
    private static ImageView imageView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_create_property_5);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);

        //if not null, means Android has killed the process while the user has been working with camera or gallery to add images, and the onCreate is called AGAIN. And we don't want to initialize the layout again cause we will loose our previously added photos.
        if (propertyListing==null) {
            propertyListing = (JSONRequestForCreatePropertyListing) getIntent().getSerializableExtra("JSONRequestForCreatePropertyListing");
            CreatePropertListingAsync cplp = new CreatePropertListingAsync(this, propertyListing);
            cplp.execute();
            ll = (LinearLayout) findViewById(R.id.llCreatePropertyImages);

        }
        else {
        //If Android has killed the activity once and this is the second time we are in onCreate(), the static ll which has the previously added images in it won't be attached to the xml page and so we have to add it manually.
            LinearLayout ll2 = (LinearLayout) findViewById(R.id.ll_activity_create_property);
            ((ViewGroup)ll.getParent()).removeView(ll);
            ll2.addView(ll);
        }

    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
    }
    public void onClickTakePicture(View v) throws IOException {
        // Camera.
        final List<Intent> cameraIntents = new ArrayList<Intent>();
        final Intent captureIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);     
        final PackageManager packageManager = getPackageManager();
        final List<ResolveInfo> listCam = packageManager.queryIntentActivities(captureIntent, 0);

        cameraImageFiles = new ArrayList<File>();

        int i=0;
        for(ResolveInfo res : listCam) {
            final String packageName = res.activityInfo.packageName;
            final Intent intent = new Intent(captureIntent);
            intent.setComponent(new ComponentName(res.activityInfo.packageName, res.activityInfo.name));
            intent.setPackage(packageName);
            intent.putExtra(MediaStore.MEDIA_IGNORE_FILENAME, ".nomedia");

            //** below 4 lines put the uri of the camera taken picture to the EXTRA_OUTPUT 
            File cameraImageOutputFile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "myFileName.jpg");
            cameraImageFiles.add(cameraImageOutputFile);
            intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(cameraImageFiles.get(i)));
            i++;

            cameraIntents.add(intent);
        }

        // Filesystem.
        final Intent galleryIntent = new Intent();
        galleryIntent.setType("image/*");
        galleryIntent.setAction(Intent.ACTION_GET_CONTENT);

        // Chooser of filesystem options.
        final Intent chooserIntent = Intent.createChooser(galleryIntent, "add new");

        // Add the camera options.
        chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, cameraIntents.toArray(new Parcelable[]{}));
        startActivityForResult(chooserIntent, ACTIVITY_REQUEST_CODE_IMAGE);

    }

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

        switch(requestCode) { 

        // For sending photos to server. We come here from activity51 when user clicks on send photo. This "case" happens second. 
        case IMAGE_DESCRIPTION:
            if(resultCode == RESULT_OK){
                //add the image to the activity5 page.
                imageView = new ImageView(this);
                imageView.setPadding(0, 10, 0, 0);
                ll.setVisibility(View.VISIBLE);
                if (findViewById(R.id.ll_create_property_successful)!= null)
                    findViewById(R.id.ll_create_property_successful).setVisibility(View.VISIBLE);
                imageView.setImageBitmap(selectedImageBitmap);
                ll.addView(imageView);

                if ((TextView) findViewById(R.id.txt_property_listing_code)!= null)
                    ((TextView) findViewById(R.id.txt_property_listing_code)).setText(""+id);
                if ((TextView)findViewById(R.id.txt_property_listing_password)!= null)
                    ((TextView) findViewById(R.id.txt_property_listing_password)).setText(""+password);

                String s = imageReturnedIntent.getStringExtra("key");
                //user entered description is in "key"
                imageView.setTag(s);
                Bitmap bitmap1 = ((BitmapDrawable)imageView.getDrawable()).getBitmap();
                ByteArrayOutputStream stream=new ByteArrayOutputStream();
                bitmap1.compress(Bitmap.CompressFormat.PNG, 90, stream);
                byte[] image=stream.toByteArray();
                String img_str = Base64.encodeToString(image, 0);

                //This part sends the picture to the server
                ArrayList<Photos> photos = new ArrayList<Photos>();
                photos.add(new Photos(new Ax(img_str)));


                //if not null, means Android has killed the process while the user has been working with camera or gallery to add images, and the onCreate is called AGAIN. And we don't want to initialize the layout again cause we will loose our previously added photos.
                JSONRequestForAddPhoto jr = new JSONRequestForAddPhoto(id, password, photos);

                new AddPhotoAsync(this, jr).execute();
            }

            //If user has pressed the cancel button and not the send photo button (in activity51) we come here and do nothing.
            break;
        //After the user has selected a photo (or taken one with camera) we come here :). This "case" happens first for a photo.
        case ACTIVITY_REQUEST_CODE_IMAGE:
            if(resultCode == RESULT_OK){

                Uri uri = null;
                if(imageReturnedIntent == null){   //since we used EXTRA_OUTPUT for camera, so it will be null

                    if (cameraImageFiles!=null && cameraImageFiles.get(0)!=null)    
                        for(int i=0;i<cameraImageFiles.size();i++){
                            if(cameraImageFiles.get(i).exists()){
                                uri = Uri.fromFile(cameraImageFiles.get(i));
                                break;
                            }
                        }
                    else
                        Toast.makeText(this, "Sorry :( A problem occured whille trying to add this photo", Toast.LENGTH_LONG);
                }
                else {  // from gallery
                    uri = imageReturnedIntent.getData();
                }

                if(uri != null){
                    try {

                        selectedImageBitmap = decodeSampledBitmapFromResource(uri, 500, 500);

                        Matrix matrix = new Matrix();
                        matrix.postRotate(getOrientation(this, uri));

                        selectedImageBitmap = Bitmap.createBitmap(selectedImageBitmap, 0, 0, selectedImageBitmap.getWidth(), selectedImageBitmap.getHeight(), matrix, true);


                        Intent i= new Intent(this, CreatePropertyActivity51.class);
                        i.putExtra("photoUri", uri);
                        startActivityForResult(i,IMAGE_DESCRIPTION);

                        //*** show activity51

                    } catch (FileNotFoundException e) {
                        e.printStackTrace();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    public Bitmap decodeSampledBitmapFromResource(Uri uri, int reqWidth, int reqHeight) throws IOException {

        ContentResolver cr = getContentResolver();
        InputStream inStream = cr.openInputStream(uri);
        // First decode with inJustDecodeBounds=true to check dimensions
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeStream(inStream, null, options);

        options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

        inStream.close();
        inStream = cr.openInputStream(uri);


        // Decode bitmap with inSampleSize set
        options.inJustDecodeBounds = false;
        Bitmap result = BitmapFactory.decodeStream(inStream, null , options);
        inStream.close();
        return result;
    }
    public int calculateInSampleSize( BitmapFactory.Options options, int reqWidth, int reqHeight) {
        // Raw height and width of image
        int height = options.outHeight;
        int width = options.outWidth;
        int inSampleSize = 1;

        if (height > reqHeight || width > reqWidth) {

            int halfHeight = height / 2;
            int halfWidth = width / 2;

            // Calculate the largest inSampleSize value that is a power of 2.
            while ((halfHeight / inSampleSize) > reqHeight     ||     (halfWidth / inSampleSize) > reqWidth) {
                inSampleSize *= 2;
            }
        }
        return inSampleSize;
    }

    public static int getOrientation(Context context, Uri photoUri) {
        /* it's on the external media. */
        Cursor cursor = context.getContentResolver().query(photoUri, new String[] { MediaStore.Images.ImageColumns.ORIENTATION }, null, null, null);

        if (cursor == null)
            return 0;
        if (cursor.getCount() != 1) {
            return -1;
        }

        cursor.moveToFirst();
        return cursor.getInt(0);
    }


}

【问题讨论】:

    标签: android image camera android-cursor


    【解决方案1】:

    当用户从 Gallery 中选择图像时,它会返回一个 投影的 URI,而在 Camera 的情况下,URI 返回的是直接图像路径 URI。

    所以,如果是 图库,您可以这样做,

    /**
     * Get from library
     */
    private void getPhoto() {
        Intent i = new Intent(Intent.ACTION_PICK,
                MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
        startActivityForResult(i, GET_PICTURE_REQUEST_CODE);
    }
    

    而对于相机,您可以这样做,

    /**
     * Take Photo
     */
    private void takePhoto() {
        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        //cameraImageUri is the Uri where camera app should save the clicked photo
        cameraImageUri = getOutputMediaFileUri(MEDIA_TYPE_IMAGE);
        intent.putExtra(MediaStore.EXTRA_OUTPUT, cameraImageUri);
        startActivityForResult(intent, TAKE_PICTURE_REQUEST_CODE);
    }
    

    在onActivityResult() 中,如果是图库,您需要获取imageUri 并获取光标,

    String[] filePathColumn = {MediaStore.Images.Media.DATA};
    Cursor cursor = getContentResolver().query(imageUri,
                  filePathColumn, null, null, null);
    

    但在相机中,可以直接使用cameraImageUri.toString()获取图片路径。

    您不必将 direct URI 转换为 projected URI(在图库图像选择的情况下获得)。

    为了详细说明 direct URI 和 projected URI 之间的区别,直接 URI 可能看起来像 content://...,而投影 URI 看起来像 file://...,因为它是通过内容解析器获得的。

    【讨论】:

    • 相机的东西就像一个魅力!谢谢!更好的解释。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-31
    • 1970-01-01
    相关资源
    最近更新 更多