Requirement: Call the phone camera by clicking the camera button, and display it on the screen after taking a photo
1. Layout file design
Place a button and an imageView control in the xml file (the picture is placed here)
PS: I personally recommend dragging components directly with constraint layout
code show as below:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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">
<Button
android:id="@+id/take_photo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="拍照"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.498"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.109" />
<ImageView
android:id="@+id/picture"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.461"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/guideline2"
tools:srcCompat="@drawable/baseline_child_care_24" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.5" />
</androidx.constraintlayout.widget.ConstraintLayout>
2. Grant permissions
Since the function we implement is to read and write data in public storage, we must use the "WRITE_EXTERNAL_STORAGE" permission, and we must remove "android:maxSdkVersion="18"".
Authorize in the manifest file
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="18"/>
3. Use the FIleProvider class
Since our needs need to share data (i.e. photos taken) between our current application and the camera, we need to use the FileProvider class
Configuration process:
First of all , you need to declare
AndroidManifest.xml
through tags in the file<provider>
and configure customandroid:authorities
attributes. The code is as follows:
<manifest>
<application>
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="my.itgungnir.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
</provider>
</application>
</manifest>
If your emulator version is below Android10, use android.support.v4.content.FileProvider
In order to allow other applications to access the files under the current application, we also need to configure which folders can be accessed. This step is also XML
configured in the file. We need to create a path configuration file under the project /res/xml
folder, named it file_paths.xml
(the file name can be customized), and the root node in this file is <paths>
to configure the folder under this node. An example configuration is as follows:
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="my_images" path="/"/>
</paths>
The path path is set to "/", which means that all folders can be accessed
After configuring each folder, we also need to reference this configuration in the label AndroidManifest.xml
in the file <provider>
, so that the configuration can take effect. Use <meta-data>
tags to refer to the configuration, the code is as follows:
<provider
android:authorities="Tom_LZK"
android:name="androidx.core.content.FileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths"/>
</provider>
<meta-data>
The attributes in the tags android:name
are fixed values android.support.FILE_PROVIDER_PATHS
, and android:resource
the attributes are references to the configuration files above.
Attach the code of MainActivity:
package com.example.arbitrary;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.FileProvider;
import java.io.File;
import java.io.IOException;
public class MainActivity extends AppCompatActivity {
public static final int TAKE_PHOTO = 1;
private ImageView picture;
private Uri imageUri;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button takePhoto = findViewById(R.id.take_photo);
picture = findViewById(R.id.picture);
takePhoto.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//创建File对象,用来存储拍照后的照片
//getExternalCacheDir()获取此应用缓存数据的位置,在这个位置保存图片
File outputImage = new File(getExternalCacheDir(), "output_image.jpg");
try {
if (outputImage.exists()) {//如果图片已经存在就删除再重新创建
outputImage.delete();
}
outputImage.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
imageUri = FileProvider.getUriForFile(MainActivity.this,
"Tom_LZK", outputImage);
//启动相机
Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
startActivityForResult(intent, TAKE_PHOTO);
}
});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == TAKE_PHOTO && resultCode == RESULT_OK) {
//显示拍出来的照片
Bitmap bitmap = BitmapFactory.decodeFile(getExternalCacheDir()+"//output_image.jpg");
picture.setImageBitmap(bitmap);
}
}
}
Finish.
Note: The authorities variable in the getUriForFile method should be consistent with the authorities in the provider