移动端对大批量图片加载的优化方法(二)

移动端对大批量图片加载的优化方法(二)Android

本篇主要从Android开发中可以使用到的对大批量图片加载的优化方法进行整理。
优化

1.合适的图片格式

详情请参考移动端对大批量图片加载的优化方法(一)。

2.异步加载

图片加载可能会阻塞UI线程,导致界面的卡顿;

a.AsyncTask

Android中一个轻量级的异步类,允许在后台线程上执行一些操作然后在主线程上更新UI,从Android 11开始弃用。

public class ImageLoadTask extends AsyncTask<String, Void, Bitmap> {  private ImageView imageView;  public ImageLoadTask(ImageView imageView) {  this.imageView = imageView;  }  @Override  protected Bitmap doInBackground(String... urls) {  String urlString = urls[0];  Bitmap bitmap = null;  try {  URL url = new URL(urlString);  HttpURLConnection connection = (HttpURLConnection) url.openConnection();  connection.setDoInput(true);  connection.connect();  InputStream inputStream = connection.getInputStream();  bitmap = BitmapFactory.decodeStream(inputStream);  } catch (Exception e) {  e.printStackTrace();  }  return bitmap;  }  @Override  protected void onPostExecute(Bitmap result) {  if (result != null) {  imageView.setImageBitmap(result);  } else {  // 处理加载失败的情况,例如显示一个默认图片或加载指示器  }  }  
}
b.线程

使用线程来执行图片加载。

class ImageLoadingThread extends Thread {  private String imageUrl;  private ImageView imageView;  private Bitmap bitmap;  public ImageLoadingThread(String url, ImageView imageView) {  this.imageUrl = url;  this.imageView = imageView;  }  @Override  public void run() {  try {  URL url = new URL(imageUrl);  HttpURLConnection connection = (HttpURLConnection) url.openConnection();  connection.setDoInput(true);  connection.connect();  InputStream inputStream = connection.getInputStream();  bitmap = BitmapFactory.decodeStream(inputStream);  } catch (Exception e) {  e.printStackTrace();  } finally {  // 在主线程中更新UI  runOnUiThread(new Runnable() {  @Override  public void run() {  if (bitmap != null) {  imageView.setImageBitmap(bitmap);  } else {  // 处理加载失败的情况,例如显示一个默认图片或加载指示器  }  }  });  }  }  
}
c.Handler

Android提供的消息传递系统,可以在主线程和其他线程之间传递消息。

// 创建Handler实例  
private Handler handler = new Handler(Looper.getMainLooper()) {  @Override  public void handleMessage(Message msg) {  // 处理从子线程传回的数据,更新UI等操作  super.handleMessage(msg);  }  
};  // 创建并启动子线程来加载图片  
new Thread(new Runnable() {  @Override  public void run() {  Bitmap bitmap = loadImageFromNetwork("http://example.com/image.jpg");  // 将Bitmap对象发送到主线程更新UI  Message message = handler.obtainMessage();  message.obj = bitmap; // 将Bitmap对象附加到Message对象上传递给Handler  handler.sendMessage(message);  }  
}).start();
d.Coroutines

从Android Jetpack Compose 1.0开始后可以使用Coroutines来执行异步操作,也是一种轻量级的线程模型。

val scope = viewModelScope // 如果你使用 ViewModel  
// 或 val scope = lifecycleScope[LifecycleOwner].coroutineScope // 如果你使用 LifecycleOwner
fun loadImageFromNetwork(): Flow<Bitmap> {  return flow {  try {  val url = URL("http://example.com/image.jpg") // 替换为你的图片URL  val connection = url.openConnection() as HttpURLConnection  connection.requestMethod = "GET"  val inputStream = connection.inputStream  val imageBytes = ByteArray(1024)  var readCount: Int = 0  while (inputStream.read(imageBytes, 0, 1024) != -1) {  readCount += 1024  imageBytes.resize(readCount)  }  val bitmap = BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.size)  emit(bitmap) // 发射图片数据到 Flow 中  } catch (e: IOException) {  e.printStackTrace()  throw e  }  }.flowOn(Dispatchers.IO) // 在 IO 线程上执行网络请求和图片解码操作  
}
e.第三方库

利用第三方图片加载库,例如Glide,它提供了异步加载和缓存机制。

Glide.initialize(this) // 在Activity或Application中初始化Glide
Glide.with(context) // 获取Glide的实例  .load("http://example.com/image.jpg") // 指定图片URL  .into(imageView) // 将加载的图片设置到ImageView中

3.懒加载

只有当图片即将被显示时才加载,可以显著提高应用的性能减少不必要的网络和磁盘I/O操作;

a.第三方库

Glide和Picasso,提供了内置的懒加载支持。

Glide.with(context)  .load("http://example.com/image.jpg")  .defer() // 延迟加载图片,直到它进入屏幕可视区域  .into(imageView)
Picasso.get().context = this // 在Activity或Application中初始化Picasso
Picasso.get().load("http://example.com/image.jpg").fit().into(imageView) // 加载并懒加载图片到ImageView中
b.自定义View

在View的onDraw方法中,你可以检查图片是否已经加载,如果没有,则开始加载图片。

public class LazyImageView extends View {  private Bitmap mBitmap;  private boolean isLoaded = false;  public LazyImageView(Context context) {  super(context);  }  public void setBitmap(Bitmap bitmap) {  mBitmap = bitmap;  invalidate(); // 重新绘制View  }  @Override  protected void onDraw(Canvas canvas) {  super.onDraw(canvas);  if (isLoaded) {  canvas.drawBitmap(mBitmap, 0, 0, null); // 在View上绘制图片  } else {  // 可以设置一个占位符图片或空图片  // canvas.drawBitmap(placeholderBitmap, 0, 0, null);  }  }  public void loadImage(String url) {  // 在这里实现图片的懒加载逻辑,例如使用Glide加载图片  // 当图片加载完成后,调用setBitmap方法设置图片并调用invalidate方法重新绘制View  }  
}
c.ListView或RecyclerView

如果使用ListView或RecyclerView显示图片列表,可以利用组件的滚动监听机制来懒加载图片。

d.缓存机制

当图片首次加载完成后,你可以将其缓存到本地存储中;
下次需要显示该图片时,可以从缓存中直接读取,而不是重新从网络上下载。

Glide.with(this) // 获取Glide实例  .load("http://example.com/image.jpg") // 指定图片URL  .into(new CustomTarget<Bitmap>() { // 自定义目标  @Override  public void onResourceReady(@NonNull Bitmap resource, @Nullable Transition<? super Bitmap> transition) {  // 图片加载完成,将其缓存到本地存储中  saveBitmapToCache(resource);  }  @Override  public void onLoadCleared(@Nullable Drawable placeholder) {  // 当View被清除时调用,可以释放资源  }  });
private void saveBitmapToCache(Bitmap bitmap) {  // 获取缓存目录的路径  File cacheDir = getExternalFilesDir(null);  // 构建保存文件的路径  File cacheFile = new File(cacheDir, "cached_image.jpg");  try (FileOutputStream out = new FileOutputStream(cacheFile)) {  bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out); // 压缩图片并写入文件  } catch (IOException e) {  e.printStackTrace();  }  
}
Glide.with(this)  .load(cacheFile) // 指定缓存文件的路径  .into(imageView); // 将图片设置到ImageView中

4.适当的Bitmap配置

在加载图片时,可以指定Bitmap的配置,例如inPreferredConfig、inJustDecodeBounds等,以优化内存使用;

a.使用合适的Bitmap位深度

如果你知道图片的像素格式,确保使用适当的位深度;
例如,对于ARGB_8888格式的图片,使用BitmapFactory.Options的inPreferredConfig属性设置为Bitmap.Config.ARGB_8888。

b.设置Bitmap的宽度和高度

在BitmapFactory.Options中设置inJustDecodeBounds为true,以仅获取图片的原始尺寸;
然后可以根据这些尺寸动态地调整图片大小。

c.避免OOM(OutOfMemoryError)

确保应用不会因内存不足而崩溃,如果图片太大而无法适应内存,考虑将其缩小或分割成更小的部分;
使用BitmapFactory.Options的inSampleSize属性来缩放图片,这可以通过指定一个大于1的数值来实现。

d.定期清理不必要的Bitmap

当不再需要某个Bitmap时,调用其recycle()方法来释放内存。

e.考虑使用Vector Drawables或Xfermodes

对于支持的设备,考虑使用Vector Drawables代替PNG或JPEG图片,因为它们占用更少的空间并支持任意缩放;
对于复杂的图形效果,使用Xfermodes来创建自定义绘图效果。

5.适当的图片大小

根据需要显示的大小来加载图片,而不是直接加载原始大小的图片。

public Bitmap loadBitmapFromFile(String filePath, int width, int height) {  // 创建BitmapFactory.Options对象  BitmapFactory.Options options = new BitmapFactory.Options();  // 设置inJustDecodeBounds属性为true,仅获取图片的原始尺寸  options.inJustDecodeBounds = true;  BitmapFactory.decodeFile(filePath, options);  // 计算合适的inSampleSize,用于缩小图片尺寸  options.inSampleSize = calculateInSampleSize(options, width, height);  // 重新加载图片,使用计算出的inSampleSize缩小图片尺寸  return BitmapFactory.decodeFile(filePath, options);  
}  private int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {  // 源图片的高度和宽度  final int height = options.outHeight;  final int width = options.outWidth;  int inSampleSize = 1;  if (height > reqHeight || width > reqWidth) {  final int halfHeight = height / 2;  final int halfWidth = width / 2;  // 计算最大的inSampleSize值,该值是2的幂且能缩小图片高度和宽度到所需的尺寸  while ((halfHeight / inSampleSize) >= reqHeight && (halfWidth / inSampleSize) >= reqWidth) {  inSampleSize *= 2;  }  }  return inSampleSize;  
}

5.预加载

用户需要某个资源之前,提前加载该资源到内存中,这样可以减少用户在需要时等待的时间,提高响应速度。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/607849.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

模板管理支持批量操作,DataEase开源数据可视化分析平台v2.2.0发布

2024年1月8日&#xff0c;DataEase开源数据可视化分析平台正式发布v2.2.0版本。 这一版本的功能升级包括&#xff1a;在“模板管理”页面中&#xff0c;用户可以通过模板管理的批量操作功能&#xff0c;对已有模板进行快速重新分类、删除等维护操作&#xff1b;数据大屏中&…

深圳易图讯科技VR三维电子沙盘系统

易图讯VR三维电子沙盘系统是一种结合虚拟现实技术的地理信息系统。它通过高精度三维模型&#xff0c;真实再现了地理环境、建筑布局和地形地貌。用户可通过VR设备沉浸式体验这一虚拟世界&#xff0c;进行各种交互操作&#xff0c;如缩放、旋转、移动等。系统还支持实时数据更新…

门店管理系统驱动智慧零售升级

在当今数字化经济的大潮中&#xff0c;实体门店正在经历一场由内而外的深度变革。门店管理系统以其高效、便捷和全面的功能特性&#xff0c;为实体店提供了高效的运营解决方案。 门店管理系统拜托了传统零售业对本地化软件的依赖&#xff0c;它将复杂的信息技术转化为易于获取…

2024十大开放式耳机品牌有哪些?公认好用的开放式耳机测评推荐

随着生活水平的提升&#xff0c;人们对音频设备的需求已经不再只是简单的声音输出&#xff0c;而是追求更高质量的听觉体验&#xff0c;而近几年出现的开放式耳机正是为了满足这一需求而诞生的&#xff0c;凭借着不入耳的设计带来了极致的佩戴体验&#xff0c;这种耳机也成为了…

如何克隆驱动器,不同的操作系统有不同的推荐软件

你需要将Windows或macOS安装迁移到新驱动器吗?你可以使用服务备份文件,也可以创建数据的完整一对一副本。通过克隆你的驱动器,你可以创建一个精确的副本。 一些业务级别的备份服务,如IDrive和Acronis,具有内置的磁盘克隆功能,是对正常文件备份的补充。但对于一次性克隆(…

SpringBoot+策略模式实现多种文件存储模式

一、策略模式 背景 针对某种业务可能存在多种实现方式&#xff1b;传统方式是通过传统if…else…或者switch代码判断&#xff1b; 弊端&#xff1a; 代码可读性差扩展性差难以维护 策略模式简介 策略模式是一种行为型模式&#xff0c;它将对象和行为分开&#xff0c;将行…

实现导航栏吸顶操作

一、使用VueUse插件 // 安装 npm i vueuse/core二、点击搜索useScroll 2.1搜索结果如图 三、使用 // 这是示例代码 import { useScroll } from vueuse/core const el ref<HTMLElement | null>(null) const { x, y, isScrolling, arrivedState, directions } useSc…

结构型设计模式——适配器模式

适配器模式 这个更加好理解&#xff0c;就是做适配功能的类&#xff0c;例如&#xff0c;现在手机没有了圆形耳机接口&#xff0c;只有Type-C接口&#xff0c;因此你如果还想要使用圆形耳机的话需要买个圆形接口转Type-C的转换器&#xff08;适配器&#xff09;&#xff0c;这…

【Java 设计模式】设计原则

文章目录 ✨单一职责原则&#xff08;SRP&#xff09;✨开放/封闭原则&#xff08;OCP&#xff09;✨里氏替换原则&#xff08;LSP&#xff09;✨依赖倒置原则&#xff08;DIP&#xff09;✨接口隔离原则&#xff08;ISP&#xff09;✨合成/聚合复用原则&#xff08;CARP&#…

深入理解云原生技术:构建现代化可靠的应用

引言 云原生技术作为软件开发和部署的新范式&#xff0c;以其高度可伸缩性、灵活性和可靠性&#xff0c;吸引了广泛的关注。本文将深入探讨云原生技术的核心概念、优势以及其在现代软件开发中的应用。 1. 什么是云原生技术&#xff1f; 云原生技术是一种以云计算为基础&#…

美国NDC药品码注册详细介绍(OTC药品FDA注册)

美国药品验证号&#xff08;NDC&#xff09;注册介绍 希望我发布的文章能帮助到刷到的有缘人 国家药品验证号&#xff08;NDC&#xff09;是中国中药及OTC非处方药通过FDA认证的快捷申请形式。主要针对美国国家药典已有的药&#xff0c;无需做新药论证&#xff0c;只需提供必…

揭秘阿里自研搜索引擎 Havenask 在线检索服务

作者&#xff1a;谷深 Havenask 是阿里巴巴智能引擎事业部自研的开源高性能搜索引擎&#xff0c;深度支持了包括淘宝、天猫、菜鸟、高德、饿了么在内几乎整个阿里的搜索业务。本文针对性介绍了 Havenask 的在线服务&#xff0c;它具备高可用、高时效、低成本的优势&#xff0c;…

前端angular 实现验证码 输入+展示(大框+加粗内容 )

参考用原生方在手机上此效果 如何实现一个4位验证码输入框效果 输入使用的任旧是html的input元素&#xff0c;只是让它看不到了只是把输入到input元素里的内容取到的内容放在改过样式的div里不需要dom操作&#xff0c;直接用双向绑定就拿到数据&#xff1b;使用动态样式 设置了…

sublime代码对齐设置

sublime代码对齐设置 sublime代码对齐设置待续、更新中 sublime代码对齐设置 Preferences->Key Bindings->user->编辑⽂档输⼊: { "keys": ["ctrlaltl"], "command": "reindent" }然后选中你要对齐的代码块或者ctrla全选代…

从0开始python学习-46.pytest框架之通过yaml处理接口关联问题-针对变量处理

目录 1. 提取变量 1.1 提取方法 1.2 提取地方&#xff1a;响应的body&#xff0c;响应的cookie&#xff0c;响应头 1.3 提取方式&#xff1a; 1.4 示例&#xff1a;在能获取到对应token的yaml用例中写入 2.使用变量&#xff1a;封装一个通用extract_util.py 3. 调用测试用…

卸载流氓软件联软

这个流氓软件也是在更新的&#xff0c;下面是本人在联想邵阳笔记本下卸载流程&#xff0c;非常简单 注&#xff1a;按照本文卸载之后&#xff0c;我重新装了一次这个垃圾&#xff0c;但是发现重装完之后&#xff0c;系统启动之后就会进入黑屏&#xff0c;也就是说&#xff0c;…

【数据库基础】Mysql与Redis的区别

看到一篇不错的关于“Mysql与Redis的区别”的文章&#xff0c;转过来记录下~ 文章目录 一、数据库类型二、运行机制三、什么是缓存数据库呢&#xff1f;四、优缺点比较五、区别总结六、数据可以全部直接用Redis储存吗&#xff1f;参考资料 一、数据库类型 Redis&#xff1a;NOS…

Win10安装配置Redis,修改密码

一、下载Redis tporadowski 提供了 支持 Windows平台的 Redis 安装包&#xff0c;目前仍在维护&#xff0c;目前最新版本是 5.0.14&#xff0c;更新速度跟Redis官网也相差好几个大版本。 下载地址&#xff1a;https://github.com/tporadowski/redis/releases 二、Redis 安装 …

哈希-力扣202快乐数

题目 编写一个算法来判断一个数 n 是不是快乐数。 「快乐数」 定义为&#xff1a; 对于一个正整数&#xff0c;每一次将该数替换为它每个位置上的数字的平方和。然后重复这个过程直到这个数变为 1&#xff0c;也可能是 无限循环 但始终变不到 1。如果这个过程 结果为 1&…