Android calls the camera system and solve two major problems

Foreword

Source Demo: Click here to
two major problems call system Android camera encountered:

  • 1. Specify the path to store pictures, models call camera system Android7.0 and later throws android.os.FileUriExposedException an exception
  • 2. Specify the path to store pictures, the camera returns intent to call the system: null

Question one"

  • Android 7.0 system after the ban applied to the external public file: // URI, URI is required FileProvider to pass to the outside world. So for the system after Android 7.0 and need to do an adaptation.
  • The actual development, the recommended way. Know the file path, you can execute the appropriate compression processing on demand.

Start Code Example (Android Studio, SdkVersion 29)

  • Add 1️⃣AndroidManifest.xml manifest file required permissions
<!--相机权限-->
<uses-permission android:name="android.permission.CAMERA" />
<!--SD卡权限-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
  • 2️⃣ activity_play_photo(PlayPhotoActivity的xml界面)
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <ImageView
        android:id="@+id/ivMyPhoto"
        android:layout_width="300dp"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true" />
    <Button
        android:layout_width="match_parent"
        android:layout_height="56dp"
        android:layout_alignParentBottom="true"
        android:gravity="center"
        android:onClick="playPhoto"
        android:padding="16dp"
        android:text="拍照(原图-路径获取)"
        android:textColor="#FF212121"
        android:textSize="16sp"
        android:textStyle="bold" />
</RelativeLayout>
  • 3️⃣ PlayPhotoActivity (call your camera activity and return to show pictures)
public class PlayPhotoActivity extends BaseActivity {
    //定义一个文件夹路径
    private String localPath = MyApplication.localPath + File.separator + "123";
    private ImageView ivMyPhoto;
    private File photoFile;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_play_photo);
        ivMyPhoto = findViewById(R.id.ivMyPhoto);

        photoFile = new File(localPath, "temp.png");
        if ((photoFile.getParentFile() != null) && (!photoFile.getParentFile().exists())) {
            photoFile.getParentFile().mkdirs();
        }
        Log.e("相机", "路径-localPath:" + localPath);
    }

    //相机点击事件:打开照相机(该方式获取到的图片是原图)
    public void playPhoto(View view) {
        //创建打开本地相机的意图对象
        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        //设置图片的保存位置(兼容Android7.0)
        Uri fileUri = getUriForFile(this, photoFile);
        //指定图片保存位置
        intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);
        //开启意图
        startActivityForResult(intent, 100);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent intent) {
        super.onActivityResult(requestCode, resultCode, intent);
        //拍照完成后返回调用
        if (resultCode == RESULT_OK) {
            if (requestCode == 100) {
                //该方式获取到的图片是原图
                FileInputStream fis = null;
                try {
                    fis = new FileInputStream(photoFile);
                    Bitmap bitmap = BitmapFactory.decodeStream(fis);
                    ivMyPhoto.setImageBitmap(bitmap);
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    try {
                        if (fis != null)
                            fis.close();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            } 
        }
    }

    private Uri getUriForFile(Context context, File file) {
        Uri fileUri;
        if (Build.VERSION.SDK_INT >= 24) {
            //参数:authority 需要和清单文件中配置的保持完全一致:${applicationId}.xxx
            fileUri = FileProvider.getUriForFile(context, context.getPackageName() + ".xxx", file);
        } else {
            fileUri = Uri.fromFile(file);
        }
        return fileUri;
    }
}
  • 4️⃣ manifest file configuration
  1. Before use SdkVersion 29: android.support.v4 (described below)
    Android: name = "android.support.v4.content.FileProvider"
  2. SdkVersion 29 started: androidx (described below)
    Android: name = "androidx.core.content.FileProvider"
  3. Authorities can define (default protocol: the present application package defined string name +)
    Android: Authorities = "package name .xxx"
        <provider
            android:name="androidx.core.content.FileProvider"
            android:authorities="${applicationId}.xxx"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths" />
        </provider>
  • 5️⃣ res directory created in the xml directory, and res / xml create a file directory: file_paths (shown as Code)
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <root-path
        name="root"
        path="" />
    <!--files-path  相当于 getFilesDir()-->
    <files-path
        name="files"
        path="path" />
    <!--cache-path  相当于 getCacheDir()-->
    <cache-path
        name="cache"
        path="path" />
    <!--external-path  相当于 Environment.getExternalStorageDirectory()-->
    <external-path
        name="external"
        path="path" />
    <!--external-files-path  相当于 getExternalFilesDir("") -->
    <external-files-path
        name="external-files"
        path="path" />
    <!--external-cache-path  相当于 getExternalCacheDir() -->
    <external-cache-path
        name="external-cache"
        path="path" />
</paths>

Problem "two"

  • When calling system cameras, if passed: the specified path (file saved addresses), then the activity of the callback method: onActivityResult in, intent objects will be null.
  • Problems such as a sample code: onActivityResult intent of the object is also null
  • How to solve it? May reference to the following codes (the actual development, this method is not recommended, the way to obtain the image data of the picture compression system Android.)

Start Code Example (Android Studio, SdkVersion 29)

  • 1️⃣ refer to "issue a" first step
  • 2️⃣ refer to "issue a" second step
  • 3️⃣ PlayPhotoActivity (call your camera activity and return to show pictures)
public class PlayPhotoActivity extends BaseActivity {
    private ImageView ivMyPhoto;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_play_photo);
        ivMyPhoto = findViewById(R.id.ivMyPhoto);
    }
    //相机点击事件:打开照相机(该方式获取到的图片是缩略图)
    public void playPhoto(View view) {
        //创建打开本地相机的意图对象
        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        //如果intent指定了存储图片的路径,那么onActivityResult回调中Intent对象就会为null
        //intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
        //开启意图
        startActivityForResult(intent, 200);
    }
    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent intent) {
        super.onActivityResult(requestCode, resultCode, intent);
        //拍照完成后返回调用
        if (resultCode == RESULT_OK) {
            if (requestCode == 200) {
                //该方式获取到的图片是缩略图
                Bundle bundle = intent.getExtras();
                Bitmap bitmap = (Bitmap) bundle.get("data");
                ivMyPhoto.setImageBitmap(bitmap);
            }
        }
    }
}

Guess you like

Origin www.cnblogs.com/io1024/p/11590382.html