您好,我看到您的博客,android11保存相册和视频到相册,觉得很好,很厉害,但是还有一个问题就是,android 11及以上保存gif到相册,以及如何保存音频到本地啊,我看您的博客文章只有保存视频和图片。麻烦您了
在 Android 11 及以上版本,为了加强隐私保护,对应用访问外部存储进行了限制。可以通过 MediaStore API 来保存图片、视频和音频文件到相册或本地。
保存 GIF 到相册:
val resolver: ContentResolver = context.contentResolver
val imageCollection = MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
val imageDetails = ContentValues().apply {
put(MediaStore.Images.Media.DISPLAY_NAME, "my_gif.gif")
put(MediaStore.Images.Media.MIME_TYPE, "image/gif")
put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_DCIM)
}
val imageUri = resolver.insert(imageCollection, imageDetails)
val outputStream = resolver.openOutputStream(imageUri!!)
outputStream?.let {
// 将 gif 字节数组写入 outputStream
it.write(gifBytes)
it.close()
}
保存音频到本地:
val resolver: ContentResolver = context.contentResolver
val audioCollection = MediaStore.Audio.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
val audioDetails = ContentValues().apply {
put(MediaStore.Audio.Media.DISPLAY_NAME, "my_audio.mp3")
put(MediaStore.Audio.Media.MIME_TYPE, "audio/mpeg")
put(MediaStore.Audio.Media.RELATIVE_PATH, Environment.DIRECTORY_MUSIC)
}
val audioUri = resolver.insert(audioCollection, audioDetails)
val outputStream = resolver.openOutputStream(audioUri!!)
outputStream?.let {
// 将音频字节数组写入 outputStream
it.write(audioBytes)
it.close()
}
需要注意的是,保存文件到相册或本地时,需要在 AndroidManifest.xml 文件中添加对应的权限声明,例如:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
另外,Android 10 及以上版本还需要在代码中动态请求权限,才能访问外部存储。
保存GIF文件到相册
// 假设你已经有一个GIF文件的路径 gifFilePath
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.DISPLAY_NAME, "my_gif.gif");
values.put(MediaStore.Images.Media.MIME_TYPE, "image/gif");
values.put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_PICTURES);
Uri imageUri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
OutputStream outputStream;
try {
outputStream = getContentResolver().openOutputStream(imageUri);
InputStream inputStream = new FileInputStream(gifFilePath);
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
inputStream.close();
outputStream.close();
// 刷新相册
MediaScannerConnection.scanFile(this, new String[]{imageUri.getPath()}, null, null);
} catch (IOException e) {
e.printStackTrace();
}
保存音频文件到本地
// 假设你已经有一个音频文件的路径 audioFilePath
ContentValues values = new ContentValues();
values.put(MediaStore.Audio.Media.DISPLAY_NAME, "my_audio.mp3");
values.put(MediaStore.Audio.Media.MIME_TYPE, "audio/mpeg");
values.put(MediaStore.Audio.Media.RELATIVE_PATH, Environment.DIRECTORY_MUSIC);
Uri audioUri = getContentResolver().insert(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, values);
OutputStream outputStream;
try {
outputStream = getContentResolver().openOutputStream(audioUri);
InputStream inputStream = new FileInputStream(audioFilePath);
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
inputStream.close();
outputStream.close();
// 刷新媒体库
MediaScannerConnection.scanFile(this, new String[]{audioUri.getPath()}, null, null);
} catch (IOException e) {
e.printStackTrace();
}
我可以为您提供如下解决方案:
在Android 11及以上系统中,应用需要请求存储权限才能访问公共存储空间,可以使用MediaStore API将gif保存到相册。
示例代码:
private void saveGifToGallery(Context context, String filePath) {
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.DISPLAY_NAME, "gif_image");
values.put(MediaStore.Images.Media.DESCRIPTION, "Gif image saved from app");
values.put(MediaStore.Images.Media.MIME_TYPE, "image/gif");
values.put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_PICTURES);
Uri external = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
ContentResolver resolver = context.getContentResolver();
Uri insertUri = resolver.insert(external, values);
if (insertUri != null) {
try {
OutputStream outputStream = resolver.openOutputStream(insertUri);
InputStream inputStream = new FileInputStream(new File(filePath));
byte[] buffer = new byte[1024];
int read;
while ((read = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, read);
}
inputStream.close();
outputStream.flush();
outputStream.close();
Toast.makeText(context, "Gif saved to gallery", Toast.LENGTH_SHORT).show();
} catch (IOException e) {
e.printStackTrace();
}
}
}
将音频保存到本地需要先请求存储权限,然后将音频数据写入到文件中。
示例代码:
private void saveAudioToLocalStorage(Context context, byte[] audioData) {
if (ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
PERMISSION_REQUEST_CODE);
return;
}
String fileName = "audio_record_" + System.currentTimeMillis();
File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC), fileName);
try {
FileOutputStream outputStream = new FileOutputStream(file);
outputStream.write(audioData);
outputStream.flush();
outputStream.close();
Toast.makeText(context, "Audio saved to local storage", Toast.LENGTH_SHORT).show();
} catch (IOException e) {
e.printStackTrace();
}
}
android 在本地建立文件夹,并将图片和音频保存在文件夹下,
件路劲是我们之前创建文件的时候保存的,通过newFileName(),我们会得到我们所需要保存文件的文件路径和文件名,然后我们将文件名返回,通过方法setoutfile将文件输出即可,当然这可能会比较伤硬盘的,因为这是一个字节一个字节的读取,我们通过缓冲读取的效果会更好一些,这样我们的文件就被保存下来了。
public void playRecord() {
mediaRecorder = new MediaRecorder();
// 第1步:设置音频来源(MIC表示麦克风)
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
// 第2步:设置音频输出格式(默认的输出格式)
mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
// 第3步:设置音频编码方式(默认的编码方式)
mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
// 第4步:指定音频输出文件
mediaRecorder.setOutputFile(newFileName());
// 第5步:调用prepare方法
try {
mediaRecorder.prepare();
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 第6步:调用start方法开始录音
mediaRecorder.start();
}
public String newFileName() {
SharedPreferences filePath = getSharedPreferences("filepath", MODE_PRIVATE);
mFileName = filePath.getString("path", null);
String s = new SimpleDateFormat("yyyy-MM-dd hhmmss").format(new Date());
return mFileName += "/music/" + s + ".3gp";
}
图片都可以报错,gif也可以的啊,gif也是类似于图片的一种,动态图片而已。网络图片或gif,可以使用像OkHttp这样的工具进行下载。同样的,音频和视频也是一样的啊,只是文件后缀不同而已。要注意请求读写权限。具体的程序代码,你可以参考:
https://www.jianshu.com/p/e3e8fb749e9f
需要在AndroidManifest.xml 文件中添加读写外部存储的权限,然后在进行保存
引用chatgpt内容作答:
在 Android 11 及以上的设备上,保存 GIF 到相册需要使用 Android 10 引入的新的存储访问框架。同时,保存音频文件到本地可以使用标准的文件操作方法。下面是一个示例代码,演示如何保存 GIF 到相册以及如何保存音频到本地。
首先,确保在 AndroidManifest.xml 文件中添加以下权限:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
接下来,你可以使用以下代码保存 GIF 到相册:
import android.content.ContentValues;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.media.MediaScannerConnection;
import android.os.Environment;
import android.provider.MediaStore;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
public class GifUtils {
public static void saveGifToGallery(Context context, Bitmap gifBitmap, String gifFileName) {
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.DISPLAY_NAME, gifFileName);
values.put(MediaStore.Images.Media.MIME_TYPE, "image/gif");
values.put(MediaStore.Images.Media.WIDTH, gifBitmap.getWidth());
values.put(MediaStore.Images.Media.HEIGHT, gifBitmap.getHeight());
// 在 Android 10 及以上版本,使用 MediaStore API 保存到公共集合
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) {
values.put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_PICTURES);
values.put(MediaStore.Images.Media.IS_PENDING, 1);
// 保存到 MediaStore
final android.content.ContentResolver resolver = context.getContentResolver();
final android.net.Uri collection = MediaStore.Images.Media
.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY);
final android.net.Uri item = resolver.insert(collection, values);
try {
// 将 GIF 图片保存到 URI
if (item != null) {
OutputStream out = resolver.openOutputStream(item);
gifBitmap.compress(Bitmap.CompressFormat.WEBP, 100, out);
out.flush();
out.close();
// 完成保存后,将 IS_PENDING 设置为 0
values.clear();
values.put(MediaStore.Images.Media.IS_PENDING, 0);
resolver.update(item, values, null, null);
}
} catch (Exception e) {
e.printStackTrace();
}
// 通知媒体库刷新
MediaScannerConnection.scanFile(context, new String[]{item.toString()}, null, null);
} else {
// 在 Android 9 及以下版本,将 GIF 图片保存到指定文件夹
File gifDirectory = new File(Environment.getExternalStorageDirectory().toString() + "/GIFs");
if (!gifDirectory.exists()) {
gifDirectory.mkdirs();
}
File gifFile = new File(gifDirectory, gifFileName + ".gif");
try {
OutputStream out = new FileOutputStream(gifFile);
gifBitmap.compress(Bitmap.CompressFormat.WEBP, 100, out);
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
// 通知媒体库刷新
MediaScannerConnection.scanFile(context, new String[]{gifFile.getAbsolutePath()}, null, null);
}
}
public static Bitmap createDummyGifBitmap(int width, int height) {
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
canvas.drawColor(Color.RED);
return bitmap;
}
}
上面的代码中,saveGifToGallery() 方法用于保存 GIF 到相册。如果设备的 Android 版本是 10 及以上,它使用 MediaStore API 将 GIF 保存到公共集合中,并设置 IS_PENDING 标志来表示此文件为待定状态。保存完成后,将 IS_PENDING 设置为 0,这样媒体库就可以正确识别文件。
如果设备的 Android 版本是 9 及以下,代码会将 GIF 图片保存到指定文件夹中,并使用 MediaScannerConnection 来通知媒体库刷新。
以下是保存音频文件到本地的示例代码:
import android.content.Context;
import android.media.MediaScannerConnection;
import android.os.Environment;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class AudioUtils {
public static void saveAudioToLocalStorage(Context context, byte[] audioData, String audioFileName) {
File audioDirectory = new File(Environment.getExternalStorageDirectory().toString() + "/Audio");
if (!audioDirectory.exists()) {
audioDirectory.mkdirs();
}
File audioFile = new File(audioDirectory, audioFileName + ".mp3");
try {
OutputStream out = new FileOutputStream(audioFile);
out.write(audioData);
out.flush();
out.close();
// 通知媒体库刷新
MediaScannerConnection.scanFile(context, new String[]{audioFile.getAbsolutePath()}, null, null);
} catch (IOException e) {
e.printStackTrace();
}
}
}
上述代码中的 saveAudioToLocalStorage() 方法用于将音频数据保存为本地文件。它将音频数据写入到指定的文件夹中,并使用 MediaScannerConnection 来通知媒体库刷新,以便在其他应用程序中能够访问到该音频文件。
在使用上述代码保存文件之前,确保已经获取了适当的权限,如写入外部存储的权限(WRITE_EXTERNAL_STORAGE)以及在 AndroidManifest.xml 文件中声明这些权限。此外,还需要注意 Android 10 及以上版本与 Android 9 及以下版本之间的存储访问差异,以选择适当的保存方式。
采用chatgpt:
要在Android 11及更高版本中保存GIF到相册,您可以使用以下代码:
ContentResolver resolver = getContentResolver();
ContentValues contentValues = new ContentValues();
contentValues.put(MediaStore.Images.Media.DISPLAY_NAME, "gifFileName.gif");
contentValues.put(MediaStore.Images.Media.MIME_TYPE, "image/gif");
contentValues.put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_PICTURES + File.separator + "GIFs");
Uri uri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues);
try {
OutputStream outputStream = resolver.openOutputStream(uri);
// 将 GIF 数据写入 outputStream
} catch (IOException e) {
e.printStackTrace();
}
这将在Pictures/GIFs目录下创建一个名为"gifFileName.gif"的GIF文件,并将其添加到媒体库中。
要将音频保存到本地,您可以使用以下代码:
String fileName = "audioFileName.mp3";
File file = new File(getExternalFilesDir(null), fileName);
try {
FileOutputStream fos = new FileOutputStream(file);
// 将音频数据写入 fos
} catch (FileNotFoundException e) {
e.printStackTrace();
}
这将在应用程序的外部存储路径中创建一个名为"audioFileName.mp3"的文件,并将音频数据写入该文件中。请注意,您需要在AndroidManifest.xml中声明WRITE_EXTERNAL_STORAGE权限才能访问外部存储器。
对于 Android 11 及更高版本,保存 GIF 到相册以及保存音频到本地的方法与保存图片和视频类似。下面是一个简单的示例代码:
// 在 AndroidManifest.xml 文件中添加 WRITE_EXTERNAL_STORAGE 权限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
// 保存 GIF 到相册
String gifFilePath = "path_to_gif_file.gif";
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.DISPLAY_NAME, "my_gif");
values.put(MediaStore.Images.Media.MIME_TYPE, "image/gif");
values.put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_PICTURES);
Uri gifUri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
try {
OutputStream outputStream = getContentResolver().openOutputStream(gifUri);
FileInputStream fileInputStream = new FileInputStream(gifFilePath);
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = fileInputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
fileInputStream.close();
outputStream.close();
Toast.makeText(this, "GIF saved to gallery", Toast.LENGTH_SHORT).show();
} catch (IOException e) {
e.printStackTrace();
}
// 在 AndroidManifest.xml 文件中添加 WRITE_EXTERNAL_STORAGE 权限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
// 保存音频到本地
String audioFilePath = "path_to_audio_file.mp3";
ContentValues values = new ContentValues();
values.put(MediaStore.Audio.Media.DISPLAY_NAME, "my_audio");
values.put(MediaStore.Audio.Media.MIME_TYPE, "audio/mpeg");
values.put(MediaStore.Audio.Media.RELATIVE_PATH, Environment.DIRECTORY_MUSIC);
Uri audioUri = getContentResolver().insert(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, values);
try {
OutputStream outputStream = getContentResolver().openOutputStream(audioUri);
FileInputStream fileInputStream = new FileInputStream(audioFilePath);
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = fileInputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
fileInputStream.close();
outputStream.close();
Toast.makeText(this, "Audio saved to local storage", Toast.LENGTH_SHORT).show();
} catch (IOException e) {
e.printStackTrace();
}
以上示例代码中,我们使用 ContentValues
来设置保存文件的相关信息,如显示名称、MIME 类型和相对路径。然后,通过调用 getContentResolver().insert()
将文件插入到媒体库中,并获取对应的 URI。最后,使用输入流和输出流来复制文件内容并保存到指定位置。
请注意,在 Android 10 及更高版本中,需要在 AndroidManifest.xml
文件中添加适当的存储权限。此外,为了确保正确的文件保存和访问,请根据实际需求进行适当的错误处理和权限请求。
看到这么多人工智能的回答,我想说的是,如果不了解本质,再多的解答对题主来说都是枉然。
题目中描述的是保存一些文件到相册,其实我们只要知道相册的路径,不管什么文件都能保存到相册,只是相册不支持的格式可能无法打开,仅此而已。
安卓相册目录,在内部存储的DCIM中,只要申请到权限,什么文件都可以保存。
其绝对路径可以用以下方式得到
Environment.getExternalStorageDirectory() + "/DCIM"
这种路径下还可以新建自定义的文件夹,保存的文件打开相册之后会自动扫描并预览
安卓12一下添加并动态申请
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
安卓12及以上添加并跳转到设置
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
tools:ignore="ScopedStorage" />
至于如何动态申请或者跳转,相信网上一大把现成的代码,写的又漂亮又简介。
谁的博客