8种机械键盘轴体对比
本人程序员,要买一个写代码的键盘,请问红轴和茶轴怎么选?
Android N也已经发布了将近一年了,各大手机厂商陆陆续续也开始更新N了,刚好最近工作中又遇到了需要拍照和选取本地图片的功能,之前写的东西在同事新买的手机上完全不好使,没有办法,也就借机研究了下7.0上的适配问题。
一、问题的发现
虽然很早就知道Android在7.0版本后对文件共享方面有所修改,但一直也没有进行深入的研究,刚好最近自己的产品在同事7.0的手机上拍照和图片选取都有问题。拿过来打出log一看,发现一直报的问题是文件找不到和FileUriExposedException的错误。
那么为什么会出现这类问题呢,Android7.0为了提高私有文件的安全性,启用了一些新的策略机制,使得file://uri类型的文件不能被访问,因此如果还采用以前的文件机制,将会报FileURIExposedException错误。
解决方法
针对此类问题,就需要通过FileProvider来解决了。本文主要来通过调用相机和选取本地图片及裁剪在7.0上的适配,顺便来介绍FileProvider的使用。
官方链接:https://developer.android.com/reference/android/support/v4/content/FileProvider.html
二、FileProvider的使用
1、 在Androidmanifest中声明FileProvider1
2
3
4
5
6
7
8
9
10
11
12
13
14
...
...
android:name="android.support.v4.content.FileProvider"
android:authorities="com.mydomain.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
...
...
name:可以使用系统提供的android.support.v4.content.FileProvider,或者使用自己定义的类的路径。
authorities:所属者,此处无过多限制,最好使用当前包名,或者相关名称即可。在FileProvider使用的过程中会用到。
exported:是否公有(也就是外部能否访问)。
grantUriPermissions:设置为true,你才有权操作文件
2、指定可用文件
FileProvider只能针对预先声明的目录文件生成URI,需要在res/xml建立对应路径文件,并添加paths节点。必须包含一个或者多个如下节点:1
2
3
4
5* 对应Context.getFilesDir()下的路径
* 对应getCacheDir()下的路径
* 对应Environment.getExternalStorageDirectory()下的路径
* 对应Context.getExternalFilesDir(String) Context.getExternalFilesDir(null)下的路径
* 对应Context.getExternalCacheDir()下的路径
属性:name=”name” URI路径。为了提高安全性,name用来隐藏你共享的子目录的名称。
属性:path=”path” 分享对应的子目录的名称。
添加完成后,为声明的FileProvider添加属性1
2
3
4
5
6
7
8
9
android:name="android.support.v4.content.FileProvider"
android:authorities="com.mydomain.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
3、生成对应文件路径的URI
为了在不同的APP之间共享文件,我们需要针对文件生成一个URI,可以通过getUriForFile()来实现。1
2
3File imagePath = new File(Context.getFilesDir(), "images");
File newFile = new File(imagePath, "default_image.jpg");
Uri contentUri = getUriForFile(getContext(), "com.mydomain.fileprovider", newFile);
4、给生成的URI赋予临时权限
为了使URI访问不受限制,我们需要针对URI赋予临时权限,否则还会报错,方法如下1
2intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
官方文档给出的是setFlags(),不过个人建议使用addFlags(),内容包含FLAG_GRANT_READ_URI_PERMISSION(读)或者FLAG_GRANT_WRITE_URI_PERMISSION(写)。
5、完成为另一个APP一共URI
三、拍照保存
URI生成方法1
2
3
4
5
6
7
8
9
10//当然为了适应所有版本,我们做出如下修改
public static Uri getUriForFile(Context context, File file) {
Uri uri;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
uri = FileProvider.getUriForFile(context.getApplicationContext(), "com.mydomain.fileprovider", file);
} else {
uri = Uri.fromFile(file);
}
return uri;
}
相机调取1
2
3
4
5
6
7
8
9
10
11
12
13
14
15/**
* 拍照
*
* @param outputFileUri //照片保存路径
* @param requestCode
* @param activity
*/
public static void takePhoto(File outputFileUri, int requestCode, Activity activity) {
if (activity == null) {
return;
}
Intent getImageByCamera = new Intent("android.media.action.IMAGE_CAPTURE")
.putExtra(MediaStore.EXTRA_OUTPUT, getUriForFile(activity, outputFileUri));
activity.startActivityForResult(getImageByCamera, requestCode);//拍照
}
图片裁剪1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21/**
* 裁剪图片
*
* @param orgFile //文件原路径
* @param cropImage //裁剪保存路径
* @param requestCode
* @param activity
*/
public static void cropImage(File orgFile, File cropImage, int requestCode, Activity activity) {
Intent intent = new Intent("com.android.camera.action.CROP");
intent.setDataAndType(getUriForFile(activity, orgFile), "image/*");
intent.putExtra("crop", "true");
intent.putExtra("aspectX", 1);
intent.putExtra("aspectY", 1);
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(cropImage));
intent.putExtra("return-data", false);
intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
//设置权限
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
activity.startActivityForResult(intent, requestCode);
}