Android 圆形头像 相册和拍照裁剪选取

知识点:

  1. 在官方7.0的以上的系统中,尝试传递 file://URI可能会触发FileUriExposedException
  2. google官方FileProvider
  3. 调用系统裁剪的过程中涉及到两个 Uri 对象:inputUri 和 outputUri
  4. 零时赋权
    (1)Context.grantUriPermission(package, Uri, mode_flags)Context.grantUriPermission(package, Uri, mode_flags)
    (2)Intent.setFlags()
  5. 自动创建Android/data/你的包名/files文件
   this.getExternalFilesDir(null).getAbsolutePath()
  1. file 转化 content://uri
  String mTempPhotoPath = this.getExternalFilesDir(null).getAbsolutePath() + File.separator + "photo.jpeg";
  File file=new File(mTempPhotoPath);
  Uri uri=FileProvider.getUriForFile(MainActivity.this, MainActivity.this.getApplicationContext().getPackageName() + ".fileprovider", file);
  //(重点)第三个参数为要共享的文件,并且这个文件一定位于path 文件中添加的子目录里面。

文件的绝对路径与第二步指定的文件目录保持一致:(假设包名为com.ysx.fileproviderserver)。如上边的代码的文件的绝对路径为/data/data/com.ysx.fileproviderserver/files/text/hello.txt,对应paths中的内容为:。getUriForFile()的第二个参数是authority,与manifest文件中声明的authorities保持一致。这时候,我们得到的URI的串为:content://com.ysx.fileproviderserver.fileprovider/my_files/hello.txt。

  1. 在paths节点内部支持以下几个子节点,分别为:
	<root-path/> 代表设备的根目录new File("/");
	<files-path/> 代表context.getFilesDir()
	<cache-path/> 代表context.getCacheDir()
	<external-path/> 代表Environment.getExternalStorageDirectory()
	<external-files-path>代表context.getExternalFilesDirs()
	<external-cache-path>代表getExternalCacheDirs()
  1. FileProvider基本使用流程
    (1)定义一个 FileProvider
    (2)指定共享目录
    (3)为文件生成有效的 Content URI
    (4)申请临时的读写权限
    (5)发送 Content URI 至其他的 App

主要代码

package com.example.administrator.popupwindow;

import android.Manifest;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.databinding.DataBinderMapper;
import android.databinding.DataBindingUtil;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Environment;
import android.provider.MediaStore;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v4.content.FileProvider;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import java.io.File;
import java.io.FileNotFoundException;


import de.hdodenhof.circleimageview.CircleImageView;

import static android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION;
import static android.content.Intent.FLAG_GRANT_WRITE_URI_PERMISSION;


public class MainActivity extends BaseActivity implements View.OnClickListener {

    private static final String TAG = "MainActivity";
    private static final String IMAGE_FILE_LOCATION = "file:///sdcard/temp.jpg";//temp file
    Uri imageUri_crop = Uri.parse(IMAGE_FILE_LOCATION);//The Uri to store the big bitmap
    private CircleImageView circleImageView;
    private String mTempPhotoPath;
    private String mTempPhotoPath2;
    private Uri imageUri;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        circleImageView = (CircleImageView) findViewById(R.id.profile_image);
        circleImageView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                showTypeDialog();
            }
        });
    }

    @Override
    public void onClick(View view) {
    }

    private void showTypeDialog() {
        //显示对话框
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setIcon(R.mipmap.ic_launcher);
        builder.setTitle("选择头像");
        final String[] items = {"相册", "相机"};
        builder.setCancelable(true);
        builder.setItems(items, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialogInterface, int i) {
                Toast.makeText(getApplicationContext(), "You clicked " + items[i], Toast.LENGTH_SHORT).show();
                if (i == 0) {
                    Intent intent1 = new Intent(Intent.ACTION_PICK, null);
                    //打开文件
                    intent1.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");
                    startActivityForResult(intent1, 1);
                    dialogInterface.dismiss();
                }
                if (i == 1) {
                    if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {   //权限还没有授予,需要在这里写申请权限的代码
                        // 第二个参数是一个字符串数组,里面是你需要申请的权限 可以设置申请多个权限
                        // 最后一个参数是标志你这次申请的权限,该常量在onRequestPermissionsResult中使用到
                        Log.e(TAG, "onClick: " + "未授权");
                        ActivityCompat.requestPermissions(MainActivity.this,
                                new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
                                2);
                    } else { //权限已经被授予,在这里直接写要执行的相应方法即可
                        takePhoto();
                    }
                    dialogInterface.dismiss();
                }
            }
        });
        final AlertDialog dialog = builder.create();
        dialog.show();
    }

    private void takePhoto() {
        // 跳转到系统的拍照界面
        Intent intentToTakePhoto = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        // 指定照片存储位置为sd卡本目录下
        // 这里设置为固定名字 这样就只会只有一张temp图 如果要所有中间图片都保存可以通过时间或者加其他东西设置图片的名称
        // File.separator为系统自带的分隔符 是一个固定的常量
        mTempPhotoPath = this.getExternalFilesDir(null).getAbsolutePath() + File.separator + "photo1.jpeg";//android/data 自动创建目录
        mTempPhotoPath2 = Environment.getExternalStorageDirectory() + File.separator + "photo2.jpeg";
        Log.e(TAG, "takePhoto: " + mTempPhotoPath);
        Log.e(TAG, "takePhoto2: " + mTempPhotoPath2);
        // 获取图片所在位置的Uri路径
        imageUri = FileProvider.getUriForFile(MainActivity.this, MainActivity.this.getApplicationContext().getPackageName() + ".fileprovider", new File(mTempPhotoPath2));
        Log.e(TAG, "takePhoto3: " + imageUri);
        //下面这句指定调用相机拍照后的照片存储的路径,如果没有这句代码,则不储存照片
        intentToTakePhoto.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);

//        intentToTakePhoto.addFlags(FLAG_GRANT_READ_URI_PERMISSION);
//        intentToTakePhoto.addFlags(FLAG_GRANT_WRITE_URI_PERMISSION);
        startActivityForResult(intentToTakePhoto, 2);
    }

    public void cropPhoto(Uri uri) {
        Intent intent = new Intent("com.android.camera.action.CROP");
        intent.setDataAndType(uri, "image/*");
        intent.putExtra("crop", "true");
        // aspectX aspectY 是宽高的比例
        intent.putExtra("aspectX", 1);
        intent.putExtra("aspectY", 1);
        // outputX outputY 是裁剪图片宽高
        intent.putExtra("outputX", 250);
        intent.putExtra("outputY", 250);
        intent.addFlags(FLAG_GRANT_READ_URI_PERMISSION);
        intent.addFlags(FLAG_GRANT_WRITE_URI_PERMISSION);
        intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri_crop);
        intent.putExtra("return-data", false);
        startActivityForResult(intent, 3);
    }

    private Bitmap decodeUriAsBitmap(Uri uri) {
        Bitmap bitmap = null;
        try {
            bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(uri));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            return null;
        }
        return bitmap;
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        switch (requestCode) {
            case 1:
                if (resultCode == RESULT_OK) {
                    Uri uri = data.getData();
                    cropPhoto(uri);
                }
                break;
            case 2:
                if (resultCode == RESULT_OK) {
                    if (imageUri != null) {
                        Log.e(TAG, "onActivityResult: " + imageUri.toString());
                        cropPhoto(imageUri);
                    }
                }
                break;
            case 3:
                if (imageUri_crop != null) {
                    Bitmap bitmap = decodeUriAsBitmap(imageUri_crop);//decode bitmap
                    circleImageView.setImageBitmap(bitmap);
                }
                break;
        }
    }
}



完整Demo下载,AS直接运行

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值