【Android 内存优化】Bitmap 长图加载 ( BitmapRegionDecoder 简介 | BitmapRegionDecoder 使用流程 | 区域解码加载示例 )

简介: 【Android 内存优化】Bitmap 长图加载 ( BitmapRegionDecoder 简介 | BitmapRegionDecoder 使用流程 | 区域解码加载示例 )

文章目录

一、BitmapRegionDecoder 简介

二、图片信息

三、BitmapRegionDecoder 对象创建

四、解码图像

五、图像区域解码示例

六、源码及资源下载







一、BitmapRegionDecoder 简介


官方文档 API : BitmapRegionDecoder




BitmapRegionDecoder 简介 :



① 主要作用 : BitmapRegionDecoder 可以从图像中 解码一个矩形区域 ;


② 适用场景 : 当一张图片非常大 , 在手机中只需要显示其中一部分内容 , BitmapRegionDecoder 非常有用 ;


③ 基本使用流程 : 先创建 , 后解码 ;


流程 1 : 创建 BitmapRegionDecoder : 调用 newInstance 方法 , 创建 BitmapRegionDecoder 对象 ;

// 创建 BitmapRegionDecoder 对象方法
static BitmapRegionDecoder newInstance(InputStream is, boolean isShareable)
static BitmapRegionDecoder newInstance(FileDescriptor fd, boolean isShareable)
static BitmapRegionDecoder newInstance(String pathName, boolean isShareable)
static BitmapRegionDecoder newInstance(byte[] data, int offset, int length, boolean isShareable)


流程 2 : 解码图像区域内容 : 调用 decodeRegion 方法 , 获取指定 Rect 矩形区域的解码后的 Bitmap 对象 ;

Bitmap decodeRegion(Rect rect, BitmapFactory.Options options)






二、图片信息


将一张图片存放在 assets 目录下 , 图片尺寸为 938 x 7561 , 这是 BitmapRegionDecoder 的文档截图 ;


该图片如果按照默认的 ARGB_8888 格式加载到内存中 , 会占用 28,368,872 字节的内存 , 大约 27 MB ;



内存大小计算过程如下 :


938 × 7561 × 4 = 28 , 368 , 872 938 \times 7561 \times 4 = 28,368,872

938×7561×4=28,368,872


image.png






三、BitmapRegionDecoder 对象创建


1 . BitmapRegionDecoder 对象创建 : 调用 newInstance 方法创建该对象 ;



① 函数作用 : 根据输入流创建 BitmapRegionDecoder 对象 ;


② 输入流的数据位置 : 输入流的当前读取位置就是在之前读取的的解码数据的后面一个字节位置 ;


③ 支持的图像格式 : 目前图像区域解码对象只支持 JPEG 和 PNG 两种图像格式 ;




2 . 函数原型 :



InputStream is 参数 : 图片的输入流 ;


boolean isShareable 参数 : 是否共享输入流 ; 如果设置了共享为 true , 如果将该输入流关闭 , 假如 BitmapRegionDecoder 对象中也在使用该输入流 , 那么关闭以后 , BitmapRegionDecoder 对象也无法使用该输入流了 ; 如果设置该参数为 false , 那么关闭该输入流 , 不影响 BitmapRegionDecoder 对象使用 , 一般都是该区域解码对象需要长时间使用 , 此处都要设置成 false ;


 

public static BitmapRegionDecoder newInstance(InputStream is,
            boolean isShareable) throws IOException {
        // 当前的输入流是 AssetInputStream 输入流的情况
        if (is instanceof AssetManager.AssetInputStream) {
            return nativeNewInstance(
                    ((AssetManager.AssetInputStream) is).getNativeAsset(),
                    isShareable);
        } else {
          // 当前的输入流是文件输入流
          // 传入临时缓存到 Native 代码中 ; 
          // 创建一个足够大的临时缓存区 , 这样可以减少 is.read 方法的回调次数 ; 
          // 应该避免 is.read 回调次数太多 , 同时每次读取很少数据的情况 ; 
            byte [] tempStorage = new byte[16 * 1024];
            return nativeNewInstance(is, tempStorage, isShareable);
        }
    }





四、解码图像


函数原型 : 解码 JPEG 或 PNG 中指定的矩形区域 ;


Rect rect 参数 : 要解码的矩形区域 ;

BitmapFactory.Options options 参数 : 解码选项 ;

public Bitmap decodeRegion(Rect rect, BitmapFactory.Options options)

1





五、图像区域解码示例


1 . 主界面代码 : 先创建 BitmapRegionDecoder 对象 , 然后调用该对象的 decodeRegion 方法 , 进行图像剪切 ;


package kim.hsl.lgl;
import android.graphics.Bitmap;
import android.graphics.BitmapRegionDecoder;
import android.graphics.Rect;
import android.os.Bundle;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import java.io.IOException;
import java.io.InputStream;
public class MainActivity extends AppCompatActivity {
    static {
        System.loadLibrary("native-lib");
    }
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        TextView tv = findViewById(R.id.sample_text);
        tv.setText(stringFromJNI());
        // 显示剪切后的正方形图像
        showImage();
    }
    private void showImage(){
        InputStream inputStream = null;
        try {
            // 获取 Assets 文件的输入流
            inputStream = getAssets().open("bitmap_region_decoder.png");
            /*
                函数原型 :
                public static BitmapRegionDecoder newInstance(InputStream is,
                    boolean isShareable) throws IOException {
                InputStream is 参数 : 图片的输入流
                boolean isShareable 参数 : 是否共享输入流
                如果设置了共享为 true , 如果将该输入流关闭 ,
                假如 BitmapRegionDecoder 对象中也在使用该输入流 ,
                那么关闭以后 , BitmapRegionDecoder 对象也无法使用该输入流了 ;
                如果设置该参数为 false , 那么关闭该输入流 , 不影响 BitmapRegionDecoder 对象使用 ,
                一般都是该区域解码对象需要长时间使用 , 此处都要设置成 false ;
             */
            BitmapRegionDecoder bitmapRegionDecoder = BitmapRegionDecoder
                    .newInstance(inputStream, false);
            /*
                解码图片
                这里解析前面的一部分图片
             */
            Bitmap bitmap = bitmapRegionDecoder.decodeRegion(
                    new Rect(0, 0, 938, 938),   //解码区域
                    null);  //解码选项 BitmapFactory.Options 类型
            ImageView imageView = findViewById(R.id.imageView);
            imageView.setImageBitmap(bitmap);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(inputStream != null){
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    public native String stringFromJNI();
}




2 . 布局文件 : 在布局中放置一个正方形的 ImageView , 显示剪切后的 938 x 938 大小的 Bitmap 图片 ;


<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
    <ImageView
        android:id="@+id/imageView"
        android:layout_width="match_parent"
        android:layout_height="0dip"
        android:scaleType="fitXY"
        app:layout_constraintDimensionRatio="1:1"
        app:layout_constraintVertical_bias="0"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
    <TextView
        android:id="@+id/sample_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>



3 . 执行效果 : 正方形的 ImageView , 显示从 938 x 7561 大小的图片上剪切下来的 938 x 938 大小的图片 , 效果如下 ;


image.png






六、源码及资源下载


源码及资源下载地址 :


① GitHub 工程地址 : Long_Graph_Loading


② MainActivity.java 主界面代码地址 : MainActivity.java , 这是上述示例代码中的主界面代码 ;


目录
相关文章
|
存储 缓存 算法
JVM简介—1.Java内存区域
本文详细介绍了Java虚拟机运行时数据区的各个方面,包括其定义、类型(如程序计数器、Java虚拟机栈、本地方法栈、Java堆、方法区和直接内存)及其作用。文中还探讨了各版本内存区域的变化、直接内存的使用、从线程角度分析Java内存区域、堆与栈的区别、对象创建步骤、对象内存布局及访问定位,并通过实例说明了常见内存溢出问题的原因和表现形式。这些内容帮助开发者深入理解Java内存管理机制,优化应用程序性能并解决潜在的内存问题。
766 29
JVM简介—1.Java内存区域
|
安全 算法 小程序
【03】微信支付商户申请下户到配置完整流程-微信开放平台创建APP应用-填写上传基础资料-生成安卓证书-获取Apk签名-申请+配置完整流程-优雅草卓伊凡
【03】微信支付商户申请下户到配置完整流程-微信开放平台创建APP应用-填写上传基础资料-生成安卓证书-获取Apk签名-申请+配置完整流程-优雅草卓伊凡
1044 28
【03】微信支付商户申请下户到配置完整流程-微信开放平台创建APP应用-填写上传基础资料-生成安卓证书-获取Apk签名-申请+配置完整流程-优雅草卓伊凡
|
缓存 监控 算法
JVM简介—2.垃圾回收器和内存分配策略
本文介绍了Java垃圾回收机制的多个方面,包括垃圾回收概述、对象存活判断、引用类型介绍、垃圾收集算法、垃圾收集器设计、具体垃圾回收器详情、Stop The World现象、内存分配与回收策略、新生代配置演示、内存泄漏和溢出问题以及JDK提供的相关工具。
JVM简介—2.垃圾回收器和内存分配策略
|
NoSQL 应用服务中间件 PHP
布谷一对一直播源码android版环境配置流程及功能明细
部署需基于 CentOS 7.9 系统,硬盘不低于 40G,使用宝塔面板安装环境,包括 PHP 7.3(含 Redis、Fileinfo 扩展)、Nginx、MySQL 5.6、Redis 和最新 Composer。Swoole 扩展需按步骤配置。2021.08.05 后部署需将站点目录设为 public 并用 ThinkPHP 伪静态。开发环境建议 Windows 操作系统与最新 Android Studio,基础配置涉及 APP 名称修改、接口域名更换、包名调整及第三方登录分享(如 QQ、微信)的配置,同时需完成阿里云与腾讯云相关设置。
|
存储 编解码 安全
阿里云高性能企业级甄选Intel第八代计算型c8i、通用型g8i和内存型r8i实例简介
计算型c8i、通用型g8i和内存型r8i实例是阿里云推出的高性能企业级甄选Intel第八代云服务器实例,采用CIPU+飞天技术架构,搭载最新的Intel 第五代至强可扩展处理器(代号EMR),性能进一步大幅提升,同时拥有AMX加持的AI能力增强,并在全球范围率先支持TDX机密虚拟机能力,实现了AI增强和全面安全防护的两大特色优势。本文将为您介绍这三个实例规格的性能、适用场景及最新活动价格以及选择指南,以供选择参考。
620 18
|
Dart 前端开发 Android开发
【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
531 4
【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
|
监控 Shell Linux
Android调试终极指南:ADB安装+多设备连接+ANR日志抓取全流程解析,覆盖环境变量配置/多设备调试/ANR日志分析全流程,附Win/Mac/Linux三平台解决方案
ADB(Android Debug Bridge)是安卓开发中的重要工具,用于连接电脑与安卓设备,实现文件传输、应用管理、日志抓取等功能。本文介绍了 ADB 的基本概念、安装配置及常用命令。包括:1) 基本命令如 `adb version` 和 `adb devices`;2) 权限操作如 `adb root` 和 `adb shell`;3) APK 操作如安装、卸载应用;4) 文件传输如 `adb push` 和 `adb pull`;5) 日志记录如 `adb logcat`;6) 系统信息获取如屏幕截图和录屏。通过这些功能,用户可高效调试和管理安卓设备。
10433 2
|
存储 编解码 缓存
|
存储 编解码 Android开发
Android内存优化-Bitmap内存优化
在日常开发中,我们不免会使用到Bitmap,而bitmap确实实在在的是内存使用的 “大户”,如何更好的使用 bitmap,减少其对 App内存的使用,是我们开发中不可回避的问题。
365 0
Android内存优化-Bitmap内存优化