1. 程式人生 > >圖片的三級快取和二次取樣使用的案例

圖片的三級快取和二次取樣使用的案例

首先跟大家介紹一下三級快取,當然快取的好處就是可以讓使用者體驗更好,通過首次訪問時將資料儲存起來,以後需要就直接在本地獲取資料,減少不必要的網路訪問次數,也減少了流量的開銷。但我們大部分應用都運用了此技術,所以三級快取運用面比較廣的。

所謂三級快取其實是一種載入圖片檔案的策略,簡單的來說就是 “記憶體——檔案——網路”,顧名思義,當你需要載入一張圖片,首先去記憶體中去取,原因是記憶體的響應速度最快,其次是外存(即SD卡),如果兩者都沒有你需要的圖片,那就只有傳送網路請求獲取圖片,但需要注意的是當網路獲取到圖片時首先存入SD卡中,當需要此圖片時,戶首先去快取中去取,但是快取還沒有存入資料,接著去sd卡中去獲取資料此時sd卡中已經有資料,在此時將sd卡中的資料存入快取中去的同時將資料取出來使用。當下一次需要使用該圖片時,就可以在快取中直接獲取圖片了。

三級快取想必大家已經有了一定的瞭解了下面來說說二次取樣

二次取樣使為了避免程式oom,當我們需要載入一張獲取多張圖片時,由於程式分配的記憶體有限,當圖片過大過多時,記憶體就就會溢位,程式就直接over了,所以二次取樣時為了優化程式。

我們來說說二次取樣的原理,首先我們獲取一張高清圖片獲取此圖片的寬(sourceWidth)和高(sourceHeight),然後自己把需要的圖片的寬(width)和高(height)通過引數縮放比率來進行調整,與原圖進行比較,通過BitmapFactory內部的解碼器引數的設定, 通過引數縮放(simpleSize)來不斷調整大小,當有一條邊和規定的邊相等時,將邊框繪製成功,第一次取樣完成,第二次取樣就是通過得到的邊框來設定彩色格式RGB_565

(如果想了解取樣格式,可以看我的下一篇部落格,裡面有彩色格式的介紹),然後就取樣好的圖片解碼填充邊框。二次取樣就完成了!

說了這麼多下面就給大家展示一個小案例,看完案例你應該就明白了。

下面是佈局檔案

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="demo.liuchen.com.android25_lrucache.MainActivity">

    <Button
        android:id="@+id/btn_getImg"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="Click"
        android:text="獲取圖片"/>

    <ImageView
        android:id="@+id/image_Show"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scaleType="centerCrop"/>


</LinearLayout>
下面是MainActivity:
package demo.liuchen.com.android25_lrucache;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Handler;
import android.os.Message;
import android.support.v4.util.LruCache;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

/**
 * 圖片的三級快取:LruCache--SDCard——Internet
 */
public class MainActivity extends AppCompatActivity {
//    private String url = "http://p8.qhimg.com/t0113125382f3c4141a.png";
    private String url = "http://t2.27270.com/uploads/tu/201606/32/k5xnewfzvz0.jpg";
    private ImageView imageView;
    private LruCache<String,Bitmap> lruCache;

    private Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if (msg.what==1){
                Bitmap bitmap = (Bitmap) msg.obj;
                imageView.setImageBitmap(bitmap);
            }
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        imageView = (ImageView) findViewById(R.id.image_Show);
        //獲取執行時記憶體
        Long MaxSize = Runtime.getRuntime().maxMemory();

        //初始化LruCache
        lruCache = new LruCache<String, Bitmap>((int) (MaxSize/8)){
            //key 從記憶體中取出或存入的物件的名字
            //value 存取的物件
            //return 返回物件的快取
            @Override
            protected int sizeOf(String key, Bitmap value) {
                return value.getByteCount();
            }
        };
    }
    public void Click(View view) {
    //當用戶需要圖片是先到快取中去取
        Bitmap bitmap = lruCache.get(getName(url));
        if (bitmap!= null){
            Log.e("TAG","在快取中獲取");
            imageView.setImageBitmap(bitmap);
        }else {
            //在檔案中查詢

            Bitmap bitmap1 = getBitmapFromSDCard(getName(url));
            if (bitmap1!= null){
                Log.e("TAG","在檔案中獲取");
                imageView.setImageBitmap(bitmap1);
                //如果圖片在SD卡中找到,將圖片放入快取
                Log.e("TAG","檔案中存在放入快取");
                lruCache.put(getName(url),bitmap1);
            }else {

                getBitmapFromNet();
            }
        }
    }
        //從網路獲取
    private void getBitmapFromNet() {
        Log.e("TAG","在網路中獲取");
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    URL path = new URL(url);
                    HttpURLConnection httpURLConn = (HttpURLConnection) path.openConnection();
                    if (httpURLConn.getResponseCode() == 200){
                        final Bitmap bitmap = BitmapFactory.decodeStream(httpURLConn.getInputStream());
                        //將圖片放入快取中
                        lruCache.put(getName(url),bitmap);
                        //將bitmap存入當前檔案的檔案中
                        SaveBitmapToSDCard(getName(url),bitmap);
                        Message message = Message.obtain();
                        message.obj=1;
                        message.obj=bitmap;


                       handler.sendMessage(message);

                    }

                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
	//將Bitmap存入sd卡中
    private void SaveBitmapToSDCard(String name, Bitmap bitmap) {
        BufferedOutputStream bos = null;
        try {
            bos = new BufferedOutputStream(new FileOutputStream(new File(getExternalCacheDir(),name)));
            if (name.endsWith("png")||name.endsWith("PNG")){
                //把bitmap存入SdCard中
                Log.e("TAG","把bitmap存入SdCard中");
                bitmap.compress(Bitmap.CompressFormat.PNG,100,bos);
            }else {
                bitmap.compress(Bitmap.CompressFormat.JPEG,100,bos);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }


    }
	//從sd卡中獲取圖片
    private Bitmap getBitmapFromSDCard(String name) {
      //  Log.e("TAG","從SD卡中獲取圖片");
	//如果需要原圖就可以不呼叫二次採用方法
  //   Bitmap bitmap = BitmapFactory.decodeFile(getExternalCacheDir().getAbsolutePath()+ File.separator+name);
        //在SD卡中取出的Bitmap進行二次取樣,傳出去後會將二次取樣好的圖片放入快取中
        Bitmap bitmap = BitmapUtils.getBitmap(getExternalCacheDir().getAbsolutePath()+File.separator+name,100,100);
        return  bitmap;
    }

    //獲取Bitmap為Url的名字
    public String getName(String url){
       String name = url.substring(url.lastIndexOf("/")+1,url.length());
        return name;
    }


}
下面是二次取樣的封裝類,方便呼叫。
package demo.liuchen.com.android25_lrucache;

/**
 * Created by Administrator on 2016/9/23.
 */

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;

/**
 * Bitmap二次取樣工具類
 */
public class BitmapUtils {
    /**
     *
     * @param filePath  bitmap的路徑
     * @param destWidth 希望取樣後Bitmap的寬
     * @param destHeight 希望取樣後Bitmap的高
     *
     * @return  只有邊框的bitmap
     */
    public static Bitmap getBitmap(String filePath, int destWidth, int destHeight) {
        //第一取樣
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(filePath, options);
        int outWidth = options.outWidth;
        int outHeight = options.outHeight;
        int sampleSize = 1;
        while ((outWidth / sampleSize > destWidth) || (outHeight / sampleSize > destHeight)) {
            sampleSize *= 2;
        }
        //第二次取樣
        options.inJustDecodeBounds = false;
        options.inSampleSize = sampleSize;
        options.inPreferredConfig = Bitmap.Config.RGB_565;
        return BitmapFactory.decodeFile(filePath, options);
    }
}
    }


    //獲取Bitmap為Url的名字
    public String getName(String url){
       String name = url.substring(url.lastIndexOf("/")+1,url.length());
        return name;
    }


}

//當然訪問了網路和sd卡記得在Manifest清單檔案加上許可權:
<uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

//好了案例就完成了,如果有問題歡迎評論和指正,也可以加好友一起交流學習。


下面是以上案例的程式碼需要的可以自行下載:http://download.csdn.net/detail/mr_condingson/9765051

相關推薦

圖片三級快取取樣使用的案例

首先跟大家介紹一下三級快取,當然快取的好處就是可以讓使用者體驗更好,通過首次訪問時將資料儲存起來,以後需要就直接在本地獲取資料,減少不必要的網路訪問次數,也減少了流量的開銷。但我們大部分應用都運用了此技術,所以三級快取運用面比較廣的。 所謂三級快取其實是一種載入圖片檔案的策

大數據技術之輔助排序排序案例(GroupingComparator)

group http pac ppr instance div lec tex boolean 大數據技術之輔助排序和二次排序案例(GroupingComparator) 1)需求 有如下訂單數據 訂單id 商品id 成交金額

PullToRefreshListView上拉下拉+輪播圖多條目+fragment巢狀fragment+取樣+側拉點選切換fragment+PullToRefreshGritView圖片展示

側拉 程式碼 1提取的基類 1.1Activity的基類 package com.example.zonghelianxi02.ui.activity; import android.os.Bundle; import android.support.annotation.Nulla

取樣三級快取

1.建立一個Util類,裡面封裝了二次取樣和三級快取的方法 public class ImageUtil { //二次取樣 public static Bitmap TwoImage(String filepath,int width,int heigh){ BitmapFac

取樣圖片

Mantivity主頁面: package com.bw.ymy.ymy1107; import android.content.Intent; import android.database.Cursor; import android.graphics.Bitmap; import

圖片取樣

MainActivity頁面 package com.example.image; import android.content.Intent; import android.database.Cursor; import android.graphics.Bitmap; import

側滑+fragment切換頁面+fragment巢狀+取樣+輪播圖+gridview展示圖片+網路請求資料+資料庫

全域性配置Appliction 所需要的依賴有:implementation ‘com.google.code.gson:gson:2.8.5’ implementation ‘com.nostra13.universalimageloader:universal-image-loader:

圖片取樣///////////子執行緒

1.提取的基類 在這裡插入程式碼片package com.example.imager_er; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v7

fragment中的ImagView+Text多條目,點選ImageView取樣切換相簿圖片

##Fragmentd的 XML: <?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android=“http://schemas.and

某宅的Android學習筆記()——圖片三級快取

圖片三級快取的重要性  很多時候我們都需要從網路上下載圖片,如果在圖片很多的情況下,每次啟動app都要從網上下載,就會造成流量的浪費,影響使用者的體驗。因此,要利用快取來避免圖片的重複載入。 圖片快取方式  所謂三級快取,即: 網路快取 記憶體快取

Android_Bitmap_圖片取樣並生成縮圖

首先嚐試通過位元組陣列或者流,只去載入圖片的外邊緣,此時必須指定BitmapFactory.Options 的inJustDecodeBounds成員名,將其只為true,一旦設定為true,BitmapFactory解碼後返回值為null,通過Options的outHe

04 用戶個人信息開發django的文件存儲系統

存在 引入 tracker 連接 code quest 安裝包 gis ase 用戶的個人信息的前端頁面如下: 業務邏輯分析 從上圖中可以看出,需要後端傳送的數據有,用戶的名字和練習的地址,和最近的瀏覽記錄。 用戶的名字和聯系的地址可以通過地址表(adre

Android反編譯打包

犯錯 解壓 就會 field har stat 生成 https make 參考:APK反編譯 一、工具介紹: 1、解壓工具 2、JDK 3.apktool: aapt.exe,apktool.bat,apktool.jar;三個在同一目錄結合使用,用來反編譯apk

Vue 中使用 el-input 自動獲取焦點獲取焦點問題

最近,碰到一個問題,就是輸入框旁邊有一個編輯按鈕,點選時,才可以對輸入框進行編輯: 要實現的效果: 為了方便輸入,需要自動獲取焦點,所以加入了autofocus,但是發現,只有第一個並且第一次點選才起作用。 查了網上的一些文件,說是跟dom的渲染順序和資料的快取有點兒關係,至

取樣+AsyncTask

#1.主頁面 package com.bw.ymy.imageloader; import android.content.Intent; import android.database.Cursor; import android.graphics.Bitmap; import a

微信開發案例,python製作微信支付小程式!

  由於最近自己在做小程式的支付,就在這裡簡單介紹一下講一下用python做小程式支付這個流程。當然在進行開發之前還是建議讀一下具體的流程,清楚支付的過程。 1.支付互動流程   當然具體的引數配置可以參考官方文件 https://p

取樣+質量壓縮

1.MainActivity頁面 package com.example.image; import android.content.Intent; import android.database.Cursor; import android.graphics.Bitmap; impo

【51Nod1405】樹上距離 掃描與換根法

continue 51nod max span ons its 轉移 rom ace 題目大意:給定一棵 N 個點的邊權均為 1 的樹,依次輸出每個點到其他各個點的距離和。 題解:首先任意選定一個節點為根節點,比如 1,第一遍 dfs 遍歷樹求出子樹大小、樹上前綴和。第二遍

側滑(點選條目進行跳轉+點選更換頭像(取樣))+ViewPager

1.Layout佈局 <?xml version="1.0" encoding="utf-8"?> <android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk

點選頭像取樣

1.側滑佈局 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_w