【Android 内存优化】Android 原生 API 图片压缩代码示例 ( PNG 格式压缩 | JPEG 格式压缩 | WEBP 格式压缩 | 动态权限申请 | Android10 存储策略 )
文章目錄
- 一、 圖片質(zhì)量壓縮
- 二、 圖片尺寸壓縮
- 三、 Android 10 文件訪問(wèn)
- 四、 完整源碼示例
上一篇博客 【Android 內(nèi)存優(yōu)化】圖片文件壓縮 ( Android 原生 API 提供的圖片壓縮功能能 | 圖片質(zhì)量壓縮 | 圖片尺寸壓縮 ) 簡(jiǎn)要介紹了 圖片文件壓縮格式 , 以及 Android 提供的圖片質(zhì)量 , 尺寸壓縮 API , 本博客中使用該 API 進(jìn)行圖片壓縮 ;
一、 圖片質(zhì)量壓縮
圖片質(zhì)量壓縮步驟 :
① 創(chuàng)建輸出流 : 創(chuàng)建一個(gè)文件輸出流 , 也可是是網(wǎng)絡(luò)輸出流 ;
FileOutputStream fos = new FileOutputStream(path);② 加載文件 : 從 Assets , 資源文件 , SD 卡 , 中 解碼圖片文件為內(nèi)存中的 Bitmap 對(duì)象 ; 這里從資源文件中加載 ;
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), resId);③ 壓縮圖片 : 調(diào)用 Bitmap 對(duì)象的 compress 方法 , 壓縮圖片 ;
bitmap.compress(compressFormat, quality, fos);二、 圖片尺寸壓縮
圖片尺寸壓縮流程 :
① 加載文件 : 從 Assets , 資源文件 , SD 卡 , 中解碼圖片文件為內(nèi)存中的 Bitmap 對(duì)象 ; 這里從資源文件中加載 ;
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), resId);② 圖片尺寸壓縮 : 調(diào)用 Bitmap 對(duì)象的 createScaledBitmap 方法 , 將目標(biāo)寬高作為參數(shù)傳入 , 并使用雙線性濾波器算法 , 該算法能大幅度提供壓縮后的圖片質(zhì)量 , 并且開(kāi)銷較少 , 官方建議開(kāi)啟該算法 ;
bitmap = Bitmap.createScaledBitmap(bitmap, width, height, true);三、 Android 10 文件訪問(wèn)
文件存儲(chǔ)相關(guān)官方參考資料 :
- Android 11 中的存儲(chǔ)機(jī)制更新
- Android storage use cases and best practices
- 應(yīng)用數(shù)據(jù)和文件
將圖片壓縮后 , 存儲(chǔ)到 SD 卡中 , 這里 涉及到了在 Android 10 系統(tǒng)中動(dòng)態(tài)申請(qǐng)權(quán)限 , 設(shè)置舊的存儲(chǔ)訪問(wèn)策略 ( 該策略將在 Android 11 中無(wú)效 ) ;
這里簡(jiǎn)要介紹暫時(shí)性的解決方案 ;
1. AndroidManifest.xml 中配置 SD 卡權(quán)限 , 及舊存儲(chǔ)策略 :
① SD 卡權(quán)限 : 配置 SD 卡讀寫(xiě)權(quán)限 ;
<!-- SD 卡訪問(wèn)權(quán)限 --> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />② 舊存儲(chǔ)策略 : 配置在 application 標(biāo)簽中 , 特別注意該策略將在 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 卡訪問(wèn)權(quán)限 --><uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /><!-- android:requestLegacyExternalStorage="true" 配置舊存儲(chǔ)策略 , Android 11 將禁止該功能 --><applicationandroid: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 中動(dòng)態(tài)申請(qǐng)權(quán)限 : 在 Activity 中調(diào)用 initPermissions(); 方法 , 即可動(dòng)態(tài)申請(qǐng) SD 卡訪問(wèn)權(quán)限 ;
/*** 需要獲取的權(quán)限列表*/private String[] permissions = new String[]{Manifest.permission.READ_EXTERNAL_STORAGE,Manifest.permission.WRITE_EXTERNAL_STORAGE};/*** 動(dòng)態(tài)申請(qǐng)權(quán)限的請(qǐng)求碼*/private static final int PERMISSION_REQUEST_CODE = 888;/*** 動(dòng)態(tài)申請(qǐng)權(quán)限*/@RequiresApi(api = Build.VERSION_CODES.M)private void initPermissions() {if (isLacksPermission()) {//動(dòng)態(tài)申請(qǐng)權(quán)限 , 第二參數(shù)是請(qǐng)求嗎requestPermissions(permissions, PERMISSION_REQUEST_CODE);}}/*** 判斷是否有 permissions 中的權(quán)限* @return*/@RequiresApi(api = Build.VERSION_CODES.M)public boolean isLacksPermission() {for (String permission : permissions) {if(checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED){return true;}}return false;}執(zhí)行完上述三個(gè)步驟的操作
- 配置權(quán)限
- 設(shè)置舊存儲(chǔ)策略
- 動(dòng)態(tài)申請(qǐng)權(quán)限
即可在 Android 10 中訪問(wèn) SD 卡 , 如果在 Android 11 訪問(wèn) , 查看章節(jié)開(kāi)始的文檔 ;
四、 完整源碼示例
圖片壓縮源碼示例 :
壓縮質(zhì)量 : 下圖中的圖片壓縮都?jí)嚎s成最低質(zhì)量的圖片 ;
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");}@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);TextView tv = findViewById(R.id.sample_text);tv.setText(stringFromJNI());// 初始化權(quán)限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);}/*** 壓縮圖片, 并將壓縮結(jié)果保存到指定文件* @param resId 圖片資源* @param compressFormat 圖片壓縮格式* @param quality 壓縮質(zhì)量* @param path 文件保存路徑*/public void compressBitmap(int resId, Bitmap.CompressFormat compressFormat,int quality, String path, int width, int height){// 從資源文件中加載一張圖片Bitmap bitmap = BitmapFactory.decodeResource(getResources(), resId);// 如果傳入的尺寸參數(shù)大于 0, 那么壓縮尺寸if(width > 0 && height > 0){bitmap = Bitmap.createScaledBitmap(bitmap, width, height, true);}// 用于寫(xiě)出壓縮后的圖片到文件中FileOutputStream fos = null;try {// 打開(kāi)文件輸出流fos = new FileOutputStream(path);// 圖片壓縮操作// 如果圖片格式是 PNG 格式, 會(huì)忽略 質(zhì)量 參數(shù)bitmap.compress(compressFormat, quality, fos);} catch (FileNotFoundException e) {e.printStackTrace();Log.i("TAG", "文件輸出流打開(kāi)失敗");}finally {if(fos != null){try {fos.close();} catch (IOException e) {e.printStackTrace();Log.i("TAG", "文件輸出流關(guān)閉失敗");}}}}public native String stringFromJNI();/*** 需要獲取的權(quán)限列表*/private String[] permissions = new String[]{Manifest.permission.READ_EXTERNAL_STORAGE,Manifest.permission.WRITE_EXTERNAL_STORAGE};/*** 動(dòng)態(tài)申請(qǐng)權(quán)限的請(qǐng)求碼*/private static final int PERMISSION_REQUEST_CODE = 888;/*** 動(dòng)態(tài)申請(qǐng)權(quán)限*/@RequiresApi(api = Build.VERSION_CODES.M)private void initPermissions() {if (isLacksPermission()) {//動(dòng)態(tài)申請(qǐng)權(quán)限 , 第二參數(shù)是請(qǐng)求嗎requestPermissions(permissions, PERMISSION_REQUEST_CODE);}}/*** 判斷是否有 permissions 中的權(quán)限* @return*/@RequiresApi(api = Build.VERSION_CODES.M)public boolean isLacksPermission() {for (String permission : permissions) {if(checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED){return true;}}return false;} }壓縮結(jié)果分析 :
① 壓縮后的 PNG 格式 : 2.63 MB ;
② 壓縮后的 JPEG 格式 : 119 KB ;
③ 壓縮后的 WEBP 格式圖片 : 102 KB ;
④ 尺寸壓縮圖片 : 219 KB ;
壓縮格式中 PNG > JPEG > WEBP 格式 ;
PNG 圖片不能壓縮 , 這里顯示的大小是原圖大小 , 非常大 ;
總結(jié)
以上是生活随笔為你收集整理的【Android 内存优化】Android 原生 API 图片压缩代码示例 ( PNG 格式压缩 | JPEG 格式压缩 | WEBP 格式压缩 | 动态权限申请 | Android10 存储策略 )的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 【Android 内存优化】图片文件压缩
- 下一篇: 【Android 内存优化】Androi