Android开发之保存图片到相册的三种方法详解
作者:xiayiye5 发布时间:2022-07-26 04:49:10
标签:Android,保存图片,相册
有三种方法如下:三个方法都需要动态申请读写权限否则保存图片到相册也会失败
方法一
/**
* 保存bitmap到本地
*
* @param bitmap Bitmap
*/
public static void saveBitmap(Bitmap bitmap, String path) {
String savePath;
File filePic;
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
savePath = path;
} else {
Log.e("tag", "saveBitmap failure : sdcard not mounted");
return;
}
try {
filePic = new File(savePath);
if (!filePic.exists()) {
filePic.getParentFile().mkdirs();
filePic.createNewFile();
}
FileOutputStream fos = new FileOutputStream(filePic);
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
fos.flush();
fos.close();
} catch (IOException e) {
Log.e("tag", "saveBitmap: " + e.getMessage());
return;
}
Log.i("tag", "saveBitmap success: " + filePic.getAbsolutePath());
}
方法二
针对小于API29以下方法,此方法会通知图库更新
/**
* API 29及以下保存图片到相册的方法
*
* @param toBitmap 要保存的图片
*/
private void saveImage(Bitmap toBitmap) {
String insertImage = MediaStore.Images.Media.insertImage(getContentResolver(), toBitmap, "壁纸", "搜索猫相关图片后保存的图片");
if (!TextUtils.isEmpty(insertImage)) {
Toast.makeText(this, "图片保存成功!" + insertImage, Toast.LENGTH_SHORT).show();
Log.e("打印保存路径", insertImage + "-");
}
}
方法三
针对大于API29以下方法,此方法也会通知图库更新
/**
* API29 中的最新保存图片到相册的方法
*/
private void saveImage29(Bitmap toBitmap) {
//开始一个新的进程执行保存图片的操作
Uri insertUri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, new ContentValues());
//使用use可以自动关闭流
try {
OutputStream outputStream = getContentResolver().openOutputStream(insertUri, "rw");
if (toBitmap.compress(Bitmap.CompressFormat.JPEG, 90, outputStream)) {
Log.e("保存成功", "success");
} else {
Log.e("保存失败", "fail");
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
上面方法二和方法三是java的写法,kotlin写法如下
package com.xiayiye.jetpackstudy.gallery
import android.Manifest
import android.content.ContentValues
import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.os.Build
import android.os.Bundle
import android.provider.MediaStore
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.core.content.ContextCompat
import androidx.core.graphics.drawable.toBitmap
import androidx.core.view.get
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager2.widget.ViewPager2
import com.xiayiye.jetpackstudy.R
import kotlinx.android.synthetic.main.fragment_view_pager2_image.*
import kotlinx.android.synthetic.main.pager_photo_view.view.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
/**
* 显示轮播大图和保存图片的页面
*/
class ViewPager2ImageFragment : Fragment() {
companion object {
const val REQUEST_WRITE_EXTERNAL_STORAGE_CODE = 1000
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_view_pager2_image, container, false)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
val photoList = arguments?.getParcelableArrayList<PhotoItem>("photo_list")
val currentPosition = arguments?.getInt("photo_position", 0)
PagerPhotoListAdapter().apply {
vp2Banner.adapter = this
submitList(photoList)
}
//设置轮播图片后的滑动当前页
vp2Banner.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
override fun onPageSelected(position: Int) {
super.onPageSelected(position)
tvShowImagePage.text =
StringBuffer().append(position + 1).append("/").append(photoList?.size)
}
})
//设置 ViewPager2 的当前页要在设置 ViewPager2 的数据后在设置当前页面,否则不生效
vp2Banner.setCurrentItem(currentPosition ?: 0, false)
//设置纵向滚动的方法
vp2Banner.orientation = ViewPager2.ORIENTATION_VERTICAL
//保存图片的方法
ivSaveImg.setOnClickListener {
if (Build.VERSION.SDK_INT < 29 && ContextCompat.checkSelfPermission(
requireContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE
) != PackageManager.PERMISSION_GRANTED
) {
requestPermissions(
arrayOf<String>(Manifest.permission.WRITE_EXTERNAL_STORAGE),
REQUEST_WRITE_EXTERNAL_STORAGE_CODE
)
} else {
viewLifecycleOwner.lifecycleScope.launch { saveImage29() }
}
}
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == REQUEST_WRITE_EXTERNAL_STORAGE_CODE && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
//权限申请成功可以保存图片
viewLifecycleOwner.lifecycleScope.launch { saveImage29() }
}
}
/**
* 保存图片到相册的方法
* API29 后此方法已废弃
*/
private fun saveImage() {
val holder =
(vp2Banner[0] as RecyclerView).findViewHolderForAdapterPosition(vp2Banner.currentItem) as PagerPhotoListAdapter.PagerPhotoViewHolder
val toBitmap = holder.itemView.ivPagerView.drawable.toBitmap()
val insertImage = MediaStore.Images.Media.insertImage(
requireActivity().contentResolver, toBitmap, "壁纸", "搜索猫相关图片后保存的图片"
)
if (insertImage.isNotEmpty()) {
Toast.makeText(requireActivity(), "图片保存成功!-${insertImage}", Toast.LENGTH_SHORT).show()
} else {
Toast.makeText(requireActivity(), "图片保存失败!}", Toast.LENGTH_SHORT).show()
}
}
/**
* API29 中的最新保存图片到相册的方法
*/
private suspend fun saveImage29() {
//开始一个新的进程执行保存图片的操作
withContext(Dispatchers.IO) {
val holder =
(vp2Banner[0] as RecyclerView).findViewHolderForAdapterPosition(vp2Banner.currentItem) as PagerPhotoListAdapter.PagerPhotoViewHolder
val toBitmap = holder.itemView.ivPagerView.drawable.toBitmap()
val insertUri = requireActivity().contentResolver.insert(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI, ContentValues()
) ?: kotlin.run {
showSaveToast("保存失败!")
return@withContext
}
//使用use可以自动关闭流
requireActivity().contentResolver.openOutputStream(insertUri).use {
if (toBitmap.compress(Bitmap.CompressFormat.JPEG, 90, it)) {
showSaveToast("保存成功!")
} else {
showSaveToast("保存失败!")
}
}
}
}
/**
* 显示保存图片结果的方法
*/
private fun showSaveToast(showMsg: String) =
MainScope().launch {
Toast.makeText(requireActivity(), showMsg, Toast.LENGTH_SHORT).show()
}
}
来源:https://blog.csdn.net/xiayiye5/article/details/115251706


猜你喜欢
- 前面文章讲述了Android手机与BLE终端之间的通信,而最常见的BLE终端应该是苹果公司倡导的iBeacon基站。iBeacon技术基于B
- 一、概述数据透视表(Pivot Table)是一种交互式的表,可以进行某些计算,如求和与计数等,可动态地改变透视表版面布置,也可以重新安排行
- 1.准备工作首先实现识别数字等字符,我们要知道需要采用OCR (Optical Character Recognition,光学字符识别)来
- /* * 获取当前的手机号 &nb
- 先给大家展示下效果图吧直接上代码:xml的布局:<Button android:id="@+id/btn_jp"
- Android开发之设置开机自动启动的几种方法方法一:<!-- 开机启动 --> <receiver android:na
- 本文介绍了springboot前后台数据交互的示例代码,分享给大家,具体如下:1.在路径中传递数据,比如对某个数据的id:123前台发送:格
- 本文实例为大家分享了Android自定义view利用PathEffect实现动态效果的具体代码,供大家参考,具体内容如下前言在上一篇此类型的
- //有何不足或者问题希望能够得到各位的多多指正,不胜感激import java.util.Scanner;/** *
- 冒泡排序冒泡排序是一种比较简单的排序算法,我们可以重复遍历要排序的序列,每次比较两个元素,如果他们顺序错误就交换位置,重复遍历到没有可以交换
- 一、配置xml路径mybatis-plus:mapper-locations: classpath:mapper/*.xml二、编写Mapp
- 多线程run方法中直接调用service业务类应注意Java多线程run方法里边使用service业务类会产生java.lang.NullP
- 从主线程发送消息到子线程(准确地说应该是非UI线程)package com.zhuozhuo;import android.app.Acti
- Java8中的lambda表达式、::符号和Optional类 0. 函数式编程 函
- Android透明状态栏只有在4.4之后有。在代码中加入下面几行代码即可实现来源:http://www.cnblogs.com/wangxi
- 概述在使用Spring Boot的时候我们经常使用actuator,健康检查,bus中使用/refresh等。这里记录如何使用注解的方式自定
- package com;import java.util.Arrays; public class sjf { &nbs
- 一、为何要使用netty开发由于之前已经用Java中的socket写过一版简单的聊天室,这里就不再对聊天室的具体架构进行细致的介绍了,主要关
- 本文实例讲述了Java获取凌晨时间戳的方法。分享给大家供大家参考,具体如下:这两天有一个需求是查询用户匹配的推荐信息,包含一个有效时间段,以
- 这篇文章主要介绍了springmvc视图解析流程代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的