Android 4.4.2 - 相机 uri 返回 null 并且裁剪功能也不起作用?

Posted

技术标签:

【中文标题】Android 4.4.2 - 相机 uri 返回 null 并且裁剪功能也不起作用?【英文标题】:Android 4.4.2 - camera uri return null and also cropping feature not working? 【发布时间】:2014-06-25 19:17:14 【问题描述】:

我正在尝试单击相机中的图像并显示到图像视图中,但 onactivityresult URI 返回 null。但是下面的代码在 JellyBean 上运行良好,ICS 具有裁剪功能。

通话意图

                Intent pickIntent = new Intent();
                pickIntent.setType("image/*");
                pickIntent.setAction(Intent.ACTION_GET_CONTENT);
                pickIntent.putExtra(MediaStore.EXTRA_SCREEN_ORIENTATION, ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
                Intent captureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                // we will handle the returned data in onActivityResult
                String pickTitle = "Select or take a new Picture";
                // startActivityForResult(captureIntent, 1);
                Intent chooserIntent = Intent.createChooser(pickIntent, pickTitle);
                chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, new Intent[]
                 captureIntent );
                startActivityForResult(chooserIntent, GlobalVariables.GALLERY_MODE);

onActivityResult

@SuppressLint("NewApi")
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data)
    
        // TODO Auto-generated method stub
        super.onActivityResult(requestCode, resultCode, data);
        try
        
            if (resultCode == RESULT_OK)
            
                // user is returning from capturing an image using the camera
                if (requestCode == GlobalVariables.GALLERY_MODE)
                
                    // get the Uri for the captured image
                    picUri = data.getData();
                    System.out.println("picUri      =======     => "+picUri);
                    boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
                    if(isKitKat)
                    
                        System.out.println(new GraphicsUtil().getPath(RegistrationActivity.this, picUri));
                        String filePath = new GraphicsUtil().getPath(RegistrationActivity.this, picUri);
                        System.out.println("filepath            => "+filePath);
                        bitmapPreview = null;
                        bitmapPreview = BitmapFactory.decodeFile(filePath);
                        System.out.println("bitmapPreview           => "+bitmapPreview );
                        imageViewUser.setImageBitmap(new GraphicsUtil().getCircleBitmap(GraphicsUtil.decodeSampledBitmapFromResource(filePath,
                                120, 120)));
                    
                    else
                    
                        performCrop(picUri, PIC_CROP, RegistrationActivity.this);
                    
                
                // user is returning from cropping the image
                else if (requestCode == PIC_CROP)
                
                    String filePath = new File (Environment.getExternalStorageDirectory() + "/temporary_holder.jpg").getAbsolutePath();
                    bitmapPreview = null;
                    bitmapPreview = BitmapFactory.decodeFile(filePath);
                    imageViewUser.setImageBitmap(new GraphicsUtil().getCircleBitmap(GraphicsUtil.decodeSampledBitmapFromResource(filePath,
                            120, 120)));
                    // imageViewUser.setImageBitmap(new
                    // GraphicsUtil().getCircleBitmap(bitmapPreview));
                    File f = new File(Environment.getExternalStorageDirectory() + "/temporary_holder.jpg");
                    if (f.exists())
                    
                        f.delete();
                    
                
            
        
        catch (Exception e)
        
            // TODO: handle exception
            e.printStackTrace();
        
    

GraphicsUtil.java

public class GraphicsUtil


    /*
     * Draw image in circular shape Note: change the pixel size if you want
     * image small or large
     */
    public Bitmap getCircleBitmap(Bitmap bitmap)
    
        Bitmap output;
        Canvas canvas = null;
        final int color = 0xffff0000;
        final Paint paint = new Paint();
        Rect rect = null;
        if (bitmap.getHeight() > 501)
        
            output = Bitmap.createBitmap(500, 500, Bitmap.Config.ARGB_8888);
            canvas = new Canvas(output);
            rect = new Rect(0, 0, 500, 500);
        
        else
        
            //System.out.println("output            else =======");
            bitmap = Bitmap.createScaledBitmap(bitmap, 500, 500, false);
            output = Bitmap.createBitmap(500, 500, Bitmap.Config.ARGB_8888);
            canvas = new Canvas(output);
            rect = new Rect(0, 0, 500, 500);
        
        final RectF rectF = new RectF(rect);

        paint.setAntiAlias(true);
        paint.setDither(true);
        paint.setFilterBitmap(true);
        canvas.drawARGB(0, 0, 0, 0);
        paint.setColor(color);
        canvas.drawOval(rectF, paint);

        paint.setColor(Color.BLUE);
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth((float) 1);
        paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
        canvas.drawBitmap(bitmap, rect, rect, paint);
        return output;
    

    public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight)
    
        // Raw height and width of image
        final int height = options.outHeight;
        final int width = options.outWidth;
        int inSampleSize = 1;

        if (height > reqHeight || width > reqWidth)
        
            // Calculate ratios of height and width to requested height and
            // width
            final int heightRatio = Math.round((float) height / (float) reqHeight);
            final int widthRatio = Math.round((float) width / (float) reqWidth);
            // Choose the smallest ratio as inSampleSize value, this will
            // guarantee
            // a final image with both dimensions larger than or equal to the
            // requested height and width.
            inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
        

        return inSampleSize;
    

    public static Bitmap decodeSampledBitmapFromResource(String path, int reqWidth, int reqHeight)
    
        // First decode with inJustDecodeBounds=true to check dimensions
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(path, options);

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

        // Decode bitmap with inSampleSize set
        options.inJustDecodeBounds = false;
        return BitmapFactory.decodeFile(path, options);
    


    @SuppressLint("NewApi")
    public String getPath(final Context context, final Uri uri) 

        final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;

        // DocumentProvider
        if (isKitKat && 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.valueOf(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 the remote address
            if (isGooglePhotosUri(uri))
                return uri.getLastPathSegment();

            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 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 index = cursor.getColumnIndexOrThrow(column);
                return cursor.getString(index);
            
         finally 
            if (cursor != null)
                cursor.close();
        
        return null;
    


    /**
     * @param uri The Uri to check.
     * @return Whether the Uri authority is ExternalStorageProvider.
     */
    public 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 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 boolean isMediaDocument(Uri uri) 
        return "com.android.providers.media.documents".equals(uri.getAuthority());
    

    /**
     * @param uri The Uri to check.
     * @return Whether the Uri authority is Google Photos.
     */
    public boolean isGooglePhotosUri(Uri uri) 
        return "com.google.android.apps.photos.content".equals(uri.getAuthority());
    

在 android 4.4.2 os 上单击图像并选择图像时的 logcat 输出:-

05-08 17:25:55.697: I/System.out(20894): picUri     =======     => null
05-08 17:25:55.698: W/System.err(20894): java.lang.NullPointerException
05-08 17:25:55.711: W/System.err(20894):    at android.provider.DocumentsContract.isDocumentUri(DocumentsContract.java:587)
05-08 17:25:55.712: W/System.err(20894):    at com.asiaelites.utils.GraphicsUtil.getPath(GraphicsUtil.java:119)
05-08 17:25:55.712: W/System.err(20894):    at com.asiaelites.RegistrationActivity.onActivityResult(RegistrationActivity.java:489)
05-08 17:25:55.712: W/System.err(20894):    at android.app.Activity.dispatchActivityResult(Activity.java:5446)
05-08 17:25:55.712: W/System.err(20894):    at android.app.ActivityThread.deliverResults(ActivityThread.java:3442)
05-08 17:25:55.712: W/System.err(20894):    at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2802)
05-08 17:25:55.712: W/System.err(20894):    at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2859)
05-08 17:25:55.712: W/System.err(20894):    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2274)
05-08 17:25:55.712: W/System.err(20894):    at android.app.ActivityThread.access$800(ActivityThread.java:139)
05-08 17:25:55.712: W/System.err(20894):    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1210)
05-08 17:25:55.712: W/System.err(20894):    at android.os.Handler.dispatchMessage(Handler.java:102)
05-08 17:25:55.712: W/System.err(20894):    at android.os.Looper.loop(Looper.java:136)
05-08 17:25:55.712: W/System.err(20894):    at android.app.ActivityThread.main(ActivityThread.java:5102)
05-08 17:25:55.712: W/System.err(20894):    at java.lang.reflect.Method.invokeNative(Native Method)
05-08 17:25:55.713: W/System.err(20894):    at java.lang.reflect.Method.invoke(Method.java:515)
05-08 17:25:55.713: W/System.err(20894):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785)
05-08 17:25:55.713: W/System.err(20894):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)
05-08 17:25:55.713: W/System.err(20894):    at dalvik.system.NativeStart.main(Native Method)

点击以下链接:-

Android Gallery on KitKat returns different Uri for Intent.ACTION_GET_CONTENT

【问题讨论】:

如果我没记错的话,这是 kitkat 中的一个已知错误。 在这里查看我的答案***.com/questions/22576049/… 如果您仍有问题,请尝试我的解决方案 参考此链接***.com/questions/23261498/… 参考此链接***.com/questions/23261498/android-kitkat-image-crop 【参考方案1】:

这项工作为Kitkat

public class YourActivity  extends Activity

private static final int SELECT_PICTURE = 1;

private String selectedImagePath;
private ImageView imageView;

public void onCreate(Bundle savedInstanceState) 
    super.onCreate(savedInstanceState);
    setContentView(R.layout.browsepicture);
    imageView = (ImageView)findViewById(R.id.imageView1);

    ((Button) findViewById(R.id.button1))
            .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();
            if (Build.VERSION.SDK_INT < 19) 
                selectedImagePath = getPath(selectedImageUri);
                Bitmap bitmap = BitmapFactory.decodeFile(selectedImagePath);
                imageView.setImageBitmap(bitmap);

            
            else 
                ParcelFileDescriptor parcelFileDescriptor;
                try 
                    parcelFileDescriptor = getContentResolver().openFileDescriptor(selectedImageUri, "r");
                    FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
                    Bitmap image = BitmapFactory.decodeFileDescriptor(fileDescriptor);
                    parcelFileDescriptor.close();
                    imageView.setImageBitmap(image);

                 catch (FileNotFoundException e) 
                    e.printStackTrace();
                 catch (IOException e) 

                    e.printStackTrace();
                
            
        
    



public String getPath(Uri uri) 
        if( uri == null ) 
            return null;
        
        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();




For Cropping image 

    private void cropImage() 
        // Use existing crop activity.
        Intent intent = new Intent("com.android.camera.action.CROP");
        intent.setDataAndType(capturedImageUri, IMAGE_UNSPECIFIED);

        // Specify image size
        intent.putExtra("outputX", IMAGE_DIMENSION);
        intent.putExtra("outputY", IMAGE_DIMENSION);

        // Specify aspect ratio, 1:1
        intent.putExtra("aspectX", 1);
        intent.putExtra("aspectY", 1);
        intent.putExtra("scale", true);
        intent.putExtra("return-data", true);
        // REQUEST_CODE_CROP_PHOTO is an integer tag you defined to
        // identify the activity in onActivityResult() when it returns
        startActivityForResult(intent, REQ_CODE_CROP_PHOTO);
    

【讨论】:

不介意 bcz 问题相机 uri 返回 null 并且裁剪功能不起作用? 我也有同样的问题。你解决了吗?【参考方案2】:

我希望你能找到解决方案,但这适用于仍在寻找解决方案的人。

在onActivityResult中使用这行代码

Uri imageUri = data.getData();

或者参考这个link for getting URI。

只需使用 getPath(final Context context, final Uri uri) 的代码,使用 uri 就会返回文件的路径

@SuppressLint("NewApi")
public static String getPath(final Context context, final Uri uri) 

final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;

// DocumentProvider
if (isKitKat && 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.valueOf(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());

【讨论】:

以上是关于Android 4.4.2 - 相机 uri 返回 null 并且裁剪功能也不起作用?的主要内容,如果未能解决你的问题,请参考以下文章

Android相机:拍照后获取图片Uri

Android webview调取安卓原生相机和相册上传图片

如何从Android片段中的相机获取图像

Android 使用系统相机拍照和读取相册照片

显示从相机拍摄的图像时,Uri 为空

Android7.0调用系统相机拍照读取系统相册照片+CropImageView剪裁照片