Cách lười tải hình ảnh trong ListView trong Android


1931

Tôi đang sử dụng a ListViewđể hiển thị một số hình ảnh và chú thích liên quan đến những hình ảnh đó. Tôi đang nhận được những hình ảnh từ Internet. Có cách nào để lười tải hình ảnh để trong khi văn bản hiển thị, giao diện người dùng không bị chặn và hình ảnh được hiển thị khi chúng được tải xuống?

Tổng số hình ảnh không cố định.


10
Bạn có thể sử dụng AsyncImageView của GreenDroid . Chỉ cần gọi setUrl.
Pascal Dimassimo

7
Tôi đã sử dụng nó. Đó là một thực hiện tuyệt vời. Tin xấu rằng AsyncImageView là một phần của dự án GreenDroid lớn, giúp ứng dụng của bạn lớn hơn ngay cả trong trường hợp tất cả những gì bạn cần là AsyncImageView. Ngoài ra, dường như, dự án GreenDroid không được cập nhật kể từ năm 2011
borisstr

5
Bạn thậm chí có thể dùng thử thư viện này: Android-http-image-manager mà theo tôi là tốt nhất để tải hình ảnh không đồng bộ.
Ritesh Kumar Dubey

34
Chỉ cần sử dụng Picasso, nó sẽ tự làm tất cả. 'Picasso.with (yourContext) .load (img src / path / drawable here) .into (imageView tức là mục tiêu của bạn);' Đó là nó!
Anuj Sharma

6
hãy thử sử dụng: github.com/nostra13/Android-Universal-Image-Loader , thư viện này rất nhanh và hiệu quả cho việc lười tải và lưu trữ hình ảnh
kuggal patel

Câu trả lời:


1087

Đây là những gì tôi đã tạo để giữ hình ảnh mà ứng dụng của tôi hiện đang hiển thị. Xin lưu ý rằng đối tượng "Nhật ký" được sử dụng ở đây là trình bao bọc tùy chỉnh của tôi xung quanh lớp Nhật ký cuối cùng bên trong Android.

package com.wilson.android.library;

/*
 Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements.  See the NOTICE file
distributed with this work for additional information
regarding copyright ownership.  The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License.  You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied.  See the License for the
specific language governing permissions and limitations
under the License.
*/
import java.io.IOException;

public class DrawableManager {
    private final Map<String, Drawable> drawableMap;

    public DrawableManager() {
        drawableMap = new HashMap<String, Drawable>();
    }

    public Drawable fetchDrawable(String urlString) {
        if (drawableMap.containsKey(urlString)) {
            return drawableMap.get(urlString);
        }

        Log.d(this.getClass().getSimpleName(), "image url:" + urlString);
        try {
            InputStream is = fetch(urlString);
            Drawable drawable = Drawable.createFromStream(is, "src");


            if (drawable != null) {
                drawableMap.put(urlString, drawable);
                Log.d(this.getClass().getSimpleName(), "got a thumbnail drawable: " + drawable.getBounds() + ", "
                        + drawable.getIntrinsicHeight() + "," + drawable.getIntrinsicWidth() + ", "
                        + drawable.getMinimumHeight() + "," + drawable.getMinimumWidth());
            } else {
              Log.w(this.getClass().getSimpleName(), "could not get thumbnail");
            }

            return drawable;
        } catch (MalformedURLException e) {
            Log.e(this.getClass().getSimpleName(), "fetchDrawable failed", e);
            return null;
        } catch (IOException e) {
            Log.e(this.getClass().getSimpleName(), "fetchDrawable failed", e);
            return null;
        }
    }

    public void fetchDrawableOnThread(final String urlString, final ImageView imageView) {
        if (drawableMap.containsKey(urlString)) {
            imageView.setImageDrawable(drawableMap.get(urlString));
        }

        final Handler handler = new Handler() {
            @Override
            public void handleMessage(Message message) {
                imageView.setImageDrawable((Drawable) message.obj);
            }
        };

        Thread thread = new Thread() {
            @Override
            public void run() {
                //TODO : set imageView to a "pending" image
                Drawable drawable = fetchDrawable(urlString);
                Message message = handler.obtainMessage(1, drawable);
                handler.sendMessage(message);
            }
        };
        thread.start();
    }

    private InputStream fetch(String urlString) throws MalformedURLException, IOException {
        DefaultHttpClient httpClient = new DefaultHttpClient();
        HttpGet request = new HttpGet(urlString);
        HttpResponse response = httpClient.execute(request);
        return response.getEntity().getContent();
    }
}

104
Tôi nghĩ bạn nên sử dụng SoftReferences để chương trình của bạn sẽ không bao giờ gây ra OutOfMemoryException. Vì GC có thể xóa các phần mềm khi kích thước heap tăng lên ... bạn có thể quản lý thế hệ của riêng mình như sau vài giây, bạn có thể đưa hình ảnh của mình vào danh sách đó và trước khi tải, bạn nên kiểm tra xem nếu hình ảnh tồn tại thì đừng tải lại thay vì thu thập nó từ danh sách đó và cũng đưa nó trở lại danh sách softref của bạn và sau đó đôi khi bạn có thể lọc danh sách cứng của mình :)
AZ_

36
Dự án Google Shelves là một ví dụ tuyệt vời về cách họ đã thực hiện code.google.com/p/shelves
AZ_

12
Bạn không bỏ lỡ sự trở lại khi drawableMap chứa hình ảnh ... mà không bắt đầu chuỗi tìm nạp?
Karussell

5
Mã này có một số vấn đề. Trước tiên, bạn nên lưu trữ Drawables, điều đó sẽ gây rò rỉ bộ nhớ: stackoverflow.com/questions/7648740/ . Thứ hai, bộ nhớ cache không bao giờ bị xóa nên nó sẽ phát triển mãi mãi, đó là một rò rỉ bộ nhớ khác.
satur9nine

10
chưa có ai nghe về LRU Cache developer.android.com/training/displaying-bitmaps/
Kẻ

1025

Tôi đã tạo một bản demo đơn giản của một danh sách lười biếng (nằm ở GitHub) bằng hình ảnh.

Cách sử dụng cơ bản

ImageLoader imageLoader=new ImageLoader(context); ...
imageLoader.DisplayImage(url, imageView); 

Đừng quên thêm các quyền sau vào AndroidManifest.xml của bạn:

 <uses-permission android:name="android.permission.INTERNET"/>
 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> Please

chỉ tạo một phiên bản của ImageLoader và sử dụng lại tất cả xung quanh ứng dụng của bạn. Cách này lưu trữ hình ảnh sẽ hiệu quả hơn nhiều.

Nó có thể hữu ích cho ai đó. Nó tải hình ảnh trong chủ đề nền. Hình ảnh đang được lưu trữ trên thẻ SD và trong bộ nhớ. Việc thực hiện bộ đệm rất đơn giản và chỉ đủ cho bản demo. Tôi giải mã hình ảnh bằng inSampleSize để giảm mức tiêu thụ bộ nhớ. Tôi cũng cố gắng xử lý các quan điểm tái chế một cách chính xác.

Văn bản thay thế


7
Cảm ơn bạn, tôi đang sử dụng một phiên bản sửa đổi một chút mã của bạn ở hầu hết mọi nơi trong dự án của tôi: code.google.com/p/vimeoid/source/browse/apk/src/com/fedorvlasov/iêu
shaman.sir

3
Có ai đã xem mã của Gilles Debunne như một sự thay thế. Hai điểm khác biệt lớn mà tôi thấy là 1) trong bộ nhớ đệm so với thẻ SD và 2) việc sử dụng AsyncT task thay vì nhóm luồng. android-developers.blogspot.com/2010/07/ khăn
Richard

4
Có một lỗi, đôi khi nó bị bắn: 10-13 09: 58: 46.738: ERROR / AndroidR.78 (24250): Trình xử lý chưa được xử lý: thoát khỏi luồng chính do ngoại lệ chưa được mở 10-13 09: 58: 46.768: ERROR / AndroidR.78 (24250) : java.lang.ArrayIndexOutOfBoundException: Chỉ số mảng nằm ngoài phạm vi: 0 10-13 09: 58: 46.768: ERROR / AndroidR.78 (24250): tại java.util.Vector.elementAt (Vector.java:331) 10-13 09: 58: 46.768: ERROR / AndroidR.78 (24250): tại java.util.Vector.get (Vector.java:445) 10-13 09: 58: 46.768: ERROR / AndroidR.78 (24250): tại com.my.app.image .ImageLoader $ PhotosQueue.Clean (ImageLoader.java:91)
Mikooos

64
Tôi muốn thêm cho những người mới như tôi rằng nếu bạn muốn thêm mã này vào dự án của riêng mình, bạn phải thêm quyền truy cập bộ đệm ngoài trong tệp kê khai. Cảm ơn bạn
Adam

2
@BruceHill Không có photosQueue trong mã nguồn mới nhất. Bạn dường như đang sử dụng một số phiên bản rất cũ.
Fedor

552

Tôi khuyên dùng công cụ mã nguồn mở Universal Image Loader . Ban đầu nó dựa trên dự án LazyList của Fedor Vlasov và đã được cải thiện rất nhiều kể từ đó.

  • Tải hình ảnh đa luồng
  • Khả năng điều chỉnh rộng rãi cấu hình của ImageLoader (bộ thực thi luồng, bộ giải mã, bộ giải mã, bộ nhớ đệm và bộ đệm đĩa, tùy chọn hình ảnh hiển thị và các tùy chọn khác)
  • Khả năng lưu trữ hình ảnh trong bộ nhớ và / hoặc trên sysytem tệp của thiết bị (hoặc thẻ SD)
  • Khả năng "lắng nghe" quá trình tải
  • Khả năng tùy chỉnh mọi cuộc gọi hình ảnh hiển thị với các tùy chọn riêng biệt
  • Hỗ trợ widget
  • Hỗ trợ Android 2.0+


16
nếu bạn đang tìm kiếm mã "tải hình ảnh" tuyệt vời mà người tạo ra nó coi và duy trì như đứa con quý giá của mình (không chỉ là giải pháp một lần), bạn chỉ cần tìm thấy nó; big up Nostra
AndroidGecko

Công việc thực sự tuyệt vời, nhưng nó chậm một chút trong danh sách của tôi. Nếu bạn có thể nói về bản dựng tốt nhất 'Bản dựng ImageLoader' ... hoặc có thể đó là vì 'DisplayImageOptions'.
dinigo

Tôi yêu lưới này rất nhiều nhưng tôi không thể sử dụng nó cho hướng dẫn của mình. Tôi là người mới bắt đầu sử dụng Android. Tôi tạo ứng dụng về Gridview nhưng ứng dụng của tôi là targetSdkVersion 15 vì vậy tôi cần sử dụng Asynctask để xử lý trong luồng nền. Tôi đã từng sử dụng Gridview này nhưng nó không hoạt động. Làm thế nào tôi có thể sử dụng nó trong targetSdkVersion 15?
kongkea

Bạn có thể tạo câu hỏi riêng với thẻ [trình tải ảnh phổ quát]
nostra13

3
Sau khi đọc các tài liệu Android chính thức và cố gắng tự mình thực hiện công cụ này, tôi khá chắc chắn rằng thư viện này là kết thúc của tất cả tải hình ảnh. Không thể upvote đủ.
Lõi

159

Đa luồng cho hiệu suất , một hướng dẫn của Gilles Debunne.

Đây là từ Blog Nhà phát triển Android. Mã đề xuất sử dụng:

  • AsyncTasks.
  • Một kích thước cứng, giới hạn, FIFO cache ,.
  • Mềm mại, dễ dàng garbage collect nhớ cache .
  • Một giữ chỗ Drawable trong khi bạn tải xuống.

nhập mô tả hình ảnh ở đây


10
Nó hoạt động tốt trong 2.1 là tốt. Chỉ không sử dụng AndroidHttpClient.
Thomas Ahle

2
@ thomas-ahle Cảm ơn bạn, tôi đã thấy AndroidHttpClient đã mắc lỗi trong 2.1, vì nó được triển khai từ 2.2, nhưng không thực sự cố gắng tìm thứ gì khác để thay thế.
Adinia

4
@Adina Bạn nói đúng, tôi quên mất. Tuy nhiên, không có gì trong công thức không thể được thực hiện bằng một httpClient bình thường.
Thomas Ahle

Tôi đã nghe nói ở một số nơi, rằng Google không khuyến nghị các tài liệu tham khảo mềm vì kernel android rất mong muốn thu thập các tài liệu tham khảo này so với các phiên bản trước của hệ thống.
Muhammad Ahmed AbuTalib

109

Cập nhật: Lưu ý rằng câu trả lời này hiện không hiệu quả. Garbage Collector hoạt động mạnh mẽ trên SoftReference và WeakReference, vì vậy mã này KHÔNG phù hợp với các ứng dụng mới. (Thay vào đó, hãy thử các thư viện như Universal Image Loader được đề xuất trong các câu trả lời khác.)

Cảm ơn James về mã và Bao-Long đã gợi ý sử dụng SoftReference. Tôi đã triển khai các thay đổi SoftReference trên mã của James. Thật không may, SoftReferences khiến hình ảnh của tôi bị thu gom rác quá nhanh. Trong trường hợp của tôi, mọi thứ đều ổn nếu không có công cụ SoftReference, vì kích thước danh sách của tôi bị giới hạn và hình ảnh của tôi nhỏ.

Có một cuộc thảo luận từ một năm trước về SoftReferences trên các nhóm google: liên kết đến chuỗi . Là một giải pháp cho bộ sưu tập rác quá sớm, họ đề xuất khả năng cài đặt thủ công kích thước heap VM bằng cách sử dụng dalvik.system.VMR nb.setMinimumHeapSize (), điều này không hấp dẫn lắm đối với tôi.

public DrawableManager() {
    drawableMap = new HashMap<String, SoftReference<Drawable>>();
}

public Drawable fetchDrawable(String urlString) {
    SoftReference<Drawable> drawableRef = drawableMap.get(urlString);
    if (drawableRef != null) {
        Drawable drawable = drawableRef.get();
        if (drawable != null)
            return drawable;
        // Reference has expired so remove the key from drawableMap
        drawableMap.remove(urlString);
    }

    if (Constants.LOGGING) Log.d(this.getClass().getSimpleName(), "image url:" + urlString);
    try {
        InputStream is = fetch(urlString);
        Drawable drawable = Drawable.createFromStream(is, "src");
        drawableRef = new SoftReference<Drawable>(drawable);
        drawableMap.put(urlString, drawableRef);
        if (Constants.LOGGING) Log.d(this.getClass().getSimpleName(), "got a thumbnail drawable: " + drawable.getBounds() + ", "
                + drawable.getIntrinsicHeight() + "," + drawable.getIntrinsicWidth() + ", "
                + drawable.getMinimumHeight() + "," + drawable.getMinimumWidth());
        return drawableRef.get();
    } catch (MalformedURLException e) {
        if (Constants.LOGGING) Log.e(this.getClass().getSimpleName(), "fetchDrawable failed", e);
        return null;
    } catch (IOException e) {
        if (Constants.LOGGING) Log.e(this.getClass().getSimpleName(), "fetchDrawable failed", e);
        return null;
    }
}

public void fetchDrawableOnThread(final String urlString, final ImageView imageView) {
    SoftReference<Drawable> drawableRef = drawableMap.get(urlString);
    if (drawableRef != null) {
        Drawable drawable = drawableRef.get();
        if (drawable != null) {
            imageView.setImageDrawable(drawableRef.get());
            return;
        }
        // Reference has expired so remove the key from drawableMap
        drawableMap.remove(urlString);
    }

    final Handler handler = new Handler() {
        @Override
        public void handleMessage(Message message) {
            imageView.setImageDrawable((Drawable) message.obj);
        }
    };

    Thread thread = new Thread() {
        @Override
        public void run() {
            //TODO : set imageView to a "pending" image
            Drawable drawable = fetchDrawable(urlString);
            Message message = handler.obtainMessage(1, drawable);
            handler.sendMessage(message);
        }
    };
    thread.start();
}

3
bạn có thể tạo ra các thế hệ như thế hệ cứng và phát triển mềm. bạn có thể sửa bộ nhớ cache xóa thời gian sẽ xóa tất cả các hình ảnh không được truy cập trong 3 giây .. bạn có thể xem dự án kệ Google
AZ_

developer.android.com/reference/java/lang/ref/ ung SoftReference doc có một lưu ý về bộ nhớ đệm, xem phần "Tránh tham chiếu mềm cho bộ nhớ đệm". Hầu hết các ứng dụng nên sử dụng android.util.LruCache thay vì tham chiếu mềm.
vokilam

Tôi ngưỡng mộ mã của bạn nhưng bây giờ trong Android O / S mới có thu thập rác 'tích cực'. Giữ một tài liệu tham khảo yếu không có ý nghĩa gì với tôi.
j2emanue

@ j2emanue Bạn nói đúng, vì tôi đã cố gắng chỉ ra ở đầu câu trả lời của tôi, SoftReferences là rác được thu thập quá nhanh. Tôi sẽ cố gắng chỉnh sửa câu trả lời này để làm cho nó rõ ràng hơn nữa.
TalkLittle

97

Picasso

Sử dụng Thư viện Picasso của Jake Wharton. (Thư viện tải hình ảnh hoàn hảo tạo thành nhà phát triển ActionBarSherlock)

Một thư viện tải hình ảnh và bộ nhớ đệm mạnh mẽ cho Android.

Hình ảnh thêm bối cảnh rất cần thiết và sự tinh tế trực quan cho các ứng dụng Android. Picasso cho phép tải hình ảnh không rắc rối trong ứng dụng của bạn thường xuyên trong một dòng mã!

Picasso.with(context).load("http://i.imgur.com/DvpvklR.png").into(imageView);

Nhiều cạm bẫy phổ biến của việc tải hình ảnh trên Android được Picasso xử lý tự động:

Xử lý tái chế ImageView và hủy tải xuống trong một bộ chuyển đổi. Biến đổi hình ảnh phức tạp với việc sử dụng bộ nhớ tối thiểu. Bộ nhớ tự động và bộ nhớ đệm đĩa.

Thư viện của Picasso Jake Wharton

Lướt

Glide là một khung quản lý phương tiện mã nguồn mở nhanh và hiệu quả dành cho Android, bao bọc giải mã phương tiện, bộ nhớ đệm và bộ nhớ cache và tài nguyên tập hợp thành một giao diện đơn giản và dễ sử dụng.

Glide hỗ trợ tìm nạp, giải mã và hiển thị ảnh tĩnh video, hình ảnh và GIF động. Glide bao gồm một api linh hoạt cho phép các nhà phát triển cắm vào hầu hết mọi ngăn xếp mạng. Theo mặc định, Glide sử dụng ngăn xếp dựa trên httpUrlConnection tùy chỉnh, nhưng cũng bao gồm các thư viện tiện ích cắm vào dự án Volley của Google hoặc thư viện OkHttp của Square.

Glide.with(this).load("http://goo.gl/h8qOq7").into(imageView);

Trọng tâm chính của Glide là làm cho việc cuộn bất kỳ loại danh sách hình ảnh nào mượt mà và nhanh nhất có thể, nhưng Glide cũng hiệu quả đối với hầu hết mọi trường hợp bạn cần tìm nạp, thay đổi kích thước và hiển thị hình ảnh từ xa.

Thư viện tải hình ảnh Glide

Fresco bởi Facebook

Fresco là một hệ thống mạnh mẽ để hiển thị hình ảnh trong các ứng dụng Android.

Fresco đảm nhiệm việc tải và hiển thị hình ảnh, vì vậy bạn không cần phải làm vậy. Nó sẽ tải hình ảnh từ mạng, bộ nhớ cục bộ hoặc tài nguyên cục bộ và hiển thị một trình giữ chỗ cho đến khi hình ảnh được gửi đến. Nó có hai cấp độ bộ đệm; một trong bộ nhớ và một trong bộ nhớ trong.

Github Fresco

Trong Android 4.x trở xuống, Fresco đặt hình ảnh vào một vùng đặc biệt của bộ nhớ Android. Điều này cho phép ứng dụng của bạn chạy nhanh hơn - và chịu đựng OutOfMemoryError đáng sợ ít thường xuyên hơn.

Tài liệu Fresco


Picasso là một thư viện được phát triển bởi Square
LordRaydenMK

83

Trình tải hiệu suất cao - sau khi kiểm tra các phương pháp được đề xuất ở đây, tôi đã sử dụng giải pháp của Ben với một số thay đổi -

  1. Tôi nhận ra rằng làm việc với drawables nhanh hơn với bitmap nên tôi sử dụng drawables thay thế

  2. Sử dụng SoftReference là rất tốt, nhưng nó làm cho hình ảnh được lưu trữ bị xóa quá thường xuyên, vì vậy tôi đã thêm một danh sách Liên kết chứa các tham chiếu hình ảnh, ngăn hình ảnh bị xóa, cho đến khi nó đạt đến kích thước được xác định trước

  3. Để mở InputStream, tôi đã sử dụng java.net.URLC Connectection cho phép tôi sử dụng bộ đệm web (trước tiên bạn cần đặt bộ đệm phản hồi, nhưng đó là một câu chuyện khác)

Mã của tôi:

import java.util.Map; 
import java.util.HashMap; 
import java.util.LinkedList; 
import java.util.Collections; 
import java.util.WeakHashMap; 
import java.lang.ref.SoftReference; 
import java.util.concurrent.Executors; 
import java.util.concurrent.ExecutorService; 
import android.graphics.drawable.Drawable;
import android.widget.ImageView;
import android.os.Handler;
import android.os.Message;
import java.io.InputStream;
import java.net.MalformedURLException; 
import java.io.IOException; 
import java.net.URL;
import java.net.URLConnection;

public class DrawableBackgroundDownloader {    

private final Map<String, SoftReference<Drawable>> mCache = new HashMap<String, SoftReference<Drawable>>();   
private final LinkedList <Drawable> mChacheController = new LinkedList <Drawable> ();
private ExecutorService mThreadPool;  
private final Map<ImageView, String> mImageViews = Collections.synchronizedMap(new WeakHashMap<ImageView, String>());  

public static int MAX_CACHE_SIZE = 80; 
public int THREAD_POOL_SIZE = 3;

/**
 * Constructor
 */
public DrawableBackgroundDownloader() {  
    mThreadPool = Executors.newFixedThreadPool(THREAD_POOL_SIZE);  
}  


/**
 * Clears all instance data and stops running threads
 */
public void Reset() {
    ExecutorService oldThreadPool = mThreadPool;
    mThreadPool = Executors.newFixedThreadPool(THREAD_POOL_SIZE);
    oldThreadPool.shutdownNow();

    mChacheController.clear();
    mCache.clear();
    mImageViews.clear();
}  

public void loadDrawable(final String url, final ImageView imageView,Drawable placeholder) {  
    mImageViews.put(imageView, url);  
    Drawable drawable = getDrawableFromCache(url);  

    // check in UI thread, so no concurrency issues  
    if (drawable != null) {  
        //Log.d(null, "Item loaded from mCache: " + url);  
        imageView.setImageDrawable(drawable);  
    } else {  
        imageView.setImageDrawable(placeholder);  
        queueJob(url, imageView, placeholder);  
    }  
} 


private Drawable getDrawableFromCache(String url) {  
    if (mCache.containsKey(url)) {  
        return mCache.get(url).get();  
    }  

    return null;  
}

private synchronized void putDrawableInCache(String url,Drawable drawable) {  
    int chacheControllerSize = mChacheController.size();
    if (chacheControllerSize > MAX_CACHE_SIZE) 
        mChacheController.subList(0, MAX_CACHE_SIZE/2).clear();

    mChacheController.addLast(drawable);
    mCache.put(url, new SoftReference<Drawable>(drawable));

}  

private void queueJob(final String url, final ImageView imageView,final Drawable placeholder) {  
    /* Create handler in UI thread. */  
    final Handler handler = new Handler() {  
        @Override  
        public void handleMessage(Message msg) {  
            String tag = mImageViews.get(imageView);  
            if (tag != null && tag.equals(url)) {
                if (imageView.isShown())
                    if (msg.obj != null) {
                        imageView.setImageDrawable((Drawable) msg.obj);  
                    } else {  
                        imageView.setImageDrawable(placeholder);  
                        //Log.d(null, "fail " + url);  
                    } 
            }  
        }  
    };  

    mThreadPool.submit(new Runnable() {  
        @Override  
        public void run() {  
            final Drawable bmp = downloadDrawable(url);
            // if the view is not visible anymore, the image will be ready for next time in cache
            if (imageView.isShown())
            {
                Message message = Message.obtain();  
                message.obj = bmp;
                //Log.d(null, "Item downloaded: " + url);  

                handler.sendMessage(message);
            }
        }  
    });  
}  



private Drawable downloadDrawable(String url) {  
    try {  
        InputStream is = getInputStream(url);

        Drawable drawable = Drawable.createFromStream(is, url);
        putDrawableInCache(url,drawable);  
        return drawable;  

    } catch (MalformedURLException e) {  
        e.printStackTrace();  
    } catch (IOException e) {  
        e.printStackTrace();  
    }  

    return null;  
}  


private InputStream getInputStream(String urlString) throws MalformedURLException, IOException {
    URL url = new URL(urlString);
    URLConnection connection;
    connection = url.openConnection();
    connection.setUseCaches(true); 
    connection.connect();
    InputStream response = connection.getInputStream();

    return response;
}
}

Hoạt động tuyệt vời! BTW có một lỗi đánh máy trong tên lớp.
Mullins

5
Trong trường hợp nó tiết kiệm thời gian cho người khác: import java.util.Map; import java.util.HashMap; import java.util.LinkedList; import java.util.Collections; import java.util.WeakHashMap; import java.lang.ref.SoftReference; import java.util.concurrent.Executors; import java.util.concurrent.ExecutorService; import android.graphics.drawable.Drawable; import android.widget.ImageView; import android.os.Handler; import android.os.Message; import java.io.InputStream; import java.net.MalformedURLException; import java.io.IOException; import java.net.URL; import java.net.URLConnection;
Michael Reed

Cảm ơn rất nhiều, đây là một thực hiện tốt đẹp. Tôi cũng đặt một trình giữ chỗ khác khi tải có thể tải được để người dùng có thể nhận được một số phản hồi.
Juan Hernandez

Ngoài ra, tôi nghĩ tốt hơn là sử dụng hàng đợi LIFO trong tệp thực thi (mThreadPool) thay vì FIFO mặc định để các hình ảnh cuối cùng được yêu cầu (có thể là những hình ảnh hiển thị) được tải trước tiên. Xem stackoverflow.com/questions/4620061/how-to-create-lifo-executor
Juan Hernandez

9
@MichaelReed, trong trường hợp bạn là người dùng Eclipse, tôi khuyên bạn nên sử dụng Ctrl-Shift-O (đó là chữ O, không phải số 0). Nó tự động hóa quá trình thêm hàng nhập khẩu và tổ chức chúng cho bạn. Nếu bạn đang dùng Mac, hãy sử dụng Command-Shift-O thay thế.
SilithCrowe

78

Tôi đã theo dõi chương trình đào tạo Android này và tôi nghĩ rằng nó thực hiện công việc tuyệt vời khi tải xuống hình ảnh mà không chặn giao diện người dùng chính. Nó cũng xử lý bộ nhớ đệm và xử lý việc cuộn qua nhiều hình ảnh: Tải Bitmap lớn một cách hiệu quả


Tôi xin lỗi, tôi chỉ chỉ một lớp duy nhất cho ứng dụng Google IO (và tôi đã quá muộn để chỉnh sửa). Bạn thực sự nên nghiên cứu tất cả các lớp tiện ích tải hình ảnh và bộ đệm của họ mà bạn có thể tìm thấy trong cùng một gói với lớp bộ đệm .
mkuech

Có ai khuyên bạn nên lấy các tệp DiskLruCache, Image * .java từ thư mục tiện ích của ứng dụng iosched để giúp xử lý tải / lưu trữ hình ảnh cho chế độ xem danh sách không? Ý tôi là nó chắc chắn đáng để làm theo các hướng dẫn dành cho Nhà phát triển trực tuyến về chủ đề này, nhưng các lớp này (từ iosched) đi xa hơn một chút với mẫu.
Gautam

65

1. Picasso cho phép tải hình ảnh không rắc rối trong ứng dụng của bạn thường xuyên trong một dòng mã!

Sử dụng lớp:

implementation 'com.squareup.picasso:picasso:2.71828'

Chỉ cần một dòng mã!

Picasso.get().load("http://i.imgur.com/DvpvklR.png").into(imageView);

2. Glide Một thư viện tải và lưu trữ hình ảnh cho Android tập trung vào việc cuộn mượt mà

Sử dụng lớp:

repositories {
  mavenCentral() 
  google()
}

dependencies {
   implementation 'com.github.bumptech.glide:glide:4.7.1'
   annotationProcessor 'com.github.bumptech.glide:compiler:4.7.1'
}

// Để xem đơn giản:

  Glide.with(this).load("http://i.imgur.com/DvpvklR.png").into(imageView);

3. fresco là một hệ thống mạnh mẽ để hiển thị hình ảnh trong các ứng dụng Android.Fresco đảm nhiệm việc tải và hiển thị hình ảnh, vì vậy bạn không cần phải làm vậy.

Bắt đầu với Fresco


Hướng dẫn này có thể giúp bạn nhiều hơn cho PICASOO: - androidtutorialshub.com/... và GLIDE: - androidtutorialshub.com/...
Lalit Vasan

52

Tôi đã viết một hướng dẫn giải thích làm thế nào để tải hình ảnh lười biếng trong một listview. Tôi đi vào một số chi tiết về các vấn đề tái chế và đồng thời. Tôi cũng sử dụng một nhóm chủ đề cố định để ngăn chặn sinh ra rất nhiều chủ đề.

Tải hình ảnh lười biếng trong Hướng dẫn Listview


41

Cách tôi làm là bằng cách khởi chạy một chuỗi để tải xuống các hình ảnh trong nền và trao cho nó một cuộc gọi lại cho mỗi mục danh sách. Khi một hình ảnh được tải xuống xong, nó gọi lại cuộc gọi để cập nhật khung nhìn cho mục danh sách.

Phương pháp này không hoạt động tốt khi bạn tái chế lượt xem.


sử dụng một chủ đề cho mỗi hình ảnh là cách tiếp cận tôi cũng sử dụng. Nếu bạn tách mô hình của mình khỏi chế độ xem, bạn có thể duy trì mô hình bên ngoài Hoạt động (như trong lớp 'ứng dụng' của bạn) để giữ cho chúng được lưu trữ. Coi chừng hết tài nguyên nếu bạn có nhiều hình ảnh.
James A Wilson

bạn có thể vui lòng giải thích. Tôi mới phát triển Android. Cảm ơn về các mẹo mặc dù
mấtInTransit

14
Bắt đầu một chủ đề mới cho mỗi hình ảnh không phải là một giải pháp hiệu quả. Bạn có thể kết thúc với rất nhiều luồng trong bộ nhớ và đóng băng UI.
Fedor

Fedor, đồng ý, tôi thường sử dụng hàng đợi và nhóm luồng, đó là cách tốt nhất để đi imo.
jasonhudgins

32

Tôi chỉ muốn thêm một ví dụ hay nữa, Bộ điều hợp XML . Vì nó được Google sử dụng và tôi cũng đang sử dụng logic tương tự để tránh lỗi OutOfMemory.

Về cơ bản , ImageD Downloader này là câu trả lời của bạn (vì nó đáp ứng hầu hết các yêu cầu của bạn). Một số bạn cũng có thể thực hiện trong đó.


2
Lớp ImageDoader không được tuân thủ: xem giải pháp bên dưới code.google.com/p/parley-android-nextgen/issues/detail?id=1
Sam

29

Đây là một vấn đề phổ biến trên Android đã được nhiều người giải quyết bằng nhiều cách. Theo tôi, giải pháp tốt nhất tôi từng thấy là thư viện tương đối mới có tên Picasso . Dưới đây là những điểm nổi bật:

  • Nguồn mở, nhưng được dẫn dắt bởi sự nổi tiếng Jake Whartoncủa ActionBarSherlock .
  • Tải hình ảnh không đồng bộ từ tài nguyên mạng hoặc ứng dụng bằng một dòng mã
  • Tự động ListView phát hiện
  • Bộ nhớ đệm đĩa và bộ nhớ tự động
  • Có thể thực hiện các biến đổi tùy chỉnh
  • Rất nhiều tùy chọn cấu hình
  • API siêu đơn giản
  • Cập nhật thường xuyên

29

Tôi đã sử dụng NetworkImageView từ Thư viện Volley Android mới com.android.volley.toolbox.NetworkImageViewvà có vẻ như nó đang hoạt động khá tốt. Rõ ràng, đây là cùng một quan điểm được sử dụng trong Google Play và các ứng dụng mới khác của Google. Chắc chắn giá trị kiểm tra.


1
Tôi nghĩ rằng đây là giải pháp tốt nhất - các câu trả lời khác rất cũ - bóng chuyền thực sự rất nhanh và kết hợp với jarth warthons Disclrucache, đây là một giải pháp hoàn hảo - tôi đã thử rất nhiều giải pháp khác nhưng không phải là ổn định và nhanh như bóng chuyền
Alexander Sidikov Pfeif

26

Vâng, thời gian tải hình ảnh từ Internet có nhiều giải pháp. Bạn cũng có thể sử dụng thư viện Android-Query . Nó sẽ cung cấp cho bạn tất cả các hoạt động cần thiết. Hãy chắc chắn những gì bạn muốn làm và đọc trang wiki thư viện. Và giải quyết hạn chế tải hình ảnh.

Đây là mã của tôi:

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    View v = convertView;
    if (v == null) {
        LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        v = vi.inflate(R.layout.row, null);
    }

    ImageView imageview = (ImageView) v.findViewById(R.id.icon);
    AQuery aq = new AQuery(convertView);

    String imageUrl = "http://www.vikispot.com/z/images/vikispot/android-w.png";

    aq.id(imageview).progress(this).image(imageUrl, true, true, 0, 0, new BitmapAjaxCallback() {
        @Override
        public void callback(String url, ImageView iv, Bitmap bm, AjaxStatus status) {
            iv.setImageBitmap(bm);
        }
    ));

    return v;
}

Nó sẽ được giải quyết vấn đề tải lười biếng của bạn.


Làm việc tốt với tôi, nhưng cần một tệp Jar để đưa vào dự án của bạn. Bạn có thể tải xuống tệp JAR đó từ đây AQuery androidAQuery = new AQuery (this); liên kết là: code.google.com/archive/p/android-query/doads
Selim Raza

25

Tôi nghĩ vấn đề này rất phổ biến đối với các nhà phát triển Android và có rất nhiều thư viện như vậy tuyên bố sẽ giải quyết vấn đề này, nhưng chỉ có một vài trong số họ dường như được đánh dấu. AQuery là một trong những thư viện như vậy, nhưng nó tốt hơn hầu hết chúng trong tất cả các khía cạnh và đáng để thử.


22

Bạn phải thử Universal Loader này là tốt nhất. Tôi đang sử dụng điều này sau khi thực hiện nhiều RnD khi lười tải.

Trình tải hình ảnh phổ quát

Đặc trưng

  • Tải hình ảnh đa luồng (không đồng bộ hoặc đồng bộ hóa)
  • Tùy chỉnh rộng rãi cấu hình của ImageLoader (người thực hiện luồng, trình tải xuống, bộ giải mã, bộ nhớ và bộ đệm đĩa, tùy chọn hình ảnh hiển thị, v.v.)
  • Nhiều tùy chọn tùy chỉnh cho mọi cuộc gọi hình ảnh hiển thị (sơ khai hình ảnh, chuyển đổi bộ đệm, tùy chọn giải mã, xử lý và hiển thị Bitmap, v.v.)
  • Bộ nhớ đệm hình ảnh trong bộ nhớ và / hoặc trên đĩa (hệ thống tệp của thiết bị hoặc thẻ SD)
  • Nghe quá trình tải (bao gồm cả tiến trình tải xuống)

Hỗ trợ Android 2.0+

nhập mô tả hình ảnh ở đây


20

Có một cái nhìn về Shutterorms , SDWebImage nhẹ Applidium của (một thư viện đẹp trên iOS) cổng cho Android. Nó hỗ trợ bộ nhớ đệm không đồng bộ, lưu trữ các URL không thành công, xử lý đồng thời tốt và các lớp con hữu ích được bao gồm.

Yêu cầu kéo (và báo cáo lỗi) cũng được chào đón!


16

DroidPartsImageFetcher yêu cầu cấu hình bằng 0 để bắt đầu.

  • Sử dụng bộ đệm & bộ nhớ tối thiểu được sử dụng gần đây (LRU).
  • Giải mã hiệu quả hình ảnh.
  • Hỗ trợ sửa đổi ảnh bitmap trong luồng nền.
  • Có phai chéo đơn giản.
  • Có hình ảnh tiến trình tải lại cuộc gọi.

Clone DroidPartsGram cho một ví dụ:

Nhập mô tả hình ảnh ở đây


Xin chào, tôi đã xem xét các ví dụ về mã nhưng tôi gặp vấn đề khi sử dụng ImageFetcher với ArrayAd CHƯƠNG, bạn có phiền khi xem câu hỏi của tôi không? stackoverflow.com/questions/21089147/ cảm ơn =]
masha

16

Chỉ là một mẹo nhanh cho một người thiếu quyết đoán về việc sử dụng thư viện nào cho hình ảnh tải lười biếng:

Có bốn cách cơ bản.

  1. DIY => Không phải là giải pháp tốt nhất nhưng cho một vài hình ảnh và nếu bạn muốn đi mà không gặp rắc rối khi sử dụng các thư viện khác

  2. Thư viện tải nhanh của Volley => Từ những người ở Android. Nó là tốt đẹp và tất cả mọi thứ nhưng là tài liệu kém và do đó là một vấn đề để sử dụng.

  3. Picasso: Một giải pháp đơn giản chỉ hoạt động, thậm chí bạn có thể chỉ định kích thước hình ảnh chính xác mà bạn muốn mang vào. Nó rất đơn giản để sử dụng nhưng có thể không "hiệu quả" cho các ứng dụng phải xử lý số lượng hình ảnh khiêm tốn.

  4. UIL: Cách tốt nhất để tải hình ảnh lười biếng. Bạn có thể lưu trữ hình ảnh (tất nhiên bạn cần có sự cho phép), khởi tạo trình tải một lần, sau đó hoàn thành công việc của bạn. Thư viện tải hình ảnh không đồng bộ trưởng thành nhất mà tôi từng thấy cho đến nay.


15

Novoda cũng có một thư viện tải hình ảnh lười biếng tuyệt vời và nhiều ứng dụng như Songkick, Podio, SecretDJ và ImageSearch sử dụng thư viện của họ.

Thư viện của họ được lưu trữ ở đây trên Github và họ cũng có một trình theo dõi các vấn đề khá tích cực . Dự án của họ dường như cũng khá tích cực, với hơn 300 cam kết tại thời điểm viết bài trả lời này.


1
Trên thực tế Novoda là một thư viện tuyệt vời nhưng ... đôi khi bạn không cần một thư viện lớn và chỉ là một cách tiếp cận đơn giản cho giải pháp. Đó là lý do tại sao LazyList trong Github rất tốt, nếu ứng dụng của bạn chỉ hiển thị hình ảnh trong listView và không phải là tính năng chính của ứng dụng của bạn, chỉ là một hoạt động khác tôi muốn sử dụng một cái gì đó nhẹ hơn. Nếu không, nếu bạn biết rằng bạn sẽ phải sử dụng thường xuyên và là một phần cốt lõi, hãy thử Novoda.
Nicolas Jafelle

13

Kiểm tra ngã ba LazyList của tôi . Về cơ bản, tôi cải thiện LazyList bằng cách trì hoãn cuộc gọi của ImageView và tạo hai phương thức:

  1. Khi bạn cần đặt một cái gì đó như "Đang tải hình ảnh ..."
  2. Khi bạn cần hiển thị hình ảnh tải về.

Tôi cũng đã cải thiện ImageLoader bằng cách triển khai một singleton trong đối tượng này.


12

Nếu bạn muốn hiển thị bố cục Shimmer như Facebook, có một thư viện facebook chính thức cho điều đó. FaceBook lung linh Android

Nó chăm sóc tất cả mọi thứ, Bạn chỉ cần đặt mã thiết kế mong muốn của bạn theo cách lồng nhau trong khung lung linh. Đây là một mã mẫu.

<com.facebook.shimmer.ShimmerFrameLayout
     android:id=“@+id/shimmer_view_container”
     android:layout_width=“wrap_content”
     android:layout_height="wrap_content"
     shimmer:duration="1000">

 <here will be your content to display />

</com.facebook.shimmer.ShimmerFrameLayout>

Và đây là mã java cho nó.

ShimmerFrameLayout shimmerContainer = (ShimmerFrameLayout) findViewById(R.id.shimmer_view_container);
shimmerContainer.startShimmerAnimation();

Thêm phụ thuộc này trong tập tin lớp của bạn.

implementation 'com.facebook.shimmer:shimmer:0.1.0@aar'

Đây là cách nó trông như thế nào.Ảnh chụp màn hình Android lung linh


11

Tất cả các mã ở trên đều có giá trị riêng nhưng với kinh nghiệm cá nhân của tôi, hãy thử dùng Picasso.

Picasso là một thư viện dành riêng cho mục đích này, trên thực tế, nó sẽ tự động quản lý bộ đệm và tất cả các hoạt động mạng khác. Bạn sẽ phải thêm thư viện trong dự án của mình và chỉ cần viết một dòng mã để tải hình ảnh từ URL từ xa.

Vui lòng truy cập tại đây: http://code.tutsplus.com/tutorials/android-sdk-usiness-with-picasso--cms-22149


9

Sử dụng thư viện trượt. Nó làm việc cho tôi và cũng sẽ làm việc cho mã của bạn. Nó cũng hoạt động cho cả hình ảnh cũng như gifs.

ImageView imageView = (ImageView) findViewById(R.id.test_image); 
    GlideDrawableImageViewTarget imagePreview = new GlideDrawableImageViewTarget(imageView);
    Glide
            .with(this)
            .load(url)
            .listener(new RequestListener<String, GlideDrawable>() {
                @Override
                public boolean onException(Exception e, String model, Target<GlideDrawable> target, boolean isFirstResource) {                       
                    return false;
                }

                @Override
                public boolean onResourceReady(GlideDrawable resource, String model, Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) {
                    return false;
                }
            })
            .into(imagePreview);
}

7

Tôi có thể đề xuất một cách khác hoạt động như bùa mê: Truy vấn Android.

Bạn có thể tải xuống tệp JAR đó từ đây

AQuery androidAQuery = new AQuery(this);

Ví dụ:

androidAQuery.id(YOUR IMAGEVIEW).image(YOUR IMAGE TO LOAD, true, true, getDeviceWidth(), ANY DEFAULT IMAGE YOU WANT TO SHOW);

Nó rất nhanh và chính xác, và bằng cách sử dụng này, bạn có thể tìm thấy nhiều tính năng khác như hoạt hình khi tải, nhận bitmap (nếu cần), v.v.




4
public class ImageDownloader {

Map<String, Bitmap> imageCache;

public ImageDownloader() {
    imageCache = new HashMap<String, Bitmap>();

}

// download function
public void download(String url, ImageView imageView) {
    if (cancelPotentialDownload(url, imageView)) {

        // Caching code right here
        String filename = String.valueOf(url.hashCode());
        File f = new File(getCacheDirectory(imageView.getContext()),
                filename);

        // Is the bitmap in our memory cache?
        Bitmap bitmap = null;

        bitmap = (Bitmap) imageCache.get(f.getPath());

        if (bitmap == null) {

            bitmap = BitmapFactory.decodeFile(f.getPath());

            if (bitmap != null) {
                imageCache.put(f.getPath(), bitmap);
            }

        }
        // No? download it
        if (bitmap == null) {
            try {
                BitmapDownloaderTask task = new BitmapDownloaderTask(
                        imageView);
                DownloadedDrawable downloadedDrawable = new DownloadedDrawable(
                        task);
                imageView.setImageDrawable(downloadedDrawable);
                task.execute(url);
            } catch (Exception e) {
                Log.e("Error==>", e.toString());
            }

        } else {
            // Yes? set the image
            imageView.setImageBitmap(bitmap);
        }
    }
}

// cancel a download (internal only)
private static boolean cancelPotentialDownload(String url,
        ImageView imageView) {
    BitmapDownloaderTask bitmapDownloaderTask = getBitmapDownloaderTask(imageView);

    if (bitmapDownloaderTask != null) {
        String bitmapUrl = bitmapDownloaderTask.url;
        if ((bitmapUrl == null) || (!bitmapUrl.equals(url))) {
            bitmapDownloaderTask.cancel(true);
        } else {
            // The same URL is already being downloaded.
            return false;
        }
    }
    return true;
}

// gets an existing download if one exists for the imageview
private static BitmapDownloaderTask getBitmapDownloaderTask(
        ImageView imageView) {
    if (imageView != null) {
        Drawable drawable = imageView.getDrawable();
        if (drawable instanceof DownloadedDrawable) {
            DownloadedDrawable downloadedDrawable = (DownloadedDrawable) drawable;
            return downloadedDrawable.getBitmapDownloaderTask();
        }
    }
    return null;
}

// our caching functions
// Find the dir to save cached images
private static File getCacheDirectory(Context context) {
    String sdState = android.os.Environment.getExternalStorageState();
    File cacheDir;

    if (sdState.equals(android.os.Environment.MEDIA_MOUNTED)) {
        File sdDir = android.os.Environment.getExternalStorageDirectory();

        // TODO : Change your diretcory here
        cacheDir = new File(sdDir, "data/ToDo/images");
    } else
        cacheDir = context.getCacheDir();

    if (!cacheDir.exists())
        cacheDir.mkdirs();
    return cacheDir;
}

private void writeFile(Bitmap bmp, File f) {
    FileOutputStream out = null;

    try {
        out = new FileOutputStream(f);
        bmp.compress(Bitmap.CompressFormat.PNG, 80, out);
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        try {
            if (out != null)
                out.close();
        } catch (Exception ex) {
        }
    }
}

// download asynctask
public class BitmapDownloaderTask extends AsyncTask<String, Void, Bitmap> {
    private String url;
    private final WeakReference<ImageView> imageViewReference;

    public BitmapDownloaderTask(ImageView imageView) {
        imageViewReference = new WeakReference<ImageView>(imageView);
    }

    @Override
    // Actual download method, run in the task thread
    protected Bitmap doInBackground(String... params) {
        // params comes from the execute() call: params[0] is the url.
        url = (String) params[0];
        return downloadBitmap(params[0]);
    }

    @Override
    // Once the image is downloaded, associates it to the imageView
    protected void onPostExecute(Bitmap bitmap) {
        if (isCancelled()) {
            bitmap = null;
        }

        if (imageViewReference != null) {
            ImageView imageView = imageViewReference.get();
            BitmapDownloaderTask bitmapDownloaderTask = getBitmapDownloaderTask(imageView);
            // Change bitmap only if this process is still associated with
            // it
            if (this == bitmapDownloaderTask) {
                imageView.setImageBitmap(bitmap);

                // cache the image

                String filename = String.valueOf(url.hashCode());
                File f = new File(
                        getCacheDirectory(imageView.getContext()), filename);

                imageCache.put(f.getPath(), bitmap);

                writeFile(bitmap, f);
            }
        }
    }

}

static class DownloadedDrawable extends ColorDrawable {
    private final WeakReference<BitmapDownloaderTask> bitmapDownloaderTaskReference;

    public DownloadedDrawable(BitmapDownloaderTask bitmapDownloaderTask) {
        super(Color.WHITE);
        bitmapDownloaderTaskReference = new WeakReference<BitmapDownloaderTask>(
                bitmapDownloaderTask);
    }

    public BitmapDownloaderTask getBitmapDownloaderTask() {
        return bitmapDownloaderTaskReference.get();
    }
}

// the actual download code
static Bitmap downloadBitmap(String url) {
    HttpParams params = new BasicHttpParams();
    params.setParameter(CoreProtocolPNames.PROTOCOL_VERSION,
            HttpVersion.HTTP_1_1);
    HttpClient client = new DefaultHttpClient(params);
    final HttpGet getRequest = new HttpGet(url);

    try {
        HttpResponse response = client.execute(getRequest);
        final int statusCode = response.getStatusLine().getStatusCode();
        if (statusCode != HttpStatus.SC_OK) {
            Log.w("ImageDownloader", "Error " + statusCode
                    + " while retrieving bitmap from " + url);
            return null;
        }

        final HttpEntity entity = response.getEntity();
        if (entity != null) {
            InputStream inputStream = null;
            try {
                inputStream = entity.getContent();
                final Bitmap bitmap = BitmapFactory
                        .decodeStream(inputStream);
                return bitmap;
            } finally {
                if (inputStream != null) {
                    inputStream.close();
                }
                entity.consumeContent();
            }
        }
    } catch (Exception e) {
        // Could provide a more explicit error message for IOException or
        // IllegalStateException
        getRequest.abort();
        Log.w("ImageDownloader", "Error while retrieving bitmap from "
                + url + e.toString());
    } finally {
        if (client != null) {
            // client.close();
        }
    }
    return null;
 }
}

4

Tôi đã có vấn đề này và thực hiện lruCache. Tôi tin rằng bạn cần API 12 trở lên hoặc sử dụng thư viện v4 compatiblity. lurCache là bộ nhớ nhanh, nhưng nó cũng có ngân sách, vì vậy nếu bạn lo lắng về việc bạn có thể sử dụng một đĩa đệm ... Tất cả đều được mô tả trong Bộ nhớ cache Bitmap .

Bây giờ tôi sẽ cung cấp triển khai của mình, đó là một đơn mà tôi gọi từ bất cứ đâu như thế này:

//Where the first is a string and the other is a imageview to load.

DownloadImageTask.getInstance().loadBitmap(avatarURL, iv_avatar);

Đây là mã lý tưởng để lưu vào bộ đệm và sau đó gọi phần trên trong getView của bộ điều hợp khi truy xuất hình ảnh web:

public class DownloadImageTask {

    private LruCache<String, Bitmap> mMemoryCache;

    /* Create a singleton class to call this from multiple classes */

    private static DownloadImageTask instance = null;

    public static DownloadImageTask getInstance() {
        if (instance == null) {
            instance = new DownloadImageTask();
        }
        return instance;
    }

    //Lock the constructor from public instances
    private DownloadImageTask() {

        // Get max available VM memory, exceeding this amount will throw an
        // OutOfMemory exception. Stored in kilobytes as LruCache takes an
        // int in its constructor.
        final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);

        // Use 1/8th of the available memory for this memory cache.
        final int cacheSize = maxMemory / 8;

        mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
            @Override
            protected int sizeOf(String key, Bitmap bitmap) {
                // The cache size will be measured in kilobytes rather than
                // number of items.
                return bitmap.getByteCount() / 1024;
            }
        };
    }

    public void loadBitmap(String avatarURL, ImageView imageView) {
        final String imageKey = String.valueOf(avatarURL);

        final Bitmap bitmap = getBitmapFromMemCache(imageKey);
        if (bitmap != null) {
            imageView.setImageBitmap(bitmap);
        } else {
            imageView.setImageResource(R.drawable.ic_launcher);

            new DownloadImageTaskViaWeb(imageView).execute(avatarURL);
        }
    }

    private void addBitmapToMemoryCache(String key, Bitmap bitmap) {
        if (getBitmapFromMemCache(key) == null) {
            mMemoryCache.put(key, bitmap);
        }
    }

    private Bitmap getBitmapFromMemCache(String key) {
        return mMemoryCache.get(key);
    }

    /* A background process that opens a http stream and decodes a web image. */

    class DownloadImageTaskViaWeb extends AsyncTask<String, Void, Bitmap> {
        ImageView bmImage;

        public DownloadImageTaskViaWeb(ImageView bmImage) {
            this.bmImage = bmImage;
        }

        protected Bitmap doInBackground(String... urls) {

            String urldisplay = urls[0];
            Bitmap mIcon = null;
            try {
                InputStream in = new java.net.URL(urldisplay).openStream();
                mIcon = BitmapFactory.decodeStream(in);

            } 
            catch (Exception e) {
                Log.e("Error", e.getMessage());
                e.printStackTrace();
            }

            addBitmapToMemoryCache(String.valueOf(urldisplay), mIcon);

            return mIcon;
        }

        /* After decoding we update the view on the main UI. */
        protected void onPostExecute(Bitmap result) {
            bmImage.setImageBitmap(result);
        }
    }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.