在android 11之后,android系统存储权限被强制分区,所以照片存储也变得越来越麻烦,加大了开发出现的问题,以下是本人写的demo,沉余代码比较多,我就不删除了,大家也可以通过这些,看到我的调试过程
1.首先,我们需要给应用授权,并申请权限(这没什么好解释的,开发的都懂)
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.CAMERA" />
String permission[] = {"android.permission.WRITE_EXTERNAL_STORAGE", "android.permission.READ_EXTERNAL_STORAGE"};
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED
|| ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED
// ||ContextCompat.checkSelfPermission(this,Manifest.permission.MANAGE_EXTERNAL_STORAGE)!=PackageManager.PERMISSION_GRANTED
) {
//6.0 以上
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
requestPermissions(permission, 100);
}
}
2.android11 之后剪裁照片就不能使用file://了,建议使用 MediaStore.Images.Media 来处理,但是问题是,在相册会对应生成bitmap照片,我的处理方式是,在逻辑完成之后删除生成的照片,避免影响用户体验
private void cut(Uri uri) {
Intent intent = new Intent("com.android.camera.action.CROP");
intent.setDataAndType(uri, "image/*");
intent.putExtra("crop", "true");
intent.putExtra("scale ", true); //是否保留比例
intent.putExtra("aspectX", 1);
intent.putExtra("aspectY", 1);
intent.putExtra("outputX", 300);
intent.putExtra("outputY", 300);
intent.putExtra("return-data", true);
intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
cutUri = createR(uri);
Log.e("clm", "createR: " + cutUri);
intent.putExtra(MediaStore.EXTRA_OUTPUT, cutUri);
}
cut_x = true;
launcher.launch(intent);
}
删除照片
getContentResolver().delete(cutUri, null);
3.但是你以为这样就搞定了吗?不,太天真了,还有我们的google手机呢。google相册的Uri和我们手机的不同需要特殊处理,不然无法识别到媒体
以上就是我打印出来的路径,google相册需要转换成常规的media,那就是使用bitmap重新替换一张照片,至少我是这样做的。。。
private Uri toUri(Uri uri) {
// 1. 获取 Google Photos 照片 Uri 的输入流,并转为 Bitmap
InputStream is = null;
try {
is = getContentResolver().openInputStream(uri);
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
}
Bitmap bitmap = BitmapFactory.decodeStream(is);
// 2. 将 bitmap 保存到手机本地相册中获取返回的 uri
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
String path = MediaStore.Images.Media.insertImage(getContentResolver(), bitmap, "temp", null);
Log.e("clm", "path: " + path);
// 能被正确解析的 uri
Uri result = Uri.parse(path);
return result;
}
private void cut(Uri uri) {
Intent intent = new Intent("com.android.camera.action.CROP");
if (uri.toString().contains("content://com.google.android.apps.photos.contentprovider")) {
//google相册里面的照片地址是需要转换的
tempToUri = toUri(uri);
} else {
tempToUri = null;
}
intent.setDataAndType(tempToUri == null ? uri : tempToUri, "image/*");
intent.putExtra("crop", "true");
intent.putExtra("scale ", true); //是否保留比例
intent.putExtra("aspectX", 1);
intent.putExtra("aspectY", 1);
intent.putExtra("outputX", 300);
intent.putExtra("outputY", 300);
intent.putExtra("return-data", false);
intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
cutUri = createR(uri);
Log.e("clm", "createR: " + cutUri);
intent.putExtra(MediaStore.EXTRA_OUTPUT, cutUri);
}
cut_x = true;
launcher.launch(intent);
}
至此,项目关键点都已列出,可以根据需要开发或者修改。另外如果大佬有更好的方法或者文中有错误地方,希望不吝赐教,感谢!!!
扫描二维码关注公众号,回复:
17105322 查看本文章
以下是全部代码,需要的可以自行copy !
package com.u8.base_dialog;
import android.Manifest;
import android.app.Activity;
import android.content.ContentValues;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.provider.Settings;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import androidx.activity.result.ActivityResult;
import androidx.activity.result.ActivityResultCallback;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContract;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityOptionsCompat;
import androidx.core.content.ContextCompat;
import androidx.core.content.FileProvider;
import androidx.core.content.PackageManagerCompat;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
public class SelectPhotoActivity extends AppCompatActivity {
String permission[] = {"android.permission.WRITE_EXTERNAL_STORAGE", "android.permission.READ_EXTERNAL_STORAGE"};
private ImageView iv_photo;
private boolean cut_x = false;
private Uri cutUri;
private Uri tempToUri;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.select_photo_activity);
iv_photo = findViewById(R.id.iv_photo);
findViewById(R.id.btn_select_photo).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
cut_x = false;
selectPhoto();
}
});
findViewById(R.id.btn_test_ac).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
testActivity();
}
});
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED
|| ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED
// ||ContextCompat.checkSelfPermission(this,Manifest.permission.MANAGE_EXTERNAL_STORAGE)!=PackageManager.PERMISSION_GRANTED
) {
//6.0 以上
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
requestPermissions(permission, 100);
}
}
}
private ActivityResultLauncher launcher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), new ActivityResultCallback<ActivityResult>() {
@Override
public void onActivityResult(ActivityResult result) {
// Log.e("clm","----action: "+result.getData().getAction());
// Log.e("clm","----cate: "+result.getData().getCategories());
Log.e("clm", "----: " + result.getResultCode());
Log.e("clm", "----result ok: " + Activity.RESULT_OK);
if (result.getData() != null) {
Uri uri = result.getData().getData();
Log.e("clm", "uri: " + uri);
if (uri != null) {
if (!cut_x) {
cut(uri);
return;
}
Bitmap bitmap = null;
try {
bitmap = BitmapFactory.decodeStream(getContentResolver().
openInputStream(uri));
Log.e("clm", "bitmap: " + bitmap);
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
}
if (bitmap == null) {
Bundle bundle = result.getData().getExtras();
if (bundle != null) {
bitmap = (Bitmap) bundle.get("data");
}
}
saveImg(bitmap);
iv_photo.setImageBitmap(bitmap);
//删除临时保存在相册的文件
/**
* 轻轻的存 正如我轻轻的删 不留下一张照片
*/
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
getContentResolver().delete(cutUri, null);
if (tempToUri != null) {
getContentResolver().delete(tempToUri, null);
}
}
Log.e("clm", "走了这里111111");
} else {
Bitmap bitmap;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
try {
bitmap = BitmapFactory.decodeStream(getContentResolver().
openInputStream(cutUri));
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
}
} else {
bitmap = result.getData().getExtras().getParcelable("data");
saveImg(bitmap);
}
iv_photo.setImageBitmap(bitmap);
Log.e("clm", "走了这里2222");
}
}
}
});
private void selectPhoto() {
Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
intent.setType("image/*");
launcher.launch(intent);
}
private void cut(Uri uri) {
Intent intent = new Intent("com.android.camera.action.CROP");
if (uri.toString().contains("content://com.google.android.apps.photos.contentprovider")) {
//google相册里面的照片地址是需要转换的
tempToUri = toUri(uri);
} else {
tempToUri = null;
}
intent.setDataAndType(tempToUri == null ? uri : tempToUri, "image/*");
intent.putExtra("crop", "true");
intent.putExtra("scale ", true); //是否保留比例
intent.putExtra("aspectX", 1);
intent.putExtra("aspectY", 1);
intent.putExtra("outputX", 300);
intent.putExtra("outputY", 300);
intent.putExtra("return-data", false);
intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
cutUri = createR(uri);
Log.e("clm", "createR: " + cutUri);
intent.putExtra(MediaStore.EXTRA_OUTPUT, cutUri);
}
cut_x = true;
launcher.launch(intent);
}
private Uri toUri(Uri uri) {
// 1. 获取 Google Photos 照片 Uri 的输入流,并转为 Bitmap
InputStream is = null;
try {
is = getContentResolver().openInputStream(uri);
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
}
Bitmap bitmap = BitmapFactory.decodeStream(is);
// 2. 将 bitmap 保存到手机本地相册中获取返回的 uri
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
String path = MediaStore.Images.Media.insertImage(getContentResolver(), bitmap, "temp", null);
Log.e("clm", "path: " + path);
// 能被正确解析的 uri
Uri result = Uri.parse(path);
return result;
}
private Uri createR(Uri uri) {
File file = new File(Environment.getExternalStorageDirectory().getPath() + File.separator + "clm.jpg");
if (!file.getParentFile().exists())
{
file.getParentFile().mkdirs();
}
ContentValues contentValues = new ContentValues();
contentValues.put(MediaStore.Images.Media.DATA, file.getAbsolutePath());
contentValues.put(MediaStore.Images.Media.DISPLAY_NAME, "clm.jpg");
contentValues.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
contentValues.put(MediaStore.Video.Media.DATE_ADDED, System.currentTimeMillis() / 1000);
contentValues.put(MediaStore.Video.Media.DATE_MODIFIED, System.currentTimeMillis() / 1000);
Uri newUrl = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues);
return newUrl;
}
private void saveImg(Bitmap bitmap) {
String testPath = Environment.getExternalStorageDirectory() + File.separator + "test.jpg";
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
testPath = getExternalFilesDir("clm").getAbsolutePath() + File.separator + "test.jpg";
File file = new File(testPath);
if (!file.getParentFile().exists()) {
file.getParentFile().mkdir();
}
}
Log.e("clm", "testPath: " + testPath);
File file = new File(testPath);
try {
FileOutputStream fileOutputStream = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.PNG, 100, fileOutputStream);
fileOutputStream.flush();
fileOutputStream.close();
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private void testActivity() {
launcher.launch(new Intent(this, MainActivity.class));
}
}