Android kotlin 从手机相册或者拍照获取照片设置头像

##一般在手机app中都会有上传图片作为头像的需求。虽然这个需求看起来挺简单,作为初学者实现起来却花了我不少时间,踩了很多坑,在这记录一下,以便下次忘记了
  1. 第一步怎加文件读写权限,和拍照权限,在AndroidMainifest中添加下列语句
 <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
 <uses-permission android:name="android.permission.CAMERA" />2
  1. 第二步,在前面加入下列语句,方便全局使用
	var realPathFromUri:String?=null//图片真实路径
    var photo:Bitmap?=null//图片的bitmap
    var imageUri: Uri? =null//图片的路径
    //下列三个是拍照和从相册获取的标志
    private val TAKE_PHOTO_REQUEST_TWO = 444
    private val TAKE_PHOTO_REQUEST_ONE = 333
    private val TAKE_PHOTO_REQUEST_THREE = 555
  1. 编写从相册获取图片函数,如下
  private fun allPhoto() {
        val intent = Intent()
        intent.action = Intent.ACTION_GET_CONTENT
        intent.type = "image/*"
        startActivityForResult(intent, 111)
    }

  1. 编写拍照函数,如下
private fun takephoto1() {
        try {
            imageUri = takePhoto(context as Activity, TAKE_PHOTO_REQUEST_THREE)
        } catch (e: IOException) {
            e.printStackTrace()
        }
    }
/**
     * 拍照
     */
    @Throws(IOException::class)
    open fun takePhoto(mActivity: Activity, flag: Int): Uri? {
        //指定拍照intent
        val takePictureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
        var imageUri: Uri? = null
        if (takePictureIntent.resolveActivity(mActivity.packageManager) != null) {
            val sdcardState = Environment.getExternalStorageState()
            var outputImage: File? = null
            if (Environment.MEDIA_MOUNTED == sdcardState) {
                outputImage = TakePhotoUtils.createImageFile(mActivity)
                Logger.d(outputImage.absolutePath)
            } else {
                Toast.makeText(
                    mActivity.applicationContext,
                    "内存异常",
                    Toast.LENGTH_SHORT
                ).show()
            }
            try {
                if (outputImage!!.exists()) {
                    outputImage.delete()
                }
                outputImage.createNewFile()
            } catch (e: IOException) {
                e.printStackTrace()
            }
            if (outputImage != null) {
                imageUri = context?.let {
                    FileProvider.getUriForFile(
                        it,
                        "com.wayeal.wateraffair.user.fileprovider",
                        outputImage
                    )
                }
                val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
                startActivityForResult(intent, TAKE_PHOTO_REQUEST_TWO)
            }
        }
        return imageUri
    }

其中有个工具类是拍照的,代码如下

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Environment;
import android.provider.MediaStore;
import android.widget.Toast;

import androidx.core.content.FileProvider;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Date;


public class TakePhotoUtils {

    /**
     * 拍照
     */

    public static  File createImageFile(Activity mActivity) throws IOException {
        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
        String imageFileName = "JPEG_" + timeStamp;//创建以时间命名的文件名称
        File storageDir = getOwnCacheDirectory(mActivity, "takephoto");//创建保存的路径
        File image = new File(storageDir.getPath(), imageFileName + ".jpg");
        if (!image.exists()) {
            try {
                //在指定的文件夹中创建文件
                image.createNewFile();
            } catch (Exception e) {
            }
        }

        return image;
    }


    /**
     * 根据目录创建文件夹
     * @param context
     * @param cacheDir
     * @return
     */
    public static File getOwnCacheDirectory(Context context, String cacheDir) {
        File appCacheDir = null;
        //判断sd卡正常挂载并且拥有权限的时候创建文件
        if ( Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) && hasExternalStoragePermission(context)) {
            appCacheDir = new File(Environment.getExternalStorageDirectory(), cacheDir);
        }
        if (appCacheDir == null || !appCacheDir.exists() && !appCacheDir.mkdirs()) {
            appCacheDir = context.getCacheDir();
        }
        return appCacheDir;
    }


    /**
     * 检查是否有权限
     * @param context
     * @return
     */
    private static boolean hasExternalStoragePermission(Context context) {
        int perm = context.checkCallingOrSelfPermission("android.permission.WRITE_EXTERNAL_STORAGE");
        return perm == 0;
    }
}

  1. 重写onActivityResult函数,用于获取拍照或者从相册获取的图片路径,代码如下
 override  fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        when (requestCode) {
            111, 222 -> {
                if (resultCode == RESULT_CANCELED) {
                    Toast.makeText(
                        context,
                        "点击取消从相册选择",
                        Toast.LENGTH_LONG
                    ).show()
                    return
                }
                try {
                        imageUri = data?.data
                        realPathFromUri = RealPathFromUriUtils.getRealPathFromUri(context, data!!.data)

                        upImage(1)
                } catch (e: Exception) {
                    e.printStackTrace()
                }
            }
           TAKE_PHOTO_REQUEST_ONE -> {
                if (resultCode == RESULT_CANCELED) {
                    context?.let { delteImageUri(it, imageUri) }
                    Toast.makeText(
                        context,
                        "点击取消  拍照",
                        Toast.LENGTH_LONG
                    ).show()
                    return
                }
                try {
                    //如果拍照图片过大会无法显示
                    val bitmap1 =
                        MediaStore.Images.Media.getBitmap(
                            context?.getContentResolver(),
                            imageUri
                        )
                    iconImage.setImageBitmap(bitmap1)
                } catch (e: Exception) {
                    e.printStackTrace()
                }
            }
            TAKE_PHOTO_REQUEST_TWO -> {
                if (resultCode == RESULT_CANCELED) {
                    context?.let { delteImageUri(it, imageUri) }
                    return
                }
                photo = data?.getParcelableExtra<Bitmap>("data")
                upImage(2)//这里可以调转上传图片到服务器

            }
           TAKE_PHOTO_REQUEST_THREE -> {
                val bitmap = BitmapFactory.decodeFile(
                    imageUri!!.path,
                    getOptions(imageUri!!.path)
                )
                iconImage.setImageBitmap(bitmap)
            }
            else -> {
            }
        }
    }

下列是上述重写函数需要的函数,目前第一个函数还没看懂啥意思,知道的可以告诉我一下,我也是从网上借鉴的代码

//个人理解把图片路径转bitmap
open fun getOptions(path: String?): BitmapFactory.Options? {
        val options =
            BitmapFactory.Options()
        options.inJustDecodeBounds = true
        BitmapFactory.decodeFile(path, options)
        options.inPreferredConfig = Bitmap.Config.RGB_565
        options.inSampleSize = 4 //此项参数可以根据需求进行计算
        options.inJustDecodeBounds = false
        return options
    }
    //删除图片url
    open fun delteImageUri(context: Context, uri: Uri?) {
        context.contentResolver.delete(uri!!, null, null)
    }
  1. 上述代码用到了一个获取文件的真实路径工具类代码如下:
import android.annotation.SuppressLint;
import android.content.ContentUris;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.provider.DocumentsContract;
import android.provider.MediaStore;

public class RealPathFromUriUtils {
    /**
     * 根据Uri获取图片的绝对路径
     *
     * @param context 上下文对象
     * @param uri     图片的Uri
     * @return 如果Uri对应的图片存在, 那么返回该图片的绝对路径, 否则返回null
     */
    public static String getRealPathFromUri(Context context, Uri uri) {
        int sdkVersion = Build.VERSION.SDK_INT;
        if (sdkVersion >= 19) { // api >= 19
            return getRealPathFromUriAboveApi19(context, uri);
        } else { // api < 19
            return getRealPathFromUriBelowAPI19(context, uri);
        }
    }

    /**
     * 适配api19以下(不包括api19),根据uri获取图片的绝对路径
     *
     * @param context 上下文对象
     * @param uri     图片的Uri
     * @return 如果Uri对应的图片存在, 那么返回该图片的绝对路径, 否则返回null
     */
    private static String getRealPathFromUriBelowAPI19(Context context, Uri uri) {
        return getDataColumn(context, uri, null, null);
    }

    /**
     * 适配api19及以上,根据uri获取图片的绝对路径
     *
     * @param context 上下文对象
     * @param uri     图片的Uri
     * @return 如果Uri对应的图片存在, 那么返回该图片的绝对路径, 否则返回null
     */
    @SuppressLint("NewApi")
    private static String getRealPathFromUriAboveApi19(Context context, Uri uri) {
        String filePath = null;
        if (DocumentsContract.isDocumentUri(context, uri)) {
            // 如果是document类型的 uri, 则通过document id来进行处理
            String documentId = DocumentsContract.getDocumentId(uri);
            if (isMediaDocument(uri)) { // MediaProvider
                // 使用':'分割
                String id = documentId.split(":")[1];

                String selection = MediaStore.Images.Media._ID + "=?";
                String[] selectionArgs = {id};
                filePath = getDataColumn(context, MediaStore.Images.Media.EXTERNAL_CONTENT_URI, selection, selectionArgs);
            } else if (isDownloadsDocument(uri)) { // DownloadsProvider
                Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(documentId));
                filePath = getDataColumn(context, contentUri, null, null);
            }
        } else if ("content".equalsIgnoreCase(uri.getScheme())) {
            // 如果是 content 类型的 Uri
            filePath = getDataColumn(context, uri, null, null);
        } else if ("file".equals(uri.getScheme())) {
            // 如果是 file 类型的 Uri,直接获取图片对应的路径
            filePath = uri.getPath();
        }
        return filePath;
    }

    /**
     * 获取数据库表中的 _data 列,即返回Uri对应的文件路径
     *
     * @return
     */
    private static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {
        String path = null;

        String[] projection = new String[]{MediaStore.Images.Media.DATA};
        Cursor cursor = null;
        try {
            cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
            if (cursor != null && cursor.moveToFirst()) {
                int columnIndex = cursor.getColumnIndexOrThrow(projection[0]);
                path = cursor.getString(columnIndex);
            }
        } catch (Exception e) {
            if (cursor != null) {
                cursor.close();
            }
        }
        return path;
    }

    /**
     * @param uri the Uri to check
     * @return Whether the Uri authority is MediaProvider
     */
    private static 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 DownloadsProvider
     */
    private static boolean isDownloadsDocument(Uri uri) {
        return "com.android.providers.downloads.documents".equals(uri.getAuthority());
    }
}
  1. 以上代码在从拍照获取照片是用到了contentProvider,不知道的可以去了解一下,在AndroidMainifest中添加如下代码:
<provider
            android:name="androidx.core.content.FileProvider"
            android:authorities="com.wayeal.wateraffair.user.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths" />
        </provider>

并且在res文件夹下创建xml文件夹在创建,命名/file_paths

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <root-path name="external_files" path="."/>
</paths>

ok以上就是完整的实现从手机相册或者拍照实现头像上传,头像上传服务器和从服务器下载,根据项目自己实现,本人只是小白,记录自己的工作,欢迎各位大神指导改正,代码基本上都是网上借鉴的,然后自己改的,如有侵权麻烦通知我

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值