【Android 内存优化】Android 原生 API 图片压缩代码示例 ( PNG 格式压缩 | JPEG 格式压缩 | WEBP 格式压缩 | 动态权限申请 | Android10 存储策略 )

简介: 【Android 内存优化】Android 原生 API 图片压缩代码示例 ( PNG 格式压缩 | JPEG 格式压缩 | WEBP 格式压缩 | 动态权限申请 | Android10 存储策略 )

文章目录

一、 图片质量压缩

二、 图片尺寸压缩

三、 Android 10 文件访问

四、 完整源码示例



上一篇博客 【Android 内存优化】图片文件压缩 ( Android 原生 API 提供的图片压缩功能能 | 图片质量压缩 | 图片尺寸压缩 ) 简要介绍了 图片文件压缩格式 , 以及 Android 提供的图片质量 , 尺寸压缩 API , 本博客中使用该 API 进行图片压缩 ;






一、 图片质量压缩


图片质量压缩步骤 :



① 创建输出流 : 创建一个文件输出流 , 也可是是网络输出流 ;


FileOutputStream fos = new FileOutputStream(path);


② 加载文件 : 从 Assets , 资源文件 , SD 卡 , 中 解码图片文件为内存中的 Bitmap 对象 ; 这里从资源文件中加载 ;


Bitmap bitmap = BitmapFactory.decodeResource(getResources(), resId);


③ 压缩图片 : 调用 Bitmap 对象的 compress 方法 , 压缩图片 ;


bitmap.compress(compressFormat, quality, fos);






二、 图片尺寸压缩


图片尺寸压缩流程 :



① 加载文件 : 从 Assets , 资源文件 , SD 卡 , 中解码图片文件为内存中的 Bitmap 对象 ; 这里从资源文件中加载 ;


Bitmap bitmap = BitmapFactory.decodeResource(getResources(), resId);


② 图片尺寸压缩 : 调用 Bitmap 对象的 createScaledBitmap 方法 , 将目标宽高作为参数传入 , 并使用双线性滤波器算法 , 该算法能大幅度提供压缩后的图片质量 , 并且开销较少 , 官方建议开启该算法 ;


bitmap = Bitmap.createScaledBitmap(bitmap, width, height, true);






三、 Android 10 文件访问


文件存储相关官方参考资料 :


Android 11 中的存储机制更新

Android storage use cases and best practices

应用数据和文件


将图片压缩后 , 存储到 SD 卡中 , 这里 涉及到了在 Android 10 系统中动态申请权限 , 设置旧的存储访问策略 ( 该策略将在 Android 11 中无效 ) ;


这里简要介绍暂时性的解决方案 ;



1. AndroidManifest.xml 中配置 SD 卡权限 , 及旧存储策略 :



① SD 卡权限 : 配置 SD 卡读写权限 ;


<!-- SD 卡访问权限 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />


② 旧存储策略 : 配置在 application 标签中 , 特别注意该策略将在 Android 11 中废弃 ;


android:requestLegacyExternalStorage="true"

③ 完整配置 :


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="kim.hsl.pc">
  <!-- SD 卡访问权限 -->
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
  <!-- android:requestLegacyExternalStorage="true" 配置旧存储策略 , Android 11 将禁止该功能 -->
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme"
        android:requestLegacyExternalStorage="true">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>




2 . 在 Activity 中动态申请权限 : 在 Activity 中调用 initPermissions(); 方法 , 即可动态申请 SD 卡访问权限 ;


 

/**
     * 需要获取的权限列表
     */
    private String[] permissions = new String[]{
            Manifest.permission.READ_EXTERNAL_STORAGE,
            Manifest.permission.WRITE_EXTERNAL_STORAGE
    };
    /**
     * 动态申请权限的请求码
     */
    private static final int PERMISSION_REQUEST_CODE = 888;
    /**
     * 动态申请权限
     */
    @RequiresApi(api = Build.VERSION_CODES.M)
    private void initPermissions() {
        if (isLacksPermission()) {
            //动态申请权限 , 第二参数是请求吗
            requestPermissions(permissions, PERMISSION_REQUEST_CODE);
        }
    }
    /**
     * 判断是否有 permissions 中的权限
     * @return
     */
    @RequiresApi(api = Build.VERSION_CODES.M)
    public boolean isLacksPermission() {
        for (String permission : permissions) {
            if(checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED){
                return true;
            }
        }
        return false;
    }



执行完上述三个步骤的操作


配置权限

设置旧存储策略

动态申请权限

即可在 Android 10 中访问 SD 卡 , 如果在 Android 11 访问 , 查看章节开始的文档 ;






四、 完整源码示例


图片压缩源码示例 :


压缩质量 : 下图中的图片压缩都压缩成最低质量的图片 ;
package kim.hsl.pc;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import android.Manifest;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.widget.TextView;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
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());
        // 初始化权限
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            initPermissions();
        }
        // 将图片压缩成 JPEG 格式, 不缩放
        compressBitmap(R.drawable.blog, Bitmap.CompressFormat.JPEG, 0,
                Environment.getExternalStorageDirectory() + "/blog_jpeg.jpeg",
                0, 0);
        // 将图片压缩成 WEBP  格式
        compressBitmap(R.drawable.blog, Bitmap.CompressFormat.WEBP, 0,
                Environment.getExternalStorageDirectory() + "/blog_webp.webp",
                0, 0);
        // 将图片压缩成 PNG  格式
        compressBitmap(R.drawable.blog, Bitmap.CompressFormat.PNG, 0,
                Environment.getExternalStorageDirectory() + "/blog_png.png",
                0, 0);
        // 将图片宽高各压缩一半
        compressBitmap(R.drawable.blog, Bitmap.CompressFormat.PNG, 0,
                Environment.getExternalStorageDirectory() + "/blog_png_half.png",
                995, 510);
    }
    /**
     * 压缩图片, 并将压缩结果保存到指定文件
     * @param resId 图片资源
     * @param compressFormat 图片压缩格式
     * @param quality 压缩质量
     * @param path 文件保存路径
     */
    public void compressBitmap(int resId, Bitmap.CompressFormat compressFormat,
                               int quality, String path, int width, int height){
        // 从资源文件中加载一张图片
        Bitmap bitmap = BitmapFactory.decodeResource(getResources(), resId);
        // 如果传入的尺寸参数大于 0, 那么压缩尺寸
        if(width > 0 && height > 0){
            bitmap = Bitmap.createScaledBitmap(bitmap, width, height, true);
        }
        // 用于写出压缩后的图片到文件中
        FileOutputStream fos = null;
        try {
            // 打开文件输出流
            fos = new FileOutputStream(path);
            // 图片压缩操作
            // 如果图片格式是 PNG 格式, 会忽略 质量 参数
            bitmap.compress(compressFormat, quality, fos);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            Log.i("TAG", "文件输出流打开失败");
        }finally {
            if(fos != null){
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                    Log.i("TAG", "文件输出流关闭失败");
                }
            }
        }
    }
    public native String stringFromJNI();
    /**
     * 需要获取的权限列表
     */
    private String[] permissions = new String[]{
            Manifest.permission.READ_EXTERNAL_STORAGE,
            Manifest.permission.WRITE_EXTERNAL_STORAGE
    };
    /**
     * 动态申请权限的请求码
     */
    private static final int PERMISSION_REQUEST_CODE = 888;
    /**
     * 动态申请权限
     */
    @RequiresApi(api = Build.VERSION_CODES.M)
    private void initPermissions() {
        if (isLacksPermission()) {
            //动态申请权限 , 第二参数是请求吗
            requestPermissions(permissions, PERMISSION_REQUEST_CODE);
        }
    }
    /**
     * 判断是否有 permissions 中的权限
     * @return
     */
    @RequiresApi(api = Build.VERSION_CODES.M)
    public boolean isLacksPermission() {
        for (String permission : permissions) {
            if(checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED){
                return true;
            }
        }
        return false;
    }
}




压缩结果分析 :



① 压缩后的 PNG 格式 : 2.63 MB ;


② 压缩后的 JPEG 格式 : 119 KB ;


③ 压缩后的 WEBP 格式图片 : 102 KB ;


④ 尺寸压缩图片 : 219 KB ;




压缩格式中 PNG > JPEG > WEBP 格式 ;


PNG 图片不能压缩 , 这里显示的大小是原图大小 , 非常大 ;


目录
相关文章
|
8天前
|
存储 编译器 Linux
【c++】类和对象(上)(类的定义格式、访问限定符、类域、类的实例化、对象的内存大小、this指针)
本文介绍了C++中的类和对象,包括类的概念、定义格式、访问限定符、类域、对象的创建及内存大小、以及this指针。通过示例代码详细解释了类的定义、成员函数和成员变量的作用,以及如何使用访问限定符控制成员的访问权限。此外,还讨论了对象的内存分配规则和this指针的使用场景,帮助读者深入理解面向对象编程的核心概念。
27 4
|
7天前
|
存储 分布式计算 算法
1GB内存挑战:高效处理40亿QQ号的策略
在面对如何处理40亿个QQ号仅用1GB内存的难题时,我们需要采用一些高效的数据结构和算法来优化内存使用。这个问题涉及到数据存储、查询和处理等多个方面,本文将分享一些实用的技术策略,帮助你在有限的内存资源下处理大规模数据集。
16 1
|
9天前
|
存储 监控 Java
深入理解计算机内存管理:优化策略与实践
深入理解计算机内存管理:优化策略与实践
|
1月前
|
存储 安全 Java
jdk21的外部函数和内存API(MemorySegment)(官方翻译)
本文介绍了JDK 21中引入的外部函数和内存API(MemorySegment),这些API使得Java程序能够更安全、高效地与JVM外部的代码和数据进行互操作,包括调用外部函数、访问外部内存,以及使用不同的Arena竞技场来分配和管理MemorySegment。
43 1
jdk21的外部函数和内存API(MemorySegment)(官方翻译)
|
22天前
|
存储 C语言
数据在内存中的存储方式
本文介绍了计算机中整数和浮点数的存储方式,包括整数的原码、反码、补码,以及浮点数的IEEE754标准存储格式。同时,探讨了大小端字节序的概念及其判断方法,通过实例代码展示了这些概念的实际应用。
45 1
|
26天前
|
存储
共用体在内存中如何存储数据
共用体(Union)在内存中为所有成员分配同一段内存空间,大小等于最大成员所需的空间。这意味着所有成员共享同一块内存,但同一时间只能存储其中一个成员的数据,无法同时保存多个成员的值。
|
8天前
|
JSON API 数据安全/隐私保护
拍立淘按图搜索API接口返回数据的JSON格式示例
拍立淘按图搜索API接口允许用户通过上传图片来搜索相似的商品,该接口返回的通常是一个JSON格式的响应,其中包含了与上传图片相似的商品信息。以下是一个基于淘宝平台的拍立淘按图搜索API接口返回数据的JSON格式示例,同时提供对其关键字段的解释
|
1月前
|
存储 弹性计算 算法
前端大模型应用笔记(四):如何在资源受限例如1核和1G内存的端侧或ECS上运行一个合适的向量存储库及如何优化
本文探讨了在资源受限的嵌入式设备(如1核处理器和1GB内存)上实现高效向量存储和检索的方法,旨在支持端侧大模型应用。文章分析了Annoy、HNSWLib、NMSLib、FLANN、VP-Trees和Lshbox等向量存储库的特点与适用场景,推荐Annoy作为多数情况下的首选方案,并提出了数据预处理、索引优化、查询优化等策略以提升性能。通过这些方法,即使在资源受限的环境中也能实现高效的向量检索。
|
1月前
|
存储 编译器
数据在内存中的存储
数据在内存中的存储
41 4
|
2月前
|
API PHP
ThinkPHP 通用的API格式封装
本文介绍了在ThinkPHP框架中如何统一封装API返回格式的方法,包括创建状态码枚举类、编写统一格式化函数以及在BaseController和Error控制器中重写`__call`方法来处理不存在的方法或控制器调用,以实现统一的错误处理和返回格式。
ThinkPHP 通用的API格式封装

热门文章

最新文章