android 选择图片 裁剪 Fileprovider

为什么会突然想到 选择图片,还有裁剪什么的,
是因为突然看到。联系人模块(6.0),创建用户的时候,当填写完用户信息,他还可以让用户选择自己的头像,当然也是点击选择图片,裁剪了, 但是我看到的是他用到了一个之前没怎么注意过的类 FilePorvider, 查了一下,也试着使用

这样子用 FilePorvider 有什么好处呢, 我看到的模块源码是,实质是将裁剪后的图片保存在了 /data/data/包名/cache 目录下了, 这个样子想想也能想通,毕竟把这个头像数据保存在cache文件夹下了,并且用的是fileprovider,这样其他模块app如果需要获取联系人的信息的话,头像的数据就可以直接从 联系人模块中获取了。

==先把问题放在上面==
测试:

小米的机子是好的 6.0, 移动的一款也是好的 6.0系统(2种跳转方式选择图片 裁剪都是好的)

移动的另外一款机子不行直接权限错误 6.0系统(选完图片后,去裁剪时,跟前面的跳转方式有关,如果用下面跳转方式的,第一种方式,进入com.android.documentsui 模块,然后用FileProvider 进行一系列操作, 在裁剪startActivityResult 就会报错,说是权限不足),但是联系人是好着的,我也不知道这个权限要怎么加 在哪里加,能加的权限都加了

大神看到了一定要帮我解决一下
错误如下:

uri content://media/external/images/media/87 from pid=10707, uid=10108 requires android.permission.READ_EXTERNAL_STORAGE, or grantUriPermission()

java.lang.SecurityException: Uid 10108 does not have permission to uri 0 @ content://com.android.providers.media.documents/document/image%3A71

一、 选择图片首先是跳转选择图片有2种

  1. 使用第一种有点问题
        Intent intent = new Intent(Intent.ACTION_GET_CONTENT);  
        intent.setType("image/*");  
        startActivityForResult(intent, 2)

有些机子直接进入的是这个模块 com.android.documentsui

2. Intent.ACTION_PICK

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

选择图库进入 com.android.gallery3d 模块
选择相册进入 com.google.android.apps.photos 模块

选择图片后, 会返回uri类似
uri: content://media/external/images/media/203474
uri.getpath: /external/images/media/203474

二、 进入裁剪图片模式

2.1 普通正常的裁剪图片方式

     intent.setDataAndType(in, "image/*");    
        intent.putExtra("crop", "true");        
        intent.putExtra("scale", true);
        intent.putExtra("scaleUpIfNeeded", true);
        intent.putExtra("aspectX", 1);
        intent.putExtra("aspectY", 1);
        // outputX,outputY 是剪裁图片的宽高
        intent.putExtra("outputX", 150); 
        intent.putExtra("outputY", 150);
        // intent.putExtra("return-data", true);
        startActivityForResult(intent, 3);

        裁剪完成后 会返回uri  也就是 裁剪后的图片的uri 
        Intent { dat=content://media/external/images/media/84 (has extras) }
        content://media/external/images/media/84

2.2 用 FileProvider (这个才是重点)

这是模块创建文件的代码

    //创建文件名称
    private static final String PHOTO_DATE_FORMAT = "'IMG'_yyyyMMdd_HHmmss";
    private static String generateTempCroppedPhotoFileName() {
        final Date date = new Date(System.currentTimeMillis());
        SimpleDateFormat dateFormat = new SimpleDateFormat(PHOTO_DATE_FORMAT, Locale.US);
        return "ContactPhoto-" + dateFormat.format(date) + "-cropped.jpg";
    }

     //路径 ontext.getCacheDir()
     private static String pathForTempPhoto(Context context, String fileName) {
        final File dir = context.getCacheDir();
        dir.mkdirs();
        final File f = new File(dir, fileName);
        return f.getAbsolutePath();
     }


    //用 FileProvider 获取uri 
    public Uri getOutUri(Context context){
//      com.example.aaaa.fileprovider
        final String  fileProviderAuthority ="com.example.aaaa.fileprovider" ;
        File ff = new File(pathForTempPhoto(context, generateTempCroppedPhotoFileName()));
        Uri uri = FileProvider.getUriForFile(context, fileProviderAuthority,ff);
        return  uri;
    }

//这里设置 intent 把 fileprovider 生成的参数传过去

out  = getOutUri(MainActivity.this);
        intent.setDataAndType(in, "image/*"); 
        //设置输出文件
        intent.putExtra(MediaStore.EXTRA_OUTPUT, out );  
    intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION |                 Intent.FLAG_GRANT_READ_URI_PERMISSION);
        intent.setClipData(ClipData.newRawUri(MediaStore.EXTRA_OUTPUT, out ));

        intent.putExtra("crop", "true");    
        intent.putExtra("scale", true);
        intent.putExtra("scaleUpIfNeeded", true);
        intent.putExtra("aspectX", 1);
        intent.putExtra("aspectY", 1);
        // outputX,outputY 是剪裁图片的宽高
        intent.putExtra("outputX", 150); 
        intent.putExtra("outputY", 150);
        // intent.putExtra("return-data", true);
        startActivityForResult(intent, 3);

//有可能 onActivityresult 有时候 uri是有路径的, 有时候是null, 可以先对
onActivityresult 中的
intent.getdata() 进行判断 ,或者直接用前面生成好的路径uri。去取数据,看看有没有

final ContentResolver cr = this.getContentResolver();          
        new Thread(){
        public void run() {
             try {  
           // FileProvider 提供的数据
               //bmp = BitmapFactory.decodeStream(cr.openInputStream(out), null ,options);
               bmp = BitmapFactory.decodeStream(cr.openInputStream( out ));
        } catch (Exception e) {
            // TODO Auto-generated catch block
             System.out.println("小米======exception==");  
            e.printStackTrace();
        }  
          aa =  new BitmapDrawable(bmp) ;
          han.sendEmptyMessage(2);
       };
   }.start(); 

在res文件夹下建立 xml文件夹
随便输个名字,一会要配置到 AndroidManifest.xml 配置文件



<paths xmlns:android="http://schemas.android.com/apk/res/android">
    
    <cache-path name="my_cache" />
paths>

在AndroidManifest.xml中配置

   
        <provider  
            android:name="android.support.v4.content.FileProvider"  
           android:authorities="@string/fileprovider_authority" //这里是作者名称,随便写
            android:exported="false"  
            android:grantUriPermissions="true" >  
            <meta-data  
                android:name="android.support.FILE_PROVIDER_PATHS"  
                android:resource="@xml/filepaths" />  //这个名字就是xml文件夹中新建的文件的名称
        provider>  

PS:看网上的也还有一种方式是这样

//      Uri.fromFile(new File("/mnt/sdcard/temp"))
//      Uri.parse("file://" + Environment.getExternalStorageDirectory().getPath() + "/" +"aaaa.jpg");  

//但是这样的方式的 uri其实会有问题, 有的手机会报
java.io.FileNotFoundException: /storage/emulated/0/aa.jpg: open failed: EACCES (Permission denied)

// 路径(关于 android 文件存储文件路径 http://blog.csdn.net/kongbaidepao/article/details/52317252 )

应该改成这样:

//2种方式生成uri
out= Uri.fromFile(new File(this.getExternalCacheDir()+ "/" + "smalaaaal.jpg"));
   //实际路径为  file:///storage/emulated/0/Android/data/com.example.aaaa/cache/smalaaaal.jpg
out= Uri.parse( "file://" +this.getExternalCacheDir()+ "/" + "smalaaaal.jpg");  

这里注意不能写成
      out= Uri.parse(this.getExternalCacheDir()+ "/" + "smalaaaal.jpg");  
       会报:
      FileNotFoundException: No content provider: /storage/emulated/0/Android/data/com.example.aaaa/cache

      // (MediaStore.EXTRA_OUTPUT 的值是  output
      intent.putExtra(MediaStore.EXTRA_OUTPUT, out);
      //intent.putExtra("outputFormat", "JPEG");// 返回格式
      intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());  
      intent.putExtra("noFaceDetection", true);

你可能感兴趣的:(android,系统)