1. 程式人生 > >android 載入大量圖片不卡頓

android 載入大量圖片不卡頓


/**
 * 通過路徑獲取圖片,然後對圖片進行壓縮 存入快取中 更新介面
 * 
 * 通過將任務存入任務佇列中,通知輪詢執行緒從任務佇列中獲取任務的方法,
 * 來解決大量圖片載入過程中 滑動卡頓的問題(核心解決辦法)
 * 
 */
public class ImageLoader
{
    /**
     * 圖片快取的核心類
     */
    private LruCache<String, Bitmap> mLruCache;
    /**
     * 執行緒池
     */
    private ExecutorService mThreadPool;
    /**
     * 執行緒池的執行緒數量,預設為1
     */
private int mThreadCount = 3; /** * 佇列的排程方式 */ private Type mType = Type.LIFO; /** * 任務佇列 */ private LinkedList<Runnable> mTasks; /** * 輪詢的執行緒 */ private Thread mPoolThread; private Handler mPoolThreadHander; /** * 執行在UI執行緒的handler,用於給ImageView設定圖片 */
private Handler mHandler; /** * 引入一個值為1的訊號量,防止mPoolThreadHander未初始化完成 */ private volatile Semaphore mSemaphore = new Semaphore(0); /** * 引入一個值為1的訊號量,由於執行緒池內部也有一個阻塞執行緒,防止加入任務的速度過快,使LIFO效果不明顯 */ private volatile Semaphore mPoolSemaphore; private static ImageLoader mInstance; /** * 佇列的排程方式 * * @author
zhy * */
public enum Type { FIFO, LIFO } /** * 單例獲得該例項物件 * * @return */ public static ImageLoader getInstance() { if (mInstance == null) { synchronized (ImageLoader.class) { if (mInstance == null) { mInstance = new ImageLoader(1, Type.LIFO); } } } return mInstance; } private ImageLoader(int threadCount, Type type) { init(threadCount, type); } private void init(int threadCount, Type type) { // loop thread mPoolThread = new Thread() { @Override public void run() { Looper.prepare(); mPoolThreadHander = new Handler() { @Override public void handleMessage(Message msg) { mThreadPool.execute(getTask()); try { mPoolSemaphore.acquire(); } catch (InterruptedException e) { } } }; // 釋放一個訊號量 mSemaphore.release(); Looper.loop(); } }; mPoolThread.start(); // 獲取應用程式最大可用記憶體 int maxMemory = (int) Runtime.getRuntime().maxMemory(); int cacheSize = maxMemory / 4; mLruCache = new LruCache<String, Bitmap>(cacheSize) { @Override protected int sizeOf(String key, Bitmap value) { return value.getRowBytes() * value.getHeight(); }; }; mThreadPool = Executors.newFixedThreadPool(threadCount); mPoolSemaphore = new Semaphore(threadCount); mTasks = new LinkedList<Runnable>(); mType = type == null ? Type.LIFO : type; } /** * 載入圖片 * * @param path * @param imageView */ public void loadImage(final String path, final ImageView imageView) { // set tag imageView.setTag(path); // UI執行緒 if (mHandler == null) { mHandler = new Handler() { @Override public void handleMessage(Message msg) { ImgBeanHolder holder = (ImgBeanHolder) msg.obj; ImageView imageView = holder.imageView; Bitmap bm = holder.bitmap; String path = holder.path; if (imageView.getTag().toString().equals(path)) { imageView.setImageBitmap(bm); } } }; } Bitmap bm = getBitmapFromLruCache(path); if (bm != null) { ImgBeanHolder holder = new ImgBeanHolder(); holder.bitmap = bm; holder.imageView = imageView; holder.path = path; Message message = Message.obtain(); message.obj = holder; mHandler.sendMessage(message); } else { addTask(new Runnable() { @Override public void run() { ImageSize imageSize = getImageViewWidth(imageView); int reqWidth = imageSize.width; int reqHeight = imageSize.height; Bitmap bm = decodeSampledBitmapFromResource(path, reqWidth, reqHeight); addBitmapToLruCache(path, bm); ImgBeanHolder holder = new ImgBeanHolder(); holder.bitmap = getBitmapFromLruCache(path); holder.imageView = imageView; holder.path = path; Message message = Message.obtain(); message.obj = holder; // Log.e("TAG", "mHandler.sendMessage(message);"); mHandler.sendMessage(message); mPoolSemaphore.release(); } }); } } /** * 新增一個任務 * * @param runnable */ private synchronized void addTask(Runnable runnable) { try { // 請求訊號量,防止mPoolThreadHander為null if (mPoolThreadHander == null) mSemaphore.acquire(); } catch (InterruptedException e) { } mTasks.add(runnable); mPoolThreadHander.sendEmptyMessage(0x110); } /** * 取出一個任務 * * @return */ private synchronized Runnable getTask() { if (mType == Type.FIFO) { return mTasks.removeFirst(); } else if (mType == Type.LIFO) { return mTasks.removeLast(); } return null; } /** * 單例獲得該例項物件 * * @return */ public static ImageLoader getInstance(int threadCount, Type type) { if (mInstance == null) { synchronized (ImageLoader.class) { if (mInstance == null) { mInstance = new ImageLoader(threadCount, type); } } } return mInstance; } /** * 根據ImageView獲得適當的壓縮的寬和高 * * @param imageView * @return */ private ImageSize getImageViewWidth(ImageView imageView) { ImageSize imageSize = new ImageSize(); final DisplayMetrics displayMetrics = imageView.getContext() .getResources().getDisplayMetrics(); final LayoutParams params = imageView.getLayoutParams(); int width = params.width == LayoutParams.WRAP_CONTENT ? 0 : imageView .getWidth(); // Get actual image width if (width <= 0) width = params.width; // Get layout width parameter if (width <= 0) width = getImageViewFieldValue(imageView, "mMaxWidth"); // Check // maxWidth // parameter if (width <= 0) width = displayMetrics.widthPixels; int height = params.height == LayoutParams.WRAP_CONTENT ? 0 : imageView .getHeight(); // Get actual image height if (height <= 0) height = params.height; // Get layout height parameter if (height <= 0) height = getImageViewFieldValue(imageView, "mMaxHeight"); // Check // maxHeight // parameter if (height <= 0) height = displayMetrics.heightPixels; imageSize.width = width; imageSize.height = height; return imageSize; } /** * 從LruCache中獲取一張圖片,如果不存在就返回null。 */ private Bitmap getBitmapFromLruCache(String key) { return mLruCache.get(key); } /** * 往LruCache中新增一張圖片 * * @param key * @param bitmap */ private void addBitmapToLruCache(String key, Bitmap bitmap) { if (getBitmapFromLruCache(key) == null) { if (bitmap != null) mLruCache.put(key, bitmap); } } /** * 計算inSampleSize,用於壓縮圖片 * * @param options * @param reqWidth * @param reqHeight * @return */ private int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { // 源圖片的寬度 int width = options.outWidth; int height = options.outHeight; int inSampleSize = 1; if (width > reqWidth && height > reqHeight) { // 計算出實際寬度和目標寬度的比率 int widthRatio = Math.round((float) width / (float) reqWidth); int heightRatio = Math.round((float) width / (float) reqWidth); inSampleSize = Math.max(widthRatio, heightRatio); } return inSampleSize; } /** * 根據計算的inSampleSize,得到壓縮後圖片 * * @param pathName * @param reqWidth * @param reqHeight * @return */ private Bitmap decodeSampledBitmapFromResource(String pathName, int reqWidth, int reqHeight) { // 第一次解析將inJustDecodeBounds設定為true,來獲取圖片大小 final BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeFile(pathName, options); // 呼叫上面定義的方法計算inSampleSize值 options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); // 使用獲取到的inSampleSize值再次解析圖片 options.inJustDecodeBounds = false; Bitmap bitmap = BitmapFactory.decodeFile(pathName, options); return bitmap; } private class ImgBeanHolder { Bitmap bitmap; ImageView imageView; String path; } private class ImageSize { int width; int height; } /** * 反射獲得ImageView設定的最大寬度和高度 * * @param object * @param fieldName * @return */ private static int getImageViewFieldValue(Object object, String fieldName) { int value = 0; try { Field field = ImageView.class.getDeclaredField(fieldName); field.setAccessible(true); int fieldValue = (Integer) field.get(object); if (fieldValue > 0 && fieldValue < Integer.MAX_VALUE) { value = fieldValue; Log.e("TAG", value + ""); } } catch (Exception e) { } return value; } }

相關推薦

android 載入大量圖片

/** * 通過路徑獲取圖片,然後對圖片進行壓縮 存入快取中 更新介面 * * 通過將任務存入任務佇列中,通知輪詢執行緒從任務佇列中獲取任務的方法, * 來解決大量圖片載入過程中 滑動卡頓的問題(核心解決辦法) * */ public cl

android載入大量圖片記憶體溢位的三種解決辦法

方法一: 在從網路或本地載入圖片的時候,只加載縮圖。   /** * 按照路徑載入圖片 * @param path 圖片資源的存放路徑 * @param scalSize 縮小的倍數 * @return */ public s

Android相簿解決載入大量圖片問題

Android開發中載入相簿是很常用的功能,但相簿圖片過多正常載入會產生卡頓,即便使用執行緒非同步載入圖片卡頓問題依然得不到改善。 正常程式碼: public class AlbumAdapter extends ?{ @Override

安卓Viewpager載入大量圖片的時候

在viewpager中使用fragment,但是fragment中有大量的圖片,所以每次滑動viewpager的時候由於viewpager的預載入機制,它每次都載入兩頁的資料,所有有時候會卡頓或奔潰,這時候就需要解決 一開始我想的是取消預載入,但是第一太麻煩,

android-Picasso請求https載入網路圖片能顯示的解決方案

Picasso載入https的圖片載入不出來的解決方案 最近專案中有需求–要顯示https連結的圖片,但是配置好路徑後原生的Picasso死活沒法加載出圖片,最後在網上找到了如下的解決辦法 確認依賴 compile 'com.squareup.ok

android https載入WebView圖片顯示問題

在webview裡面載入https url的時候,如果裡面需要載入http的資源或者重定向的時候,webview會block頁面載入。這是Android 4.4以來google對安全機制的提升。 即當一個安全站點企圖載入來自一個不安全站點資源時WebView的行為,an

Android滑動列表載入大量圖片時候的優化

1 正在滾動的時候停止載入圖片2 滾動到頂部和底部的時候,載入圖片3 滑動速度降低到一定速率的時候,載入圖片4 到底部時候載入更多/** * Created by android on 2018/1/9. * * 快速滑動時候,停止載入圖片, 載入更多 */ publi

Android多個fragment懶載入的坑(

在Android開發中,有很多種情況都是viewpage+fragment左右滑動進行佈局的,例如下面的今日頭條 在今日頭條app上,我們可以看到,其頂部都是一欄的型別資料來源,可滑動,可聯動下面的viewpage裡的fragment,但是很多時候,viewpage+fragment中

RecyclerView載入圖片滑動

在專案上線,遇到了一個讓人很難受的問題,主介面滑動卡頓,有的手機情況情況還好,但是部分手機很糟糕,這個問題說實話讓人很蛋疼。 RecyclerView相比較listview與gridview具有更多的活動性。所以在這個介面我使用萬能重新整理控制元件XRefreshView來

Android GridView載入大量圖片時出現OOM情況

最近寫的一個應用涉及到使用GridView顯示圖片,當使用BaseAdapter傳統的的實現時,在真機上快速滾動時會出現OOM情況。 一個臨時性的解決方案就是改動圖片尺寸,減小記憶體。這種方法簡單卻不

Android RecyclerView載入時大圖

問題 由於載入圖片過大時,在配置低的手機裡滾動比較卡頓。這裡記錄下優化方法。 Scaling 是一種畫布操作,通常是由硬體加速的。圖片實際大小保持不變,它只不過在繪製時被放大或縮小。 Re

[UI列表]LoopScrollRect無限滑動

分享圖片 close 對比 部分 ets init ace fresh reward 應用場景 對於背包界面,排行榜列表,聊天消息,等有大量的UI列表的界面,常規做法是為每一條數據生成一個格子,在數據量越大的情況下,會生成越來越多的Gameobject,引起卡頓。 這篇文章

UCloud推出GlobalSSH,讓海外SSH訪問

nat 文件 管理 隧道 oot 獲得 華盛頓 png UC 近年來,隨著海外發展中國家的互聯網普及率逐步提升,加之BAT等互聯網巨頭對國內市場的壟斷,導致越來越多的中小企業迫於生存壓力開始選擇“出海”拓展業務。與此同時,出海對企業的IT基礎設施管理也帶來了諸多挑戰。 SS

Jquery實現拖拽div巢狀的iframe

css * {padding: 0;margin: 0;box-sizing: border-box;} .main {width: 1000px;height: 700px;position: absolute;left: 50%;top: 50%;margi

android滑動頁面時內容顯示

apicloud圖片快取用法html示例: <img class="lazy" data-src="{{=value.img}}" src="../image/placeholder.png" onload="loadImg(this);">

Android-載入圖片

在開發之中會遇到,載入小圖片沒問題,當載入大圖片的時候,記憶體溢位,為了解決這個問題,Android是提供了API 來處理優化圖片的方式解決,就是計算螢幕寬高 和 圖片寬高 的縮放比例,進行縮放,這樣就不會報記憶體溢位錯誤來    activity_image.xml 佈局檔案:

Android UI優化—從Android渲染原理理解UI

Android渲染機制 1、Android系統每隔16ms發出VSYNC訊號,觸發對UI進行渲染 2、渲染的過程是由CPU與GPU協作完成 如下圖: 為什麼是16ms? 1、人眼與大腦之間的協作無法感知超過60fps的畫面更新 2、1000/60hz,相當於16ms 什

Android載入超大圖片

Android載入超大圖片 一、目標 二、體驗地址 三、準備工作 1. 載入超大圖片 2. 獲取圖片大小 3. 使用者互動 四、subsampling-scale-image-vie

tcgames無需安卓模擬器,刺激戰場電腦玩手機遊戲怎麼設定高清流暢

tcgames電腦玩手機遊戲助手是一款無需安卓模擬器也可以在電腦上滑鼠鍵盤操作手遊的軟體!只要設定好了可以達到在電腦上玩手機遊戲高清流暢不卡頓的效果,並且可以匹配手遊服玩家。但是很多遊戲玩家不知道怎麼設定,特別是用tcgames在電腦上玩絕地求生:全軍出擊和絕地求生:刺激戰場

Androd載入圖片 崩 但是顯示黑屏的問題

發現問題 最近在做圖片載入時,在開啟硬體加速情況下,超大圖無法正常顯示(圖的長寬有一個大於9000),而且程式不會crash,只是圖片載入不出來,View顯示為黑色。通過檢視日誌,發現系統打印出了下面的內容: 1 W OpenGLRenderer( 4014): Bitmap too larg