Catalog
Call System Camera
If it is not a special requirement, we usually call the system to take pictures to complete the work, and there is no need to implement a photo function by ourselves. It's very simple to call the system camera, just need one intent to jump to several interfaces, and then get the picture through onActivity Result.
Intent openCameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); // System Constant, the Key to Starting Camera startActivityForResult(openCameraIntent, REQUEST_CODE_TAKE_PICTURE); // Parameter constants are custom request code s that are useful for retrieving results
Get pictures
Rewrite the onActivityResult method to get request_code.
@Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { switch (requestCode) { case REQUEST_CODE_TAKE_PICTURE: // Write "How to Get Pictures" here. break; } }
How to Get Pictures
No storage directory specified
You can see from the top that Intent Action: MediaStore.ACTION_IMAGE_CAPTURE opens the camera and takes a picture and returns the result.
If no additional parameter MediaStore.EXTRA_OUTPUT is set to control the storage path of the image, the result will be a small Bitmap.
Bitmap bm = (Bitmap) data.getExtras().get("data"); ImageView.setImageBitmap(bm);
The above method is only suitable when the application needs a small picture. And after testing, it is found that the image saved is seriously distorted when compared with the preview image taken. The reason is that the pixels of the camera are very large now. Every picture is on M. The maximum memory allocated by Android system to each application is 16M. If the image is returned directly to the caller through memory, it will take up too much memory. So here is a processed thumbnail.
Specify storage directory
The second way to get a picture is to specify the location of the image in intent. This method obtains the original image. By setting MediaStore.EXTRA_OUTPUT parameters. This method saves the original image to the specified Uri without compression. The code is as follows:
// Open Camera Intent Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); // Specify storage locations for photographs taken String f = System.currentTimeMillis()+".jpg"; // Designated name Uri fileUri = Uri.fromFile(new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM), f)); // Specify the uri of the image to be saved, where the image is saved in the system album cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri); //Specify where the image is stored, and when specified, the Data in onActivityResult will be null // Start the camera startActivityForResult(cameraIntent, REQUEST_CODE_CAMERA);
Designated storage directories above Android 7.0
In general, the above "designated storage directory" method has no problem running; however, when targetSdkVersion is designated as 24 and above and running on API >= 24 (Android 7.0 or more) devices, an exception will be thrown:
android.os.FileUriExposedException: The file path and file name you specify (i.e. fileUri above) exposed beyond app through ClipData.Item.getUri()
Reason: Android no longer allows file://Uri to be exposed to other apps in apps, including but not limited to methods such as Intent or ClipData. The reason is that there are some risks in using file://Uri, such as: the file is private and the app receiving file://Uri cannot access the file.
Runtime privileges are introduced after Android 6.0. If the app receiving file://Uri does not apply for READ_EXTERNAL_STORAGE privileges, the crash will occur when the file is read.
Therefore, Google provides FileProvider, which generates content://Uri instead of file://Uri.
Simple Use of FileProvider
Simple use of FileProvider can be referred to: http://gelitenight.github.io/android/2017/01/29/solve-FileUriExposedException-caused-by-file-uri-with-FileProvider.html#fileprovider-1
I use FileProvider with reference to the description here. The specific method is not to go into detail, but to paste the code.
provider_paths.xml
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <external-path path="DCIM" name="external_files"/> </paths>
In the code:
// Open Camera Intent Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); // Specify storage locations for photographs taken String f = System.currentTimeMillis()+".jpg"; // Designated name File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM), f); // Designated file fileUri = FileProvider.getUriForFile(MainActivity.this, getPackageName() + ".provider", file); // Path Conversion cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri); //Specify where the image is stored, and when specified, the Data in onActivityResult will be null startActivityForResult(cameraIntent, REQUEST_CODE_CAMERA);
Next, I'll talk about some of the problems encountered in using the methods in the links.
-
android:name="android.support.v4.content.FileProvider" cannot identify problems when provider s are added to the Android Manifest. XML file.
Solution: android.support.v4.content.FileProvider was changed to androidx.core.content.FileProvider. The migration of Android libraries to Androidx resulted in the failure of android.support.v4.content.FileProvider. Replace the library. -
Error opening camera:
java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.res.XmlResourceParser android.content.pm.PackageItemInfo.loadXmlMetaData(android.content.pm.PackageManager, java.lang.String)' on a null object reference
This error occurs because android:authorities at Android Manifest. xml do not match mActivity. getPackageName ()+". provider".
In Android Manifest.xml:
android:authorities="${applicationId}.fileprovider"
In the code:
fileUri = FileProvider.getUriForFile(MainActivity.this, getPackageName() + ".provider", file); // Path Conversion
Change the code to:
fileUri = FileProvider.getUriForFile(MainActivity.this, getPackageName() + ".fileprovider", file); // Path Conversion
Problem solving.