提高Android應用性能,LRUCache是個好幫手

在Android應用開發中,優化應用性能是一項非常重要的任務。應用程序的性能優化需要仔細考慮內存使用和緩存管理。在這篇文章中,我將介紹一種優化緩存管理的技術——LRUCache,並提供一些使用它的實際代碼示例。

一、什麼是LRUCache

LRUCache是一個Android內置的緩存管理類,它可以幫助我們高效地管理內存中的緩存對象。”LRU”代表最近最少使用(Least Recently Used)。該類按照值的最近使用次數自動回收緩存對象。當緩存空間滿時,較早不使用的緩存對象將被回收,從而騰出空間。

二、使用LRUCache實現內存緩存

在實現內存緩存時,可以使用LRUCache類。接下來,我們將看到如何使用LRUCache執行內存緩存。

    private int cacheSize = 4 * 1024 * 1024; // 4 MiB
    private LRUCache memoryCache = new LRUCache(cacheSize) {
        protected int sizeOf(String key, Bitmap bitmap) {
            return bitmap.getByteCount();
        }
    };
    
    //向緩存中添加數據
    public void addBitmapToMemoryCache(String key, Bitmap bitmap) {
        if (getBitmapFromMemCache(key) == null) {
            memoryCache.put(key, bitmap);
        }
    }
    
    //從緩存中獲取數據    
    public Bitmap getBitmapFromMemCache(String key) {
        return memoryCache.get(key);
    }

在上面的代碼中,我們使用LRUCache類表示一個內存緩存,它在存儲數據時會自動回收內存。它使用Bitmap類作為緩存對象,並使用緩存對象的位元組數來表示緩存的大小。

我們通過addBitmapToMemoryCache()方法向緩存中添加Bitmap對象,並通過getBitmapFromMemCache()方法從緩存中獲取對象。以上代碼段僅為參考,您需要根據實際情況自行實現相應的數據的添加和獲取操作。

三、使用LRUCache實現磁碟緩存

實現磁碟緩存的方式與內存緩存有所不同。我們需要先將緩存對象寫入磁碟,然後在需要時從磁碟中獲取。請看下面的代碼示例:

    private static final long DISK_CACHE_SIZE = 50 * 1024 * 1024; // 50 MiB
    private static final int DISK_CACHE_INDEX = 0;
    
    private DiskLruCache diskCache;

    //初始化磁碟緩存
    private void initDiskCache() {
        try {
            File cacheDir = getDiskCacheDir(mContext, "bitmap");
            if (!cacheDir.exists()) {
                cacheDir.mkdirs();
            }
            diskCache = DiskLruCache.open(cacheDir, getAppVersion(), 1, DISK_CACHE_SIZE);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    //添加Bitmap對象到磁碟緩存中
    private boolean addBitmapToDiskCache(String key, Bitmap bitmap) {
        if (getBitmapFromDiskCache(key) == null) {
            try {
                DiskLruCache.Editor editor = diskCache.edit(key);
                if (editor != null) {
                    OutputStream outputStream = editor.newOutputStream(DISK_CACHE_INDEX);
                    bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream);
                    editor.commit();
                    outputStream.close();
                    return true;
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return false;
    }
    
    //從磁碟緩存中獲取Bitmap對象
    private Bitmap getBitmapFromDiskCache(String key) {
        try {
            DiskLruCache.Snapshot snapshot = diskCache.get(key);
            if (snapshot != null) {
                FileInputStream input = (FileInputStream) snapshot.getInputStream(DISK_CACHE_INDEX);
                return BitmapFactory.decodeStream(input);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
    
    //獲取磁碟緩存的路徑
    private static File getDiskCacheDir(Context context, String uniqueName) {
        String cachePath = context.getCacheDir().getPath();
        return new File(cachePath + File.separator + uniqueName);
    }
    
    //獲取應用程序當前版本號
    private int getAppVersion() {
        try {
            PackageInfo info = mContext.getPackageManager().getPackageInfo(mContext.getPackageName(), 0);
            return info.versionCode;
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        return 1;
    }

在上面的代碼段中,我們首先使用DiskLruCache類創建一個磁碟緩存。然後,我們使用addBitmapToDiskCache()方法將Bitmap對象寫入磁碟緩存,使用getBitmapFromDiskCache()方法從緩存中獲取Bitmap對象。

與內存緩存不同,磁碟緩存可存儲所有類型的對象,而不僅僅是Bitmap。在使用時,我們需要自己負責緩存對象的序列化和反序列化。

四、LRUCache應用舉例

接下來,我們將看到如何在實際的應用程序中應用LRUCache類。

假設我們需要在一個圖片顯示應用程序中使用LRUCache來管理圖片緩存。該應用程序從一個網站中獲取圖片,並在屏幕上顯示這些圖片。為了優化應用程序的性能,我們需要使用LRUCache類來管理內存和磁碟緩存。

根據應用程序的需求,我們可以設計一個ImageLoader類來負責圖片的載入和緩存。以下是該類的示例代碼:

    public class ImageLoader {

        private final LRUCache memoryCache;
        private final DiskLruCache diskCache;

        public ImageLoader(Context context) {
            int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
            int cacheSize = maxMemory / 4;
            memoryCache = new LRUCache(cacheSize) {
                @Override
                protected int sizeOf(String key, Bitmap value) {
                    return value.getByteCount() / 1024;
                }
            };

            try {
                File cacheDir = getDiskCacheDir(context, "bitmap");
                if (!cacheDir.exists()) {
                    cacheDir.mkdirs();
                }
                diskCache = DiskLruCache.open(cacheDir, getAppVersion(context), 1, DISK_CACHE_SIZE);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        //從內存緩存中獲取圖片
        public Bitmap getBitmapFromMemoryCache(String url) {
            return memoryCache.get(url);
        }

        //存儲圖片到內存緩存
        public void addBitmapToMemoryCache(String url, Bitmap bitmap) {
            if (getBitmapFromMemoryCache(url) == null) {
                memoryCache.put(url, bitmap);
            }
        }

        //從磁碟緩存中獲取圖片
        public Bitmap getBitmapFromDiskCache(String url) {
            Bitmap bitmap = null;
            String key = hashKeyForDisk(url);
            try {
                DiskLruCache.Snapshot snapshot = diskCache.get(key);
                if (snapshot != null) {
                    FileInputStream inputStream = (FileInputStream) snapshot.getInputStream(0);
                    FileDescriptor fileDescriptor = inputStream.getFD();
                    bitmap = BitmapFactory.decodeFileDescriptor(fileDescriptor);
                    if (bitmap != null) {
                        //存儲圖片到內存緩存
                        addBitmapToMemoryCache(url, bitmap);
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            return bitmap;
        }

        //下載圖片並存儲在本地磁碟緩存
        public void downloadBitmapToDiskCache(String url) {
            String key = hashKeyForDisk(url);
            try {
                DiskLruCache.Editor editor = diskCache.edit(key);
                if (editor != null) {
                    OutputStream outputStream = editor.newOutputStream(0);
                    if (downloadUrlToStream(url, outputStream)) {
                        editor.commit();
                    } else {
                        editor.abort();
                    }
                    outputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        //將URL轉換為磁碟緩存中的鍵
        private String hashKeyForDisk(String url) {
            String cacheKey;
            try {
                final MessageDigest mDigest = MessageDigest.getInstance("MD5");
                mDigest.update(url.getBytes());
                cacheKey = bytesToHexString(mDigest.digest());
            } catch (NoSuchAlgorithmException e) {
                cacheKey = String.valueOf(url.hashCode());
            }
            return cacheKey;
        }

        private String bytesToHexString(byte[] bytes) {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < bytes.length; i++) {
                String hex = Integer.toHexString(0xFF & bytes[i]);
                if (hex.length() == 1) {
                    sb.append('0');
                }
                sb.append(hex);
            }
            return sb.toString();
        }

        private boolean downloadUrlToStream(String urlString, OutputStream outputStream) {
            HttpURLConnection urlConnection = null;
            BufferedOutputStream out = null;
            BufferedInputStream in = null;
            try {
                final URL url = new URL(urlString);
                urlConnection = (HttpURLConnection) url.openConnection();
                in = new BufferedInputStream(urlConnection.getInputStream(), IO_BUFFER_SIZE);
                out = new BufferedOutputStream(outputStream, IO_BUFFER_SIZE);

                int b;
                while ((b = in.read()) != -1) {
                    out.write(b);
                }
                return true;
            } catch (final IOException e) {
                e.printStackTrace();
            } finally {
                if (urlConnection != null) {
                    urlConnection.disconnect();
                }
                try {
                    if (out != null) {
                        out.close();
                    }
                    if (in != null) {
                        in.close();
                    }
                } catch (final IOException e) {
                    e.printStackTrace();
                }
            }
            return false;
        }

        private static final int IO_BUFFER_SIZE = 8 * 1024;

        //獲取應用程序當前版本號
        private int getAppVersion(Context context) {
            try {
                PackageInfo info = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
                return info.versionCode;
            } catch (PackageManager.NameNotFoundException e) {
                e.printStackTrace();
            }
            return 1;
        }

        //獲取磁碟緩存的路徑
        private static File getDiskCacheDir(Context context, String uniqueName) {
            String cachePath = context.getCacheDir().getPath();
            return new File(cachePath + File.separator + uniqueName);
        }
    }    

ImageLoader類包含了所有必要的方法,包括從內存和磁碟緩存中獲取圖片、將圖片添加到內存和磁碟緩存中、將URL轉換為磁碟上的鍵等等。

在這個應用程序中,LRUCache使我們的緩存管理更容易實現。通過使用LRUCache,我們可以輕鬆地管理Android應用程序中的內存和磁碟緩存,從而最大限度地提高應用程序的性能。

原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/303706.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
小藍的頭像小藍
上一篇 2024-12-31 11:50
下一篇 2024-12-31 11:50

相關推薦

發表回復

登錄後才能評論