Android10相机拍摄保存照片并显示(解决各种闪退,添加v4包)

1. 测试条件:

1) Eclipse

Eclipse Java EE IDE for Web Developers.
Version: Photon Release (4.8.0)
Build id: 20180619-1200

2) ADT

23.0.7

3) SDK

Android 7, 9

4) build-tools

build-tools=25.0.2

2. 注意事项:

Android6.0开始需动态申请权限
Android7.0开始需使用FileProvider传递存储地址
//7.0之后你的app就算有权限,给出一个URI之后手机也认为你没有权限
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
StrictMode.setVmPolicy(builder.build());
}

3.添加V4包

ChoosePicTest下新建lib文件夹
SDK\extras\android\m2repository\com\android\support\support-v4\24.1.1\support-v4-24.1.1.aar\classes.jar复制到lib文件夹下,改为v4.jar
关闭工程,再打开这样在工程下lib下显示v4.jar,在v4.jar上右击,“Build Path”,“Add to build Path”,工程下出现“Referenced Libraries” “v4.jar”
查看工程的属性,v4.jar是否添加成功。
Android10相机拍摄保存照片并显示(解决各种闪退,添加v4包)_第1张图片

4. 测试机型:

在Android9、10手机上测试通过。

5. 详细代码

//MainActivity.java

package com.example.choosepictest;

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

import android.Manifest;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.StrictMode;
import android.provider.MediaStore;
import android.provider.Settings;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;
import android.support.v4.content.FileProvider;
import android.util.Log;

public class MainActivity extends Activity {
	public static final String TAG = "MainActivity";
	public static final int TAKE_PHOTO = 1;
	public static final int CROP_PHOTO = 2;
	public static final int TAKE_PHOTO2 = 3;
    // 申请相机权限的requestCode
    private static final String[] sPermissonVal = {Manifest.permission.CAMERA,Manifest.permission.WRITE_EXTERNAL_STORAGE};
	private static final int PERMISSION_CAMERA_REQUEST_CODE = 3;
	private Button takePhoto;
	private ImageView picture;
	private Uri imageUri;

	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		//Android需加,不然使用intent打开相机,即使动态申请了相机权限,但还是会闪退
		if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { 
			StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
		    StrictMode.setVmPolicy(builder.build());
		}
		takePhoto = (Button) findViewById(R.id.take_photo);
		picture = (ImageView) findViewById(R.id.picture); 
		takePhoto.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				requestPermission();
			}
		});		
	}
	
    //申请权限
    private void requestPermission() {
        // Android6.0开始, 即当API大于等于 23 时,才动态申请权限
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
			Log.d(TAG,"requestPermission, Build.VERSION.SDK_INT = "+Build.VERSION.SDK_INT );
 	    	this.requestPermissions(sPermissonVal, PERMISSION_CAMERA_REQUEST_CODE);			
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
		Log.d(TAG,"onRequestPermissionsResult, requestCode = "+requestCode);
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode) {
            case PERMISSION_CAMERA_REQUEST_CODE:
        		Log.d(TAG,"onRequestPermissionsResult, grantResults.length = " + grantResults.length);
        		Log.d(TAG,"just note, PackageManager.PERMISSION_GRANTED = " + PackageManager.PERMISSION_GRANTED);
                //权限请求失败
                if (grantResults.length == sPermissonVal.length) {
                    for (int i=0;i<grantResults.length;i++) {
                		Log.d(TAG,"onRequestPermissionsResult, result = "+grantResults[i]);
                        if (grantResults[i] != PackageManager.PERMISSION_GRANTED) {
					        //用户已经拒绝过一次,再次弹出权限申请对话框需要给用户一个解释
					        if (this.shouldShowRequestPermissionRationale(sPermissonVal[i]) == false) {
	                        	//弹出对话框引导用户去设置
	                            showDialog();	//手动进入App,单独设置权限管理设置,“拒绝”->"询问"
					        }else {
	                            Toast.makeText(MainActivity.this, "请求权限被拒绝", Toast.LENGTH_LONG).show();					        	
					        }
                            break;
                        }
                    }
	                //允许权限,有调起相机拍照。
                    for(int i=0;i<grantResults.length;i++) {
                        if(grantResults[i] != PackageManager.PERMISSION_GRANTED) {
        	     			Log.d(TAG,"Permissions Fail, return");
                        	return;
                        }
                    }
	     			Log.d(TAG,"openCamera Now");
	                openCamera();                    
                }else{
            		Log.d(TAG,"onRequestPermissionsResult 10");
                    Toast.makeText(MainActivity.this, "授权不完整", Toast.LENGTH_LONG).show();
                }
                break;
        }
    }

    //弹出提示框
    private void showDialog(){
        @SuppressWarnings("unused")
		AlertDialog dialog = new AlertDialog.Builder(this)
                .setMessage("相机需要相机和读写权限,修改成“询问”或者“允许”,是否去设置?")
                .setPositiveButton("是", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.dismiss();
                        goToAppSetting();
                    }
                })
                .setNegativeButton("否", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.dismiss();
                    }
                })
                .setCancelable(false)
                .show();
    }

    // 跳转到当前应用的设置界面
    private void goToAppSetting(){
        Intent intent = new Intent();
        intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
        Uri uri = Uri.fromParts("package", getPackageName(), null);
        intent.setData(uri);
        startActivity(intent);
    } 

    private void openCamera() {
    	if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {	    		
			Log.d(TAG,"openCamera 1");
//				File outputImage = new File(Environment.getExternalStorageDirectory(),"output_image.jpg");	//存储根目录
			File outputImage = new File(getExternalCacheDir(),"output_image.jpg");	//内部存储设备/Android/data/com.example.choosepictest/cache/output_image.jpg
			try {
				if(outputImage.exists()) {
					outputImage.delete();
				}
				outputImage.createNewFile();
				Log.d(TAG,"openCamera createNewFile");
			} catch(IOException e) {
				Log.d(TAG,"openCamera e1");
				e.printStackTrace();
			}
		    //Android 7.0  FileProvider传入Uri对象
	        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){
	            imageUri = FileProvider.getUriForFile(MainActivity.this,
	                    "com.example.choosepictest.fileprovider",outputImage);
	        }else{
	            imageUri = Uri.fromFile(outputImage);
	        }
			imageUri = Uri.fromFile(outputImage);
			Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
			intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
			startActivityForResult(intent,TAKE_PHOTO);	//TAKE_PHOTO 拍摄好之后直接保存, TAKE_PHOTO2 拍摄并裁剪后保存				
    	}else {
			Log.d(TAG,"openCamera cannot access Storage ");
    	}
    }
	
	@Override
	protected void onActivityResult(int requestCode,int resultCode,Intent data) {
		Log.d(TAG,"onActivityResult 1");
		super.onActivityResult(requestCode, resultCode, data);
		switch(requestCode) {
		case TAKE_PHOTO:
			if(resultCode == RESULT_OK) {
				try {
					Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(imageUri));
					picture.setImageBitmap(bitmap);
				}catch(FileNotFoundException e) {
					e.printStackTrace();
				}
			}
			break;
		case TAKE_PHOTO2:
			if(resultCode == RESULT_OK) {
				Intent intent = new Intent("com.android.camera.action.CROP");
				intent.setDataAndType(imageUri, "image/*");
				intent.putExtra("scacle",true);
				intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
				startActivityForResult(intent,CROP_PHOTO);
			}
			break;
		case CROP_PHOTO:
			if(resultCode == RESULT_OK) {
				try {
					Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(imageUri));
					picture.setImageBitmap(bitmap);
				}catch(FileNotFoundException e) {
					e.printStackTrace();
				}
			}
			break;
		default:
			break;
		}
	}	

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		// Handle action bar item clicks here. The action bar will
		// automatically handle clicks on the Home/Up button, so long
		// as you specify a parent activity in AndroidManifest.xml.
		int id = item.getItemId();
		if (id == R.id.action_settings) {
			return true;
		}
		return super.onOptionsItemSelected(item);
	}
}

//project.properties

target=android-28
build-tools=25.0.2

//activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.choosepictest.MainActivity" >

    
    <Button
        android:id="@+id/take_photo"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Take Photo" />
    
    <ImageView 
        android:id="@+id/picture"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal" />    

</RelativeLayout>

//AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.choosepictest"
    android:versionCode="1"
    android:versionName="1.0" >

    <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"/>    
    
    <uses-sdk
        android:minSdkVersion="23"
        android:targetSdkVersion="24" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        
 		<provider
            android:authorities="com.example.choosepictest.fileprovider"
            android:name="android.support.v4.content.FileProvider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/provider_paths"/>
        </provider>           
        
    </application>

</manifest>

//res/xml/provider_paths.xml

在工程目录下res文件夹下新建xml文件夹,在xml下新建provider_paths.xml

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

你可能感兴趣的:(Android)