5.21学习总结——android开发实现用户头像的上传
阅读原文时间:2023年07月11日阅读:1

最近在做个人头像的上传,具体是能调用摄像头和从相册进行选择。本篇文章参考的我的同学的博客,大家有兴趣可以去原作者那里去看看:

Hi(。・∀・)ノ (cnblogs.com)

1.使用glide进行图片的展示效果

关于glide

2.PermissionGen动态权限获取

关于PermissionGen

代码:

一、准备工作

1.在AndroidManifest.xml添加权限

<uses-permission android:name="android.permission.INTERNET" />  
<uses-permission android:name="android.permission.WRITE\_EXTERNAL\_STORAGE" />  
<uses-permission android:name="android.permission.READ\_EXTERNAL\_STORAGE" />  
<uses-permission android:name="android.permission.CAMERA" />

2.在build.gradle中添加依赖

dependencies {

implementation 'com.github.bumptech.glide:glide:4.10.0'  
implementation 'com.lovedise:permissiongen:0.0.6'

}

二、主代码

1.util工具类(toast和照片)

import android.content.Context;
import android.widget.Toast;

public class ToastUtil {
public static Toast mToast;
public static void showMsg(Context context, String msg){
if(mToast == null){
mToast = Toast.makeText(context,msg,Toast.LENGTH_SHORT);
}else{
mToast.setText(msg);
}
mToast.show();
}
}

Toast

Toast

import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.MediaStore;

import androidx.appcompat.app.AppCompatActivity;

import java.io.File;

/**
* CSDN_LQR
* 图片选择工具类
*/
public class LQRPhotoSelectUtils {

public static final int REQ\_TAKE\_PHOTO = 10001;  
public static final int REQ\_SELECT\_PHOTO = 10002;  
public static final int REQ\_ZOOM\_PHOTO = 10003;

private AppCompatActivity mActivity;  
//拍照或剪切后图片的存放位置(参考file\_provider\_paths.xml中的路径)  
private String imgPath = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + String.valueOf(System.currentTimeMillis()) + ".jpg";  
//FileProvider的主机名:一般是包名+".fileprovider",严格上是build.gradle中defaultConfig{}中applicationId对应的值+".fileprovider"  
private String AUTHORITIES = "packageName" + ".fileprovider";  
private boolean mShouldCrop = false;//是否要裁剪(默认不裁剪)  
private Uri mOutputUri = null;  
private File mInputFile;  
private File mOutputFile = null;

//剪裁图片宽高比  
private int mAspectX = 1;  
private int mAspectY = 1;  
//剪裁图片大小  
private int mOutputX = 800;  
private int mOutputY = 480;  
PhotoSelectListener mListener;

/\*\*  
 \* 可指定是否在拍照或从图库选取照片后进行裁剪  
 \* <p>  
 \* 默认裁剪比例1:1,宽度为800,高度为480  
 \*  
 \* @param activity   上下文  
 \* @param listener   选取图片监听  
 \* @param shouldCrop 是否裁剪  
 \*/  
public LQRPhotoSelectUtils(AppCompatActivity activity, PhotoSelectListener listener, boolean shouldCrop) {  
    mActivity = activity;  
    mListener = listener;  
    mShouldCrop = shouldCrop;  
    AUTHORITIES = activity.getPackageName() + ".fileprovider";  
    imgPath = generateImgePath();  
}

/\*\*  
 \* 可以拍照或从图库选取照片后裁剪的比例及宽高  
 \*  
 \* @param activity 上下文  
 \* @param listener 选取图片监听  
 \* @param aspectX  图片裁剪时的宽度比例  
 \* @param aspectY  图片裁剪时的高度比例  
 \* @param outputX  图片裁剪后的宽度  
 \* @param outputY  图片裁剪后的高度  
 \*/  
public LQRPhotoSelectUtils(AppCompatActivity activity, PhotoSelectListener listener, int aspectX, int aspectY, int outputX, int outputY) {  
    this(activity, listener, true);  
    mAspectX = aspectX;  
    mAspectY = aspectY;  
    mOutputX = outputX;  
    mOutputY = outputY;  
}

/\*\*  
 \* 设置FileProvider的主机名:一般是包名+".fileprovider",严格上是build.gradle中defaultConfig{}中applicationId对应的值+".fileprovider"  
 \* <p>  
 \* 该工具默认是应用的包名+".fileprovider",如项目build.gradle中defaultConfig{}中applicationId不是包名,则必须调用此方法对FileProvider的主机名进行设置,否则Android7.0以上使用异常  
 \*  
 \* @param authorities FileProvider的主机名  
 \*/  
public void setAuthorities(String authorities) {  
    this.AUTHORITIES = authorities;  
}

/\*\*  
 \* 修改图片的存储路径(默认的图片存储路径是SD卡上 Android/data/应用包名/时间戳.jpg)  
 \*  
 \* @param imgPath 图片的存储路径(包括文件名和后缀)  
 \*/  
public void setImgPath(String imgPath) {  
    this.imgPath = imgPath;  
}

/\*\*  
 \* 拍照获取  
 \*/  
public void takePhoto() {  
    File imgFile = new File(imgPath);  
    if (!imgFile.getParentFile().exists()) {  
        imgFile.getParentFile().mkdirs();  
    }  
    Uri imgUri = null;

    //        if (Build.VERSION.SDK\_INT >= 24) {//这里用这种传统的方法无法调起相机  
    //            imgUri = FileProvider.getUriForFile(mActivity, AUTHORITIES, imgFile);  
    //        } else {  
    //            imgUri = Uri.fromFile(imgFile);  
    //        }  
    /\*  
    \* 1.现象  
        在项目中调用相机拍照和录像的时候,android4.x,Android5.x,Android6.x均没有问题,在Android7.x下面直接闪退  
       2.原因分析  
        Android升级到7.0后对权限又做了一个更新即不允许出现以file://的形式调用隐式APP,需要用共享文件的形式:content:// URI  
       3.解决方案  
        下面是打开系统相机的方法,做了android各个版本的兼容:  
    \* \*/

    if (Build.VERSION.SDK\_INT < 24) {  
        // 从文件中创建uri  
        imgUri = Uri.fromFile(imgFile);  
    } else {  
        //兼容android7.0 使用共享文件的形式  
        ContentValues contentValues = new ContentValues(1);  
        contentValues.put(MediaStore.Images.Media.DATA, imgFile.getAbsolutePath());  
        imgUri = mActivity.getApplication().getContentResolver().insert(MediaStore.Images.Media.EXTERNAL\_CONTENT\_URI, contentValues);  
    }

    Intent intent = new Intent(MediaStore.ACTION\_IMAGE\_CAPTURE);  
    intent.putExtra(MediaStore.EXTRA\_OUTPUT, imgUri);  
    mActivity.startActivityForResult(intent, REQ\_TAKE\_PHOTO);  
}

/\*\*  
 \* 从图库获取  
 \*/  
public void selectPhoto() {  
    Intent intent = new Intent(Intent.ACTION\_PICK, null);  
    intent.setDataAndType(MediaStore.Images.Media.EXTERNAL\_CONTENT\_URI, "image/\*");  
    mActivity.startActivityForResult(intent, REQ\_SELECT\_PHOTO);  

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

private void zoomPhoto(File inputFile, File outputFile) {  
    File parentFile = outputFile.getParentFile();  
    if (!parentFile.exists()) {  
        parentFile.mkdirs();  
    }  
    Intent intent = new Intent("com.android.camera.action.CROP");  
    if (Build.VERSION.SDK\_INT >= Build.VERSION\_CODES.N) {  
        intent.setDataAndType(getImageContentUri(mActivity, inputFile), "image/\*");  
    } else {  
        intent.setDataAndType(Uri.fromFile(inputFile), "image/\*");  
    }  
    intent.putExtra("crop", "true");

    //设置剪裁图片宽高比  
    intent.putExtra("mAspectX", mAspectX);  
    intent.putExtra("mAspectY", mAspectY);

    //设置剪裁图片大小  
    intent.putExtra("mOutputX", mOutputX);  
    intent.putExtra("mOutputY", mOutputY);

    // 是否返回uri  
    intent.putExtra("return-data", false);  
    intent.putExtra(MediaStore.EXTRA\_OUTPUT, Uri.fromFile(outputFile));  
    intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());

    mActivity.startActivityForResult(intent, REQ\_ZOOM\_PHOTO);  
}

public void attachToActivityForResult(int requestCode, int resultCode, Intent data) {  
    if (resultCode == AppCompatActivity.RESULT\_OK) {  
        switch (requestCode) {  
            case LQRPhotoSelectUtils.REQ\_TAKE\_PHOTO://拍照  
                mInputFile = new File(imgPath);  
                if (mShouldCrop) {//裁剪  
                    mOutputFile = new File(generateImgePath());  
                    mOutputUri = Uri.fromFile(mOutputFile);  
                    zoomPhoto(mInputFile, mOutputFile);  
                } else {//不裁剪  
                    mOutputUri = Uri.fromFile(mInputFile);  
                    if (mListener != null) {  
                        mListener.onFinish(mInputFile, mOutputUri);  
                    }  
                }  
                break;  
            case LQRPhotoSelectUtils.REQ\_SELECT\_PHOTO://图库  
                if (data != null) {  
                    Uri sourceUri = data.getData();  
                    String\[\] proj = {MediaStore.Images.Media.DATA};  
                    Cursor cursor = mActivity.managedQuery(sourceUri, proj, null, null, null);  
                    int columnIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);  
                    cursor.moveToFirst();  
                    String imgPath = cursor.getString(columnIndex);  
                    mInputFile = new File(imgPath);

                    if (mShouldCrop) {//裁剪  
                        mOutputFile = new File(generateImgePath());  
                        mOutputUri = Uri.fromFile(mOutputFile);  
                        zoomPhoto(mInputFile, mOutputFile);  
                    } else {//不裁剪  
                        mOutputUri = Uri.fromFile(mInputFile);  
                        if (mListener != null) {  
                            mListener.onFinish(mInputFile, mOutputUri);  
                        }  
                    }  
                }  
                break;  
            case LQRPhotoSelectUtils.REQ\_ZOOM\_PHOTO://裁剪  
                if (data != null) {  
                    if (mOutputUri != null) {  
                        //删除拍照的临时照片  
                        File tmpFile = new File(imgPath);  
                        if (tmpFile.exists())  
                            tmpFile.delete();  
                        if (mListener != null) {  
                            mListener.onFinish(mOutputFile, mOutputUri);  
                        }  
                    }  
                }  
                break;  
        }  
    }  
}

/\*\*  
 \* 安卓7.0裁剪根据文件路径获取uri  
 \*/  
private Uri getImageContentUri(Context context, File imageFile) {  
    String filePath = imageFile.getAbsolutePath();  
    Cursor cursor = context.getContentResolver().query(  
            MediaStore.Images.Media.EXTERNAL\_CONTENT\_URI,  
            new String\[\]{MediaStore.Images.Media.\_ID},  
            MediaStore.Images.Media.DATA + "=? ",  
            new String\[\]{filePath}, null);

    if (cursor != null && cursor.moveToFirst()) {  
        int id = cursor.getInt(cursor  
                .getColumnIndex(MediaStore.MediaColumns.\_ID));  
        Uri baseUri = Uri.parse("content://media/external/images/media");  
        return Uri.withAppendedPath(baseUri, "" + id);  
    } else {  
        if (imageFile.exists()) {  
            ContentValues values = new ContentValues();  
            values.put(MediaStore.Images.Media.DATA, filePath);  
            return context.getContentResolver().insert(  
                    MediaStore.Images.Media.EXTERNAL\_CONTENT\_URI, values);  
        } else {  
            return null;  
        }  
    }  
}

/\*\*  
 \* 产生图片的路径,带文件夹和文件名,文件名为当前毫秒数  
 \*/  
private String generateImgePath() {  
    return getExternalStoragePath() + File.separator + String.valueOf(System.currentTimeMillis()) + ".jpg";  
    //        return Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + String.valueOf(System.currentTimeMillis()) + ".jpg";//测试用  
}

/\*\*  
 \* 获取SD下的应用目录  
 \*/  
private String getExternalStoragePath() {  
    StringBuilder sb = new StringBuilder();  
    sb.append(Environment.getExternalStorageDirectory().getAbsolutePath());  
    sb.append(File.separator);  
    String ROOT\_DIR = "Android/data/" + mActivity.getPackageName();  
    sb.append(ROOT\_DIR);  
    sb.append(File.separator);  
    return sb.toString();  
}

public interface PhotoSelectListener {  
    void onFinish(File outputFile, Uri outputUri);  
}  

}

LQRPhotoSelectUtils

LQRPhotoSelectUtils

2.MainActivity

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import android.Manifest;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import com.bumptech.glide.Glide;
import com.example.camera.utils.LQRPhotoSelectUtils;
import com.example.camera.utils.ToastUtil;

import java.io.File;

import kr.co.namee.permissiongen.PermissionGen;

public class MainActivity extends AppCompatActivity {

//定义控件  
private Button mBtnTakePhoto;  
private Button mBtnSelectPic;  
private Button mBtnFinish;  
private ImageView mIvPic;  
private TextView mTvPath;  
private TextView mTvUri;

private static final int REQUEST\_CODE = 0x001;  
private LQRPhotoSelectUtils mLqrPhotoSelectUtils;

@Override  
protected void onCreate(Bundle savedInstanceState) {  
    super.onCreate(savedInstanceState);  
    setContentView(R.layout.activity\_main);

    //绑定控件  
    mBtnTakePhoto = findViewById(R.id.btn\_take\_photo);  
    mBtnSelectPic = findViewById(R.id.btn\_select\_pic);  
    mTvPath = findViewById(R.id.tvPath);  
    mTvUri = findViewById(R.id.tvUri);  
    mIvPic = findViewById(R.id.iv\_pic);  
    mBtnFinish = findViewById(R.id.btn\_finish);

    init();  
    initListener();  
}  
private void init() {//初始化  
    //创建LQRPhotoSelectUtils(一个Activity对应一个LQRPhotoSelectUtils)  
    mLqrPhotoSelectUtils = new LQRPhotoSelectUtils(this, new LQRPhotoSelectUtils.PhotoSelectListener() {  
        @Override  
        public void onFinish(File outputFile, Uri outputUri) {  
            //当拍照或从图库选取图片成功后回调  
            mTvPath.setText(outputFile.getAbsolutePath());//显示图片路径  
            mTvUri.setText(outputUri.toString());//显示图片uri  
            //System.out.println(outputUri.toString());  
            Glide.with(MainActivity.this).load(outputUri).into(mIvPic);//使用Glide进行图片展示  
        }  
    }, true);//是否裁剪。true裁剪,false不裁剪

    //检查权限  
    if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.READ\_EXTERNAL\_STORAGE)!= PackageManager.PERMISSION\_GRANTED||  
        ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE\_EXTERNAL\_STORAGE)!= PackageManager.PERMISSION\_GRANTED||  
        ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.CAMERA)!= PackageManager.PERMISSION\_GRANTED){  
            ActivityCompat.requestPermissions(MainActivity.this, new String\[\]{Manifest.permission.READ\_EXTERNAL\_STORAGE, Manifest.permission.WRITE\_EXTERNAL\_STORAGE, Manifest.permission.CAMERA}, REQUEST\_CODE);  
    }else{  
        ToastUtil.showMsg(MainActivity.this, "已经获得了所有权限");  
    }  
}

private void initListener(){//初始化监听器  
    mBtnTakePhoto.setOnClickListener(new View.OnClickListener(){  
        @Override  
        public void onClick(View v) {  
            //获取权限,调用拍照方法  
            PermissionGen.with(MainActivity.this)  
                    .addRequestCode(LQRPhotoSelectUtils.REQ\_TAKE\_PHOTO)  
                    .permissions(Manifest.permission.READ\_EXTERNAL\_STORAGE,  
                            Manifest.permission.WRITE\_EXTERNAL\_STORAGE,  
                            Manifest.permission.CAMERA  
                    ).request();  
            //拍照  
            mLqrPhotoSelectUtils.takePhoto();  
        }  
    });

    mBtnSelectPic.setOnClickListener(new View.OnClickListener() {  
        @Override  
        public void onClick(View v) {  
            // 选择图片  
            mLqrPhotoSelectUtils.selectPhoto();  
        }  
    });

    mBtnFinish.setOnClickListener(new View.OnClickListener() {  
        @Override  
        public void onClick(View v) {  
            if (mTvPath.getText().toString().equals("图片路径:")){  
                // 如果一张图片都没选  
                ToastUtil.showMsg(getApplicationContext(), "您还没有选择图片呢!");  
            }else{  
                ToastUtil.showMsg(getApplicationContext(), "选择图片成功:"+mTvPath.getText().toString());  
                Bundle bundle = new Bundle();  
                Intent intent = new Intent();  
                bundle.putString("uri", mTvUri.getText().toString());  
                intent.putExtras(bundle);  
                setResult(Activity.RESULT\_OK, intent);  
                finish();  
            }  
        }  
    });  
}

public void onRequestPermissionsResult(int requestCode, @NonNull String\[\] permissions, @NonNull int\[\] grantResults) {  
    if (requestCode == REQUEST\_CODE) {  
        if (grantResults.length > 0 && grantResults\[0\] == PackageManager.PERMISSION\_GRANTED) {  
            initListener();  
        } else {  
            Toast.makeText(this, "您已拒绝授予权限", Toast.LENGTH\_LONG).show();  
        }  
    }  
}

@Override  
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {  
    super.onActivityResult(requestCode, resultCode, data);  
    //在Activity中的onActivityResult()方法里与LQRPhotoSelectUtils关联  
    mLqrPhotoSelectUtils.attachToActivityForResult(requestCode, resultCode, data);  
}  

}

3.xml界面


<Button  
    android:id="@+id/btn\_take\_photo"  
    android:text="拍照"  
    android:layout\_width="match\_parent"  
    android:layout\_height="wrap\_content"/>

<Button  
    android:id="@+id/btn\_select\_pic"  
    android:text="从图库中选取"  
    android:layout\_width="match\_parent"  
    android:layout\_height="wrap\_content"/>

<TextView  
    android:id="@+id/tvPath"  
    android:layout\_width="wrap\_content"  
    android:layout\_height="50dp"  
    android:text="图片路径:"/>

<TextView  
    android:id="@+id/tvUri"  
    android:layout\_width="wrap\_content"  
    android:layout\_height="50dp"  
    android:text="图片Uri:"/>  
<ImageView  
    android:id="@+id/iv\_pic"  
    app:srcCompat="@drawable/head\_portrait"  
    android:layout\_width="300dp"  
    android:layout\_height="300dp"/>

<Button  
    android:id="@+id/btn\_finish"  
    android:layout\_width="match\_parent"  
    android:layout\_height="50dp"  
    android:text="完成"/>