在Android 6.0的时候我们进行拍照 需要动态权限不然会报错, 有的也就直接崩溃,都没有错误日志,今天先说动态授权,并介入到拍照,拍照的话在7.0 的时候使用直接的包名储存会进行报错,就需要一个共享地址去储存砸门的图片,大致的问题就这些,接下来我们进行代码实现并进行讲解。
我们使用摄像头所以第一步现在我们的清单文件也就是AndroidManifest中添加
<uses-permission android:name="android.permission.CAMERA"/>
public class MainActivity extends AppCompatActivity {
private Button viewById;
private final int MIME = 5; //权限回调参数
private final int CAMERA_DATA = 6;//摄像头回调
private Uri uriForFile;
private ImageView image;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewById = findViewById(R.id.butt);
image = findViewById(R.id.imageView);
viewById.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.CAMERA}, MIME);
} else {
call();
}
}
});
}
public void call() {
File outImage = new File(getExternalCacheDir(), "outputimage.jpg");
if (outImage.exists()) {
outImage.delete();
}
try {
outImage.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
if (Build.VERSION.SDK_INT >= 24) {
uriForFile = FileProvider.getUriForFile(MainActivity.this, "com.example.jing.myapplication,fileprovider", outImage);
} else {
uriForFile = Uri.fromFile(outImage);
}
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, uriForFile);
startActivityForResult(intent, CAMERA_DATA);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
switch (requestCode) {
case MIME:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
call();
} else {
Toast.makeText(this, "您尚未打开摄像头的权限", Toast.LENGTH_SHORT).show();
}
break;
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
switch (requestCode) {
case CAMERA_DATA:
if (resultCode==Activity.RESULT_OK){
try {
Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(uriForFile));
image.setImageBitmap(bitmap);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
break;
}
}
}
看完以上代码如果是一脸懵逼的话,OK 接下来就看详细的解释
首先 viewById 是我们的按钮我通过匿名点击的方法进行申请权限和打开摄像头,这个就不多解释了
if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED)
在这需要看的是 此方法 ContextCompat.checkSelfPermission 是我们进行权限 判断 是否有此权限 又 Android 提供的方法、
checkSelfPermission 的第一个参数是Context 第二个参数是具体的权限名 Manifest.permission.CAMERA PackageManager.PERMISSION_GRANTED 此常量为0 进行判断是否已经申请 如果已经申请过那就会走else 的方法直接调用 call();打开摄像头
OK ContextCompat.checkSelfPermission(Context,String manager)参数说完我们说一下 当没有权限的时候要调用
ActivityCompat.requestPermissions();此方法的第一个参数是Activity的实例,第二个是String 数组 , 我们把我们的权限申请写道此数组中,第三个参数是一个int 值,此值就好比状态码,只要是唯一的int 值就行
调完ActivityCompat.requestPermissions(); 系统就会弹出权限申请的对话框,用户进行选择是或否,不管是什么结果都会回调到onRequestPermissionsResult(); 方法中授权的结果就是 grantResults参数我们对grantResults进行判断并调用 call();方法。
到这我们的 权限申请已经写完了,接下来我们解析call();方法进行打开摄像头。
首先创建了File对象,用来储存摄像头的图片,并把图片命名为output.jpg,并储存到手机SD 的应用下不应该是缓存目录下,
getExternalCacheDir();为缓存目录要这个目录下去找到它是/Android/data/包名/cache,使用此目录是因为从Android6.0开始读写权限已经被列为了危险权限,如果放在别的路径下那我们就要运行时权限,当然运行权限我们已经学习过了。Build.VERSION.SDK_INT >= 24 要判断手机是否是大于7.0 因为从Android7.0 就要使用Uri不然会出问题因为我们要使用了一个共享目录才行 大于7.0 就调用FilePrvider的getUriForFile();如果小于就直接调用formFile();接下在构建了意图也就是Intent并启动,启动是通过startAcivityForResult();这样拍照完毕后我们回调到onActivityResult();方法中如果发现拍照成功那么就调用BitmapFactory()方法中的人codeStream();将图片解析成Bitmap并进行展示。
以为这样就完了?
不一你错我们上边说过,我们有一个共享目录没有创建接下来我们创建共享目录。
在AndroidManifest.xml中进行注册
<provider
android:authorities="com.example.jing.myapplication,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/file_paths"
/>
</provider>
此时有人说android:authorities:"";中的属性是什么我告诉你只需要和我们FileProvider():中方法一样就行 。
接下在创建,file_paths文件右击res-new-Directory,创建xml目录在xml目录new-File,创建file_pats.xml文件,
<?xml version="1.0" encoding="utf-8"?>
<paths >
<external-path
name="name"
path="."/>
</paths>
external-path 中的name 可以随意写,path 中就是我们的地址有的人不写 点不会报错, 如果不写就写一个点, 他代表任意。