Android项目实战 | 从零开始写app(14)实现图片发布模块 | 必知必会之调用系统相机拍照相册一一解决android7 打开相机闪退奔溃问题

Posted 李猫er

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android项目实战 | 从零开始写app(14)实现图片发布模块 | 必知必会之调用系统相机拍照相册一一解决android7 打开相机闪退奔溃问题相关的知识,希望对你有一定的参考价值。

续更,这个系列即将完结了。本篇实现的是一个发布图片的功能案例,调用系统相机拍照、相册实现图片发布模块效果,本来想是实现服务端的贴子和图片DRUD操作发送,但后台接口没时间写,就改为这个简单的图片拍照显示,因为调用系统相机拍照,打开相册这些常规操作基本都是开发app中必知必会的,嗯,所以就这样~,我没话了。直接看下面。

本篇效果

第一次调用会进行访问权限提示,授权后才可以进行调用:
在这里插入图片描述

在这里插入图片描述
实现Intent隐式意图调用系统相机拍照、打开系统相册并进行图片的处理后实现图片数据的回传。其中用到了AlertDialog对话框,Intent等数据传递等基础知识点。


文章导航

一、【Android项目实战 | 从零开始写app(一)】 创建项目

二、【Android项目实战 | 从零开始写app(二)】实现闪屏页,启动app

三、【Android项目实战 | 从零开始写app(三)】实现引导页,进入登录or主页面

四、【Android项目实战 | 从零开始写app(四)】Okhttp+Gson实现服务端登录验证功能

五、【Android项目实战 | 从零开始写app(五)】okhttp+gson实现服务端注册功能

六、【Android项目实战 | 从零开始写app(六)】用TabLayout+ViewPager搭建App 框架主页面底部导航栏

七、【Android项目实战 | 从零开始写app(七)】优化主页导航栏,禁用主页页面滑动切换效果

八、【Android项目实战 | 从零开始写app(八)】实现app首页广告轮播图切换和搜索跳转

九、【Android项目实战 | 从零开始写app(九)】实现主页底部新闻模块数据的解析

十、【Android项目实战 | 从零开始写app(10)】Okhttp+glide+json+ListView实现新闻模块数据的填充显示

十一、【Android项目实战 | 从零开始写app(11)】实现app首页智慧服务页面服务分类数据的解析及点击跳转

十二、【Android项目实战 | 从零开始写app(12)】实现app首页智慧服务&热门推荐&热门主题、新闻

十三、【Android项目实战 | 从零开始写app(13)】实现用户中心模块清除token退出登录&信息修改等功能

十四、【Android项目实战 | 从零开始写app(14)】实现图片发布模块 | 必知必会之调用系统相机拍照、相册

十五、【Android项目实战 | 从零开始写app(教程汇总)】Android 项目实战系列汇总、源代码


功能实现

首先,在androidManifest.xml清单文件中加入授权权限:

<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

TakePhotoActivity:

package com.example.myapp.activity;

import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import android.Manifest;
import android.app.AlertDialog;
import android.content.ContentResolver;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PaintFlagsDrawFilter;
import android.graphics.Rect;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.StrictMode;
import android.provider.MediaStore;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import com.example.myapp.R;

import java.io.FileNotFoundException;
import java.io.IOException;

public class TakePhotoActivity extends AppCompatActivity {
    private Button btn_photo;
    private TextView tv;
    private ImageView img;
    private Toolbar toolbar;
    Intent intent = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_take_photo);
        toolbar = (Toolbar) findViewById(R.id.toolbar);
        btn_photo = findViewById(R.id.btn_photo);
        img = findViewById(R.id.img);

        /**
         * 解决android7调用照相机后直接奔溃问题
         */
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
            StrictMode.setVmPolicy(builder.build());
            builder.detectFileUriExposure();
        }
        checkPermission();
        initListener();
    }

    /**
     * 检查拍照权限,防止权限拒绝
     */
    private void checkPermission() {
        if (ContextCompat.checkSelfPermission(TakePhotoActivity.this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
            // 执行到这里表示没有访问权限
            if (ActivityCompat.shouldShowRequestPermissionRationale(TakePhotoActivity.this, Manifest.permission.CAMERA)) {
                Toast.makeText(TakePhotoActivity.this,"禁止访问",Toast.LENGTH_LONG).show();
            } else {
                ActivityCompat.requestPermissions(TakePhotoActivity.this, new String[]{Manifest.permission.CAMERA}, 200);
            }
        } else {
            takePhoto();
        }
    }

    private void initListener() {
        // 顶部返回
        toolbar.setNavigationIcon(R.mipmap.top_bar_left_back);
        toolbar.setNavigationOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                finish();
            }
        });
        // 按钮点击事件,单击弹出AlertDialog对话框
        btn_photo.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                new AlertDialog.Builder(TakePhotoActivity.this)
                        .setIcon(R.mipmap.picture)
                        .setMessage("插入图片")
                        .setPositiveButton("拍照", new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                takePhoto();
                            }
                        }).setNegativeButton("相册", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        chooseFromAlbum();
                    }
                }).create().show();
            }
        });
    }

    /**
     * 获取图片
     */
    public void takePhoto() {
        intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); // 调用系统相机
        intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);
        startActivityForResult(intent, 200);   //有数据的返回
    }

    /**
     * 选择相册
     */
    public void chooseFromAlbum() {
        intent = new Intent();
        intent.setType("image/*");   //设定类型为image
        intent.setAction(Intent.ACTION_GET_CONTENT);
        startActivityForResult(intent, 100);//选中相片后返回本Activity
    }


    /**
     * 重写onActivityResult方法:将返回的图片数据设置到ImageView上
     *
     * 参数说明:requestCode值:100 为打开系统相册选择相片,requestCode值:200为调用系统相机拍照
     * @param requestCode
     * @param resultCode
     * @param data
     */
    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode == RESULT_OK) {
            Uri uri = data.getData();  //获取数据
            ContentResolver contentResolver = getContentResolver();
            Bitmap bitmap = null;
            Bundle extras = null;
            if (requestCode == 100) {
                try {
                    bitmap = BitmapFactory.decodeStream(contentResolver.openInputStream(uri));  //将对象存入Bitmap中
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                }
            }
            if (requestCode == 200) {
                try {
                    if (uri != null){
                        bitmap = MediaStore.Images.Media.getBitmap(contentResolver, uri);  // 根据Uri获取Bitmap图片
                    } else{  // 从Bundle里面获取Bitmap图片
                        extras = data.getExtras();
                        bitmap = extras.getParcelable("data");
                    }
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            int imgWidth = bitmap.getWidth();  //获取图片宽度
            int imgHeight = bitmap.getHeight();  // 获取图片高度
            double partion = imgWidth * 1.0 / imgHeight;
            double sqrtLength = Math.sqrt(partion * partion + 1);

            /**
             * 设置图片新的缩略图大小
             */
            double newImgW = 680 * (partion / sqrtLength);
            double newImgH = 680  * (1 / sqrtLength);
            float scaleW = (float) (newImgW / imgWidth);
            float scaleH = (float) (newImgH / imgHeight);
            Matrix mx = new Matrix();

            /**
             * 对原图片进行缩放
             */
            mx.postScale(scaleW, scaleH);
            bitmap = Bitmap.createBitmap(bitmap, 0, 0, imgWidth, imgHeight, mx, true);
            bitmap = getBitmapWidth(bitmap);
            img.setImageBitmap(bitmap);
        }
    }

    /**
     * 给图片加边框,并返回边框后的图片
     * @param bitmap
     * @return
     */
    public Bitmap getBitmapWidth(Bitmap bitmap) {
        float frameSize = 0.2f;
        Matrix matrix = new Matrix();
        // 用来做底图
        Bitmap mbitmap = Bitmap.createBitmap(bitmap.getWidth(),bitmap.getHeight(), Bitmap.Config.ARGB_8888);
        // 设置底图为画布
        Canvas canvas = new Canvas(mbitmap);
        canvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG));
        float scale_x = (bitmap.getWidth() - 2 * frameSize - 2) * 1f / (bitmap.getWidth());
        float scale_y = (bitmap.getHeight() - 2 * frameSize - 2) * 1f / (bitmap.getHeight());
        matrix.reset();
        matrix.postScale(scale_x, scale_y);

        // 减去边框的大小
        bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),bitmap.getHeight(), matrix, true);

        Paint paint = new Paint();
        paint.setColor(Color.WHITE);
        paint.setStrokeWidth(1);
        paint.setStyle(Paint.Style.FILL);

        // 绘制底图边框
        canvas.drawRect(new Rect(0, 0, mbitmap.getWidth(), mbitmap.getHeight()),paint);
        // 绘制灰色边框
        paint.setColor(Color.GRAY);
        canvas.drawRect(new Rect((int) (frameSize), (int) (frameSize), mbitmap.getWidth() - (int) (frameSize), mbitmap.getHeight() - (int) (frameSize)), paint);
        canvas.drawBitmap(bitmap, frameSize + 2, frameSize + 2, paint);
        return mbitmap;
    }

}

有一点要注意的是Android7及以上调用相机会出现闪退,可以通过StrictMode.VmPolicy.Builder来解决这个问题。

上面的checkPermission()是用来检查权限的,这是因为高版本的如果直接调用拍照会出现闪退奔溃,需要做权限处理:

    private void checkPermission() {
        if (ContextCompat.checkSelfPermission(TakePhotoActivity.this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
            // 执行到这里表示没有访问权限
            if (ActivityCompat.shouldShowRequestPermissionRationale(TakePhotoActivity.this, Manifest.permission.CAMERA)) {
                Toast.makeText(TakePhotoActivity.this,"禁止访问",Toast.LENGTH_LONG).show();
            } else {
                ActivityCompat.requestPermissions(TakePhotoActivity.this, new String[]{Manifest.permission.CAMERA}, 200);
            }
        } else {
            takePhoto();
        }
    }

activity_take_photo.xml

简单的页面布局,其他功能,页面想更好看的,可以自己是实现,我这里简单粗糙实现,勿吐槽哈。
在这里插入图片描述

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
    android:orientation="vertical"
    android:layout_height="match_parent">
    <RelativeLayout
        android:layout_width="match_parent"
        android:id=以上是关于Android项目实战 | 从零开始写app(14)实现图片发布模块 | 必知必会之调用系统相机拍照相册一一解决android7 打开相机闪退奔溃问题的主要内容,如果未能解决你的问题,请参考以下文章

Android项目实战 | 从零开始写app实现app首页智慧服务&热门推荐&热门主题新闻

Android项目实战 | 从零开始写app(十三)实现用户中心模块清除token退出登录&信息修改等功能

《Android Studio开发实战 从零基础到App上线(第3版)》出版后记

《Android Studio开发实战 从零基础到App上线(第3版)》出版后记

《Android Studio开发实战 从零基础到App上线(第3版)》出版后记

《Android App开发进阶与项目实战》出版后记