安卓10(Android10API29)保存图片到相册DCIM/Camera
Posted Wei_Leng
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了安卓10(Android10API29)保存图片到相册DCIM/Camera相关的知识,希望对你有一定的参考价值。
大家都知道android10最大的变化可能就是Scoped Storage(分区存储)。对于把图片保存到相册的应用,影响就大了,因为这个功能在Android10的手机上就会出现异常了,今天就来说说如何兼容Android10保存图片到相册。
1、要存储权限
protected void save()
AndPermission.with(getContext())
.runtime()
.permission(Permission.WRITE_EXTERNAL_STORAGE,Permission.READ_EXTERNAL_STORAGE)
.onGranted(permissions ->
Object uri = urls.get(isInfinite ? position % urls.size() : position);//图片地址
saveNetPic(getContext(),uri);position));
)
.onDenied(permissions ->
ToastUtil.showLong("权限被拒绝!");
)
.start();
2、保存到本应用的文件目录下,这个步骤不需要权限
private void saveNetPic(final Context mContext,Object uri)
final Handler mainHandler = new Handler(Looper.getMainLooper());
final ExecutorService executor = Executors.newSingleThreadExecutor();
executor.execute(new Runnable()
@Override
public void run()
File source = imageLoader.getImageFile(mContext, uri);
try
//1. create path
String dirPath = mContext.getExternalFilesDir(Environment.DIRECTORY_PICTURES).getAbsolutePath();
File dirFile = new File(dirPath);
if (!dirFile.exists()) dirFile.mkdirs();
ImageType type = ImageHeaderParser.getImageType(new FileInputStream(source));
String ext = getFileExt(type);
final File target = new File(dirPath, System.currentTimeMillis() + "." + ext);
if (target.exists()) target.delete();
target.createNewFile();
//2. save,保存到本应用目录
writeFileFromIS(target, new FileInputStream(source));
//3. notify
MediaScannerConnection.scanFile(mContext, new String[]target.getAbsolutePath(),
new String[]"image/" + ext, new MediaScannerConnection.OnScanCompletedListener()
@Override
public void onScanCompleted(final String path, Uri uri)
mainHandler.post(new Runnable()
@Override
public void run()
Toast.makeText(mContext, "已保存到相册!", Toast.LENGTH_SHORT).show();
//4.保存到相册
try
Bitmap bitmap = BitmapFactory.decodeFile(target.getAbsolutePath());
saveBitmap(getContext(),bitmap);
catch (Exception e)
e.printStackTrace();
);
);
catch (IOException e)
e.printStackTrace();
);
3、通过SAF的方式保存文件到任意位置
public void saveBitmap(Context context, Bitmap bitmap)
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.DESCRIPTION, "This is an image");
values.put(MediaStore.Images.Media.DISPLAY_NAME, "Image.png");
values.put(MediaStore.Images.Media.MIME_TYPE, "image/png");
values.put(MediaStore.Images.Media.TITLE, System.currentTimeMillis()+".png");
values.put(MediaStore.Images.Media.RELATIVE_PATH, "DCIM/Camera");
Uri external = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
ContentResolver resolver = context.getContentResolver();
Uri insertUri = resolver.insert(external, values);
OutputStream os = null;
if (insertUri != null)
try
os = resolver.openOutputStream(insertUri);
bitmap.compress(Bitmap.CompressFormat.PNG, 90, os);
catch (IOException e)
e.printStackTrace();
finally
try
if (os != null)
os.close();
catch (IOException e)
e.printStackTrace();
其中写入文件流和判断图片格式的代码如下:
写入文件流
private static boolean writeFileFromIS(final File file, final InputStream is)
OutputStream os = null;
try
os = new BufferedOutputStream(new FileOutputStream(file));
byte data[] = new byte[8192];
int len;
while ((len = is.read(data, 0, 8192)) != -1)
os.write(data, 0, len);
return true;
catch (IOException e)
e.printStackTrace();
return false;
finally
try
is.close();
catch (IOException e)
e.printStackTrace();
try
if (os != null)
os.close();
catch (IOException e)
e.printStackTrace();
判断图片类型:
private static String getFileExt(ImageType type)
switch (type)
case GIF:
return "gif";
case PNG:
case PNG_A:
return "png";
case WEBP:
case WEBP_A:
return "webp";
case JPEG:
return "jpeg";
return "jpeg";
还有个ImageHeaderParser
来至 XPopup
import static com.lxj.xpopup.enums.ImageType.GIF;
import static com.lxj.xpopup.enums.ImageType.JPEG;
import static com.lxj.xpopup.enums.ImageType.PNG;
import static com.lxj.xpopup.enums.ImageType.PNG_A;
import static com.lxj.xpopup.enums.ImageType.UNKNOWN;
/**
* Date: 2020/3/24
* author: SmallCake
*/
public class ImageHeaderParser
private static final int GIF_HEADER = 0x474946;
private static final int PNG_HEADER = 0x89504E47;
static final int EXIF_MAGIC_NUMBER = 0xFFD8;
// WebP-related
// "RIFF"
private static final int RIFF_HEADER = 0x52494646;
// "WEBP"
private static final int WEBP_HEADER = 0x57454250;
// "VP8" null.
private static final int VP8_HEADER = 0x56503800;
private static final int VP8_HEADER_MASK = 0xFFFFFF00;
private static final int VP8_HEADER_TYPE_MASK = 0x000000FF;
// 'X'
private static final int VP8_HEADER_TYPE_EXTENDED = 0x00000058;
// 'L'
private static final int VP8_HEADER_TYPE_LOSSLESS = 0x0000004C;
private static final int WEBP_EXTENDED_ALPHA_FLAG = 1 << 4;
private static final int WEBP_LOSSLESS_ALPHA_FLAG = 1 << 3;
public static ImageType getImageType(InputStream is) throws IOException
Reader reader = new StreamReader(is);
final int firstTwoBytes = reader.getUInt16();
// JPEG.
if (firstTwoBytes == EXIF_MAGIC_NUMBER)
return JPEG;
final int firstFourBytes = (firstTwoBytes << 16 & 0xFFFF0000) | (reader.getUInt16() & 0xFFFF);
// PNG.
if (firstFourBytes == PNG_HEADER)
// See: http://stackoverflow.com/questions/2057923/how-to-check-a-png-for-grayscale-alpha
// -color-type
reader.skip(25 - 4);
int alpha = reader.getByte();
// A RGB indexed PNG can also have transparency. Better safe than sorry!
return alpha >= 3 ? PNG_A : PNG;
// GIF from first 3 bytes.
if (firstFourBytes >> 8 == GIF_HEADER)
return GIF;
// WebP (reads up to 21 bytes). See https://developers.google.com/speed/webp/docs/riff_container
// for details.
if (firstFourBytes != RIFF_HEADER)
return UNKNOWN;
// Bytes 4 - 7 contain length information. Skip these.
reader.skip(4);
final int thirdFourBytes =
(reader.getUInt16() << 16 & 0xFFFF0000) | (reader.getUInt16() & 0xFFFF);
if (thirdFourBytes != WEBP_HEADER)
return UNKNOWN;
final int fourthFourBytes =
(reader.getUInt16() << 16 & 0xFFFF0000) | (reader.getUInt16() & 0xFFFF);
if ((fourthFourBytes & VP8_HEADER_MASK) != VP8_HEADER)
return UNKNOWN;
if ((fourthFourBytes & VP8_HEADER_TYPE_MASK) == VP8_HEADER_TYPE_EXTENDED)
// Skip some more length bytes and check for transparency/alpha flag.
reader.skip(4);
return (reader.getByte() & WEBP_EXTENDED_ALPHA_FLAG) != 0 ? ImageType.WEBP_A : ImageType.WEBP;
if ((fourthFourBytes & VP8_HEADER_TYPE_MASK) == VP8_HEADER_TYPE_LOSSLESS)
// See chromium.googlesource.com/webm/libwebp/+/master/doc/webp-lossless-bitstream-spec.txt
// for more info.
reader.skip(4);
return (reader.getByte() & WEBP_LOSSLESS_ALPHA_FLAG) != 0 ? ImageType.WEBP_A : ImageType.WEBP;
is.close();
return ImageType.WEBP;
private interface Reader
int getUInt16() throws IOException;
short getUInt8() throws IOException;
long skip(long total) throws IOException;
int read(byte[] buffer, int byteCount) throws IOException;
int getByte() throws IOException;
private static final class StreamReader implements Reader
private final InputStream is;
// Motorola / big endian byte order.
StreamReader(InputStream is)
this.is = is;
@Override
public int getUInt16() throws IOException
return (is.read() << 8 & 0xFF00) | (is.read() & 0xFF);
@Override
public short getUInt8() throws IOException
return (short) (is.read() & 0xFF);
@Override
public long skip(long total) throws IOException
if (total < 0)
return 0;
long toSkip = total;
while (toSkip > 0)
long skipped = is.skip(toSkip);
if (skipped > 0)
toSkip -= skipped;
else
// Skip has no specific contract as to what happens when you reach the end of
// the stream. To differentiate between temporarily not having more data and
// having finished the stream, we read a single byte when we fail to skip any
// amount of data.
int testEofByte = is.read();
if (testEofByte == -1)
break;
else
toSkip--;
return total - toSkip;
@Override
public int read(byte[] buffer, int byteCount) throws IOException
int toRead = byteCount;
int read;
while (toRead > 0 && ((read = is.read(buffer, byteCount - toRead, toRead)) != -1))
toRead -= read;
return byteCount - toRead;
@Override
public int getByte() throws IOException
return is.read();
参考:
OPPO - Android Q版本应用兼容性适配指导
作者:Small_Cake
链接:https://www.jianshu.com/p/cd9e58d1f8b9
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
android File和bitmap 相互转换 以及AsyncTask显示图片_龙之吻的博客-CSDN博客_android file转bitmap
以上是关于安卓10(Android10API29)保存图片到相册DCIM/Camera的主要内容,如果未能解决你的问题,请参考以下文章
安卓10(Android10API29)保存图片到相册DCIM/Camera
Android 10 (api 29) 中没有这样的文件或目录
将图片保存到共享图片文件夹 android target api 29