专栏目录
- 第一节 自定义轮播图的制作
- 第二节 底部导航栏菜单,炫酷菜单动画,背景变暗、按钮焦点获取
- 第三节 适配Android10的拍照、从相册获取代码,包括完整的权限申请和图片地址获取
- 第四节 百度定位、地图SDK,和风天气获取教程
- 第五节 微信朋友圈式九宫格添加图片展示(待更新)
- 第六节 第三方api获取淘宝数据,用RecyclerView进行商品展示、刷新和搜索(待更新)
引言
通过拍照和相册获取图片是App中常用的功能,而随着安卓版本的更新,在最新安卓系统上开发总是会出现各种各样的问题,所以我总结了适配Android10的拍照、从相册获取代码,包括完整的权限申请和图片地址获取,减少大家的工作量,同时进一步学习安卓开发。
效果图
注:因为用的虚拟机,所以拍照显示是乱的,真机运行正常。
Java代码
public class MainActivity extends AppCompatActivity {
//打开图片标记
private final int IMAGE_OPEN = 2;
//相机启动请求码
private static final int CAMERA_REQUEST_CODE = 1;
// 是否是Android 10以上手机
private boolean isAndroidQ = Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q;
// 用于保存图片的文件路径,Android 10以下使用图片路径访问图片
private String mCameraImagePath;
//用于保存拍照图片的uri
private Uri mCameraUri;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(null);
setContentView(R.layout.activity_main);
//第一步 测试权限并请求权限
PermissionUtil.checkPermission(this,null);
//相机点击事件
ImageView camera = findViewById(R.id.button_camera);
camera.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//动态权限:点击相机时获取相机权限
if (Build.VERSION.SDK_INT >= 23) {
String[] mPermissionList = new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.CAMERA};
ActivityCompat.requestPermissions(MainActivity.this, mPermissionList, 123);
}
//从相机获取图片
openCamera();
}
});
//相册点击事件
ImageView album = findViewById(R.id.button_album);
album.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//从相册获取图片
if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},1);
}
Intent photoPickerIntent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(photoPickerIntent, IMAGE_OPEN);
}
});
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
//第二步 申请权限结果用户禁用引到系统设置
PermissionUtil.onRequestPermissionsResult(this,requestCode,permissions,grantResults);
}
/**
* 调起相机拍照
*/
private void openCamera() {
//使用MediaStore.ACTION_IMAGE_CAPTURE,拍照到指定目录
Intent captureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// 判断是否有相机
if (captureIntent.resolveActivity(getPackageManager()) != null) {
File photoFile = null;
Uri photoUri = null;
if (isAndroidQ) {
// 适配android 10
photoUri = createImageUri();
} else {
try {
// android 10 以下版本
photoFile = createImageFile();
} catch (IOException e) {
e.printStackTrace();
}
if (photoFile != null) {
//获取绝对路径
mCameraImagePath = photoFile.getAbsolutePath();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
//适配Android 7.0文件权限,通过FileProvider创建一个content类型的Uri
photoUri = FileProvider.getUriForFile(this, getPackageName() + ".fileprovider", photoFile);
} else {
photoUri = Uri.fromFile(photoFile);
}
}
}
//得到照片的Uri
mCameraUri = photoUri;
if (photoUri != null) {
//以下两行代码是将图片保存到本地,可以看情况删掉
//照片原来存储的地方输出保存
captureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);
//表示添加写入权限。
captureIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
startActivityForResult(captureIntent, CAMERA_REQUEST_CODE);
}
}
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
switch (requestCode) {
// 调用相机后返回
case 1:
//打开相机
if (resultCode == RESULT_OK) {
if (isAndroidQ) {
// Android 10 使用图片uri加载
final Bitmap photo = getBitmapFromUri(MainActivity.this, mCameraUri);
ImageView Camera = findViewById(R.id.camera);
Camera.setImageBitmap(photo);
} else {
// 使用图片路径加载
final Bitmap photo = BitmapFactory.decodeFile(mCameraImagePath);
ImageView Camera = findViewById(R.id.camera);
Camera.setImageBitmap(photo);
}
} else {
Toast.makeText(this,"取消",Toast.LENGTH_LONG).show();
}
break;
//调用相册后返回
case 2:
//打开图片
if (resultCode == RESULT_OK) {
Uri uri = intent.getData();
if (!TextUtils.isEmpty(uri.getAuthority())) {
ImageView Album = findViewById(R.id.album);
//将Uri转成Bitmap
Album.setImageBitmap(getBitmapFromUri(this,uri));
//在真机上可以调用裁剪图片
//cropPhoto(uri);
}
}else {
Toast.makeText(this,"取消",Toast.LENGTH_LONG).show();
}
break;
//调用剪裁后返回
case 3:
Bundle bundle = intent.getExtras();
if (bundle != null) {
//在这里获得了剪裁后的Bitmap对象,可以用于上传
Bitmap image = bundle.getParcelable("data");
//设置到ImageView上
ImageView Album = findViewById(R.id.album);
Album.setImageBitmap(image);
}
break;
}
}
/**
* 裁剪图片
*/
private void cropPhoto(Uri uri) {
//使用com.android.camera.action.CROP 则直接打开裁剪照片的activity
Intent intent = new Intent("com.android.camera.action.CROP");
intent.setDataAndType(uri, "image/*");
//设置在开启的Intent中设置显示的view可裁剪
/*这段注释掉就不会跳转到裁剪的activity*/
intent.putExtra("crop", "true");
//设置x,y的比例,截图方框就按照这个比例来截 若设置为0,0,或者不设置 则自由比例截图
intent.putExtra("aspectX", 1);
intent.putExtra("aspectY", 2);
// 裁剪区的宽和高 其实就是裁剪后的显示区域 若裁剪的比例不是显示的比例,则自动压缩图片填满显示区域。若设置为0,0 就不显示。若不设置,则按原始大小显示
intent.putExtra("outputX", 150);
intent.putExtra("outputY", 300);
// true的话直接返回bitmap
intent.putExtra("return-data", true);
// 上面设为false的时候将MediaStore.EXTRA_OUTPUT即"output"关联一个Uri
//intent.putExtra("output", Uri);
// 看参数即可知道是输出格式
intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
// 想从Activity中获得返回数据,在启动Activity时候使用startActivityForResult方法
//3为请求代码,可以是任意值
startActivityForResult(intent, 3);
}
/**
* 创建图片地址uri,用于保存拍照后的照片 Android 10以后使用这种方法
*/
private Uri createImageUri() {
String status = Environment.getExternalStorageState();
// 判断是否有SD卡,优先使用SD卡存储,当没有SD卡时使用手机存储
if (status.equals(Environment.MEDIA_MOUNTED)) {
return getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, new ContentValues());
} else {
return getContentResolver().insert(MediaStore.Images.Media.INTERNAL_CONTENT_URI, new ContentValues());
}
}
/**
* 创建保存图片的文件,Android10之前使用
*/
private File createImageFile() throws IOException {
String imageName = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date());
File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
if (!storageDir.exists()) {
storageDir.mkdir();
}
File tempFile = new File(storageDir, imageName);
if (!Environment.MEDIA_MOUNTED.equals(EnvironmentCompat.getStorageState(tempFile))) {
return null;
}
return tempFile;
}
// 通过uri加载图片
public static Bitmap getBitmapFromUri(Context context, Uri uri) {
try {
ParcelFileDescriptor parcelFileDescriptor =
context.getContentResolver().openFileDescriptor(uri, "r");
FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
Bitmap image = BitmapFactory.decodeFileDescriptor(fileDescriptor);
parcelFileDescriptor.close();
return image;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
//将图片路径转为Uri
public static Uri getImageContentUri(Context context, String path) {
Cursor cursor = context.getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
new String[] { MediaStore.Images.Media._ID }, MediaStore.Images.Media.DATA + "=? ",
new String[] { path }, null);
if (cursor != null && cursor.moveToFirst()) {
int id = cursor.getInt(cursor.getColumnIndex(MediaStore.MediaColumns._ID));
Uri baseUri = Uri.parse("content://media/external/images/media");
return Uri.withAppendedPath(baseUri, "" + id);
} else {
// 如果图片不在手机的共享图片数据库,就先把它插入。
if (new File(path).exists()) {
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.DATA, path);
return context.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
} else {
return null;
}
}
}
}
PermissionUtil工具类代码
/**
* 权限管理工具,快速解决系统功能权限申请问题
* 一个个权限申请也太麻烦,这个批量申请能满足你的需求。
* 程序在android 6 版本大于 23 时,权限需要申请,在配置表中设置的权限当拒绝后,导至功能失常,或闪退现象
* 调用checkPermission申请权限回时调用 onRequestPermissionsResult
*/
public class PermissionUtil {
static String[] permissions;
/**
*
* 检测权限是否己申请,通过在启动应用程序时检测,当需要时,会自动弹出提示请求权限
* @param context 请求的 Activity
* @param pms 关键的权限,也就是必须要的权限 当为null 时,申请的全部权限都是必需的
* @return 需要请求返回 false,返回true时全部权限都已获取
*/
static public boolean checkPermission(Activity context,String[] pms){
int permissionCode=0;
int decode=0;
try {
// APP 权限
permissions = (pms!=null)?pms:context.getPackageManager().getPackageInfo(context.getPackageName(),PackageManager.GET_PERMISSIONS).requestedPermissions;
for(int i=0;i<permissions.length;i++){
System.out.println("PermissionUtil: " +permissions[i] );
//判断用户是否给这些权限授权
if(ContextCompat.checkSelfPermission(context, permissions[i]) != PackageManager.PERMISSION_GRANTED) {
permissionCode+=1;
//判断是否拒绝过
decode += ActivityCompat.shouldShowRequestPermissionRationale(context, permissions[i]) ? 1 : 0;
}
}
}catch (Exception e){
System.out.println("PermissionUtil checkPermission error :"+e.getMessage());
}
if(permissionCode>0) {
if(decode>0)
requestTip(context);
else
requestPermissions(context,permissions);
return false;
}
return true;
}
/**
* 请求获取权限 当权限需要申请时调用
* @param context 请求的 Activity
* @param perms 需要请求的权限
*/
static public void requestPermissions(Activity context,String[] perms){
ActivityCompat.requestPermissions(context, perms, 1);
}
/**
* 引导用户到设置权限
* @param context 请求的 Activity
*/
static public void toSetting(Context context){
Intent intent = new Intent();
intent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");
intent.setData(Uri.fromParts("package", context.getPackageName(), null));
context.startActivity(intent);
}
/**
* 提示请求权限 当拒绝了授权后,为提升用户体验,可以以弹窗的方式引导用户到设置中去进行设置
* @param context 请求的 Activity
*/
static public void requestTip(final Activity context){
new AlertDialog.Builder(context)
.setMessage("为更好体验,需要开启权限才能使用此功能!")
.setPositiveButton("设置", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
toSetting(context);
}
})
.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
context.finish();
}
})
.create()
.show();
}
/**
* 请求权限回调检测 如有拒绝 将直接引导到系统设置要求打开
* @param context 请求的 Activity
* @param requestCode
* @param permissions
* @param grantResults
*/
static public void onRequestPermissionsResult(Activity context,int requestCode, String[] permissions, int[] grantResults) {
if(requestCode!=1)return;
int code=0;
if (grantResults.length <1)return;
//用户是否拒绝了权限
for (int i=0;i<grantResults.length;i++)
code+=(grantResults[i]!= PackageManager.PERMISSION_GRANTED)?1:0;
if(code==0)return;
requestTip(context);
}
/**
* 设置中打开权限管理界面
* 跟据不同厂商进行快捷目录界面
* @param context
*/
public static void gotoPermissionManager(Context context) {
String brand = Build.BRAND;//手机厂商
if (TextUtils.equals(brand.toLowerCase(), "redmi")
|| TextUtils.equals(brand.toLowerCase(), "xiaomi")) {
gotoMiuiPermissionManager(context);//小米
return;
}
if (TextUtils.equals(brand.toLowerCase(), "meizu")) {
gotoMeizuPermissionManager(context);
return;
}
if (TextUtils.equals(brand.toLowerCase(), "huawei")
|| TextUtils.equals(brand.toLowerCase(), "honor")) {
gotoHuaweiPermissionManager(context);
return;
}
toSetting(context);
}
/**
* 跳转到魅族的权限管理系统
*/
private static void gotoMeizuPermissionManager(Context context) {
try {
Intent intent = new Intent();
intent.setAction("com.meizu.safe.security.SHOW_APPSEC");
intent.addCategory(Intent.CATEGORY_DEFAULT);
intent.putExtra("packageName", context.getPackageName());
context.startActivity(intent);
} catch (Exception e) {
toSetting(context);
}
}
/**
* 跳转到miui的权限管理页面
*/
private static void gotoMiuiPermissionManager(Context context) {
try { // MIUI 8
Intent localIntent = new Intent();
localIntent.setAction("miui.intent.action.APP_PERM_EDITOR");
localIntent.setClassName("com.miui.securitycenter", "com.miui.permcenter.permissions.PermissionsEditorActivity");
localIntent.putExtra("extra_pkgname", context.getPackageName());
context.startActivity(localIntent);
} catch (Exception e) {
try { // MIUI 5/6/7
Intent localIntent = new Intent("miui.intent.action.APP_PERM_EDITOR");
localIntent.setClassName("com.miui.securitycenter", "com.miui.permcenter.permissions.AppPermissionsEditorActivity");
localIntent.putExtra("extra_pkgname", context.getPackageName());
context.startActivity(localIntent);
} catch (Exception e1) { // 否则跳转到应用详情
toSetting(context);
}
}
}
/**
* 华为的权限管理页面
*/
private static void gotoHuaweiPermissionManager(Context context) {
try {
Intent intent = new Intent();
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
ComponentName comp = new ComponentName("com.huawei.systemmanager", "com.huawei.permissionmanager.ui.MainActivity");//华为权限管理
intent.setComponent(comp);
context.startActivity(intent);
} catch (Exception e) {
toSetting(context);
}
}
}
Layout xml 代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center_horizontal">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:orientation="horizontal"
android:gravity="center_horizontal">
<ImageView
android:id="@+id/button_camera"
android:src="@drawable/icon_photo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<ImageView
android:id="@+id/button_album"
android:src="@drawable/icon_album"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
<LinearLayout
android:background="#000"
android:layout_marginBottom="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/camera"
android:layout_width="150dp"
android:layout_height="250dp"/>
</LinearLayout>
<LinearLayout
android:background="#000"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/album"
android:layout_width="150dp"
android:layout_height="250dp"/>
</LinearLayout>
</LinearLayout>
AndroidManifest.xml中权限申请
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
权限申请流程
整理不易,还望有收获的同时点赞、收藏,谢谢。