android - تحميل كسول من الصور في ListView




image url universal-image-loader (25)

Novoda also has a great lazy image loading library and many apps like Songkick, Podio, SecretDJ and ImageSearch use their library.

Their library is hosted here on Github and they have a pretty active issues tracker as well. Their project seems to be pretty active too, with over 300+ commits at the time of writing this reply.

أستخدم ListView لعرض بعض الصور والتعليقات المصاحبة لتلك الصور. أنا أتلقى الصور من الإنترنت. هل هناك طريقة لتحميل الصور كسولًا حتى أثناء عرض النص ، لا يتم قفل واجهة المستخدم ويتم عرض الصور أثناء تنزيلها؟

العدد الإجمالي للصور غير ثابت.


android-developers.blogspot.com/2010/07/… ، وهو برنامج تعليمي من قبل جيل Debunne.

هذا من مدونة مطوّري برامج Android. تستخدم الشفرة المقترحة:

  • AsyncTasks .
  • حجم صعب ، محدود ، FIFO cache .
  • مخبأ ناعما garbage collect بسهولة garbage collect .
  • عنصر نائب Drawable أثناء التنزيل.


أعتقد أن هذه المشكلة تحظى بشعبية كبيرة بين مطوّري برامج Android ، وهناك الكثير من هذه المكتبات التي تدعي حل هذه المشكلة ، ولكن يبدو أن عددًا قليلاً منها فقط على المحك. AQuery هي إحدى هذه المكتبات ، لكنها أفضل من معظمها في جميع الجوانب وتستحق المحاولة.



محمل عالي الأداء - بعد دراسة الطرق المقترحة هنا ، استخدمت حل Ben مع بعض التغييرات -

  1. أدركت أن العمل مع الرسوم المتحركة يكون أسرع مع الصور النقطية لذلك أنا استخدم drawables بدلاً من ذلك

  2. يعد استخدام SoftReference أمرًا رائعًا ، ولكنه يجعل الصورة المخزنة مؤقتًا يتم حذفها كثيرًا ، لذلك أضفت قائمة مرتبطة تحتوي على مراجع صور ، تمنع من حذف الصورة ، حتى تصل إلى حجم محدد مسبقًا

  3. لفتح InputStream استخدمت java.net.URLConnection الذي يسمح لي باستخدام ذاكرة الويب المخبأة (تحتاج إلى ضبط ذاكرة التخزين المؤقت للاستجابة أولاً ، ولكن هذه قصة أخرى)

رمز بلدي:

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;
}
}

Just a quick tip for someone who is in indecision regarding what library to use for lazy-loading images:

There are four basic ways.

  1. DIY => Not the best solution but for a few images and if you want to go without the hassle of using others libraries

  2. Volley's Lazy Loading library => From guys at android. It is nice and everything but is poorly documented and hence is a problem to use.

  3. Picasso: A simple solution that just works, you can even specify the exact image size you want to bring in. It is very simple to use but might not be very "performant" for apps that has to deal with humongous amounts of images.

  4. UIL: The best way to lazy load images. You can cache images(you need permission of course), initialize the loader once, then have your work done. The most mature asynchronous image loading library I have ever seen so far.


هذه مشكلة شائعة على Android تم حلها بطرق كثيرة من قبل العديد من الأشخاص. في رأيي أن أفضل حل رأيته هو المكتبة الجديدة نسبياً المسماة بيكاسو . فيما يلي النقاط البارزة:

  • المصدر المفتوح ، ولكن برئاسة Jake Wharton من ActionBarSherlock الشهرة.
  • تحميل الصور بشكل غير متزامن من شبكة أو موارد التطبيق مع سطر واحد من التعليمات البرمجية
  • الكشف التلقائي ListView
  • التخزين التلقائي للذاكرة والذاكرة
  • يمكن القيام تحويلات مخصصة
  • الكثير من الخيارات شكلي
  • سوبر API بسيطة
  • يتم تحديثه بشكل متكرر

I had this issue and implemented lruCache. I believe you need API 12 and above or use the compatiblity v4 library. lurCache is fast memory, but it also has a budget, so if you're worried about that you can use a diskcache... It's all described in developer.android.com/training/displaying-bitmaps/… .

I'll now provide my implementation which is a singleton I call from anywhere like this:

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

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

Here's the ideal code to cache and then call the above in getView of an adapter when retrieving the web image:

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);
        }
    }
}

لقد كتبت برنامجًا تعليميًا يشرح كيفية إجراء تحميل كسول للصور في listview. أذهب إلى بعض التفاصيل حول قضايا إعادة التدوير والتزامن. أنا أيضا استخدام بركة الصفحات ثابتة لمنع وضع الكثير من المواضيع.

تحميل كسول من الصور في Listview دروس


يمكنك تجربة مكتبة Aquery Android للحصول على صورة تحميل كسولة و listview ... قد يساعدك الرمز أدناه على تنزيل مكتبة من هنا .

AQuery aq = new AQuery(mContext);
aq.id(R.id.image1).image("http://data.whicdn.com/images/63995806/original.jpg");

الطريقة التي أقوم بها هي عن طريق إطلاق موضوع لتحميل الصور في الخلفية وتسليمها لاستدعاء لكل عنصر القائمة. عند انتهاء الصورة ، يتم تنزيلها وتستدعي معاودة الاتصال التي تقوم بتحديث طريقة العرض لعنصر القائمة.

لا تعمل هذه الطريقة بشكل جيد عند إعادة تدوير طرق العرض.


حسنا ، وقت تحميل الصور من الإنترنت لديه العديد من الحلول. يمكنك أيضًا استخدام المكتبة Android-Query . سوف يوفر لك كل النشاط المطلوب. تأكد من ما تريد القيام به وقراءة صفحة wiki الخاصة بالمكتبة. وحل قيود تحميل الصور.

هذه هي شفرتي:

@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;
}

يجب أن يكون حل مشكلة التحميل البطيئة.


DroidParts has ImageFetcher that requires zero configuration to get started.

  • Uses a disk & in-memory Least Recently Used (LRU) cache.
  • Efficiently decodes images.
  • Supports modifying bitmaps in background thread.
  • Has simple cross-fade.
  • Has image loading progress callback.

Clone DroidPartsGram for an example:


تحديث: لاحظ أن هذه الإجابة غير فعالة حتى الآن. يعمل جامع البيانات المهملة بقوة على SoftReference و WeakReference ، لذا لا يعد هذا الرمز مناسبًا للتطبيقات الجديدة. (بدلاً من ذلك ، جرّب استخدام مكتبات مثل github.com/nostra13/Android-Universal-Image-Loader في إجابات أخرى.)

بفضل جيمس للرمز ، وباو لونغ لاقتراح استخدام SoftReference. قمت بتطبيق التغييرات SoftReference على رمز جيمس. لسوء الحظ تسبب SoftReferences صوري لجمع القمامة بسرعة كبيرة. في حالتي كانت جيدة دون الأشياء SoftReference ، لأن حجم قائمتي محدود وصوري صغيرة.

هناك نقاش منذ عام حول SoftReferences على مجموعات google: link to thread . كحل لمجموعات المهملة مبكرًا جدًا ، يقترحون إمكانية إعداد حجم كومة الذاكرة المؤقتة يدويًا باستخدام dalvik.system.VMRuntime.setMinimumHeapSize () ، وهو ليس جذابًا جدًا بالنسبة لي.

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();
}

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;
 }
}

Give Android-Query a try. It has amazingly simple methods to load and cache images asynchronously.


1. يسمح بيكاسو بتحميل صور خالية من المتاعب في تطبيقك - غالبًا في سطر واحد من الكود!

استخدم Gradle:

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

مجرد سطر واحد من التعليمات البرمجية!

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

تتم معالجة العديد من المخاطر الشائعة لتحميل الصور على Android تلقائيًا بواسطة بيكاسو

  • التعامل مع إعادة تدوير ImageView وتنزيل إلغاء في محول.
  • تحويلات الصور المعقدة بأقل استخدام للذاكرة.
  • الذاكرة التلقائية والتخزين المؤقت للقرص.

2. انسلق مكتبة لتحميل الصور والتخزين المؤقت لنظام Android تركز على التمرير السلس

استخدم Gradle:

repositories {
  mavenCentral() // jcenter() works as well because it pulls from Maven Central
}

dependencies {
  compile 'com.github.bumptech.glide:glide:3.7.0'
  compile 'com.android.support:support-v4:19.1.0'
}

// للحصول على رأي بسيط:

@Override public void onCreate(Bundle savedInstanceState) {
  ...
  ImageView imageView = (ImageView) findViewById(R.id.my_image_view);

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

// للحصول على قائمة صور بسيطة:

 @Override public View getView(int position, View recycled, ViewGroup container) {
      final ImageView myImageView;
      if (recycled == null) {
        myImageView = (ImageView) inflater.inflate(R.layout.my_image_view, container, false);
      } else {
        myImageView = (ImageView) recycled;
      }

      String url = myUrls.get(position);

      Glide
        .with(myFragment)
        .load(url)
        .centerCrop()
        .placeholder(R.drawable.loading_spinner)
        .crossFade()
        .into(myImageView);

      return myImageView;
}

أوصي أداة مفتوحة المصدر github.com/nostra13/Android-Universal-Image-Loader . ويستند في الأصل على مشروع Fedor Vlasov LazyList وقد تم تحسينه بشكل كبير منذ ذلك الحين.

  • تحميل الصور المتعددة
  • إمكانية الضبط الواسع لتكوين ImageLoader (منفذي الخيوط ، downlaoder ، مفكك التشفير ، الذاكرة وذاكرة التخزين المؤقت للقرص ، خيارات عرض الصور ، وغيرها)
  • إمكانية التخزين المؤقت للصور في الذاكرة و / أو على sysytem ملف الجهاز (أو بطاقة SD)
  • إمكانية "الاستماع" عملية التحميل
  • إمكانية لتخصيص كل مكالمة صورة عرض بخيارات منفصلة
  • دعم القطعة
  • دعم Android 2.0+

github.com/nostra13/Android-Universal-Image-Loader


إليك ما قمت بإنشائه للاحتفاظ بالصور التي يعرضها تطبيقي حاليًا. يرجى ملاحظة أن الكائن "Log" المستخدم هنا هو غلاف مخصص حول فئة السجل النهائية داخل 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();
    }
}

أريد فقط إضافة مثال جيد آخر ، محولات XML . نظرًا لأنه يتم استخدامه بواسطة Google ، فأنا أستخدم أيضًا نفس المنطق لتجنب حدوث خطأ OutOfMemory.

أساسا هذا ImageDownloader هو إجابتك (لأنها تغطي معظم متطلباتك). بعض يمكنك أيضا تنفيذ ذلك.


لقد قدمت عرضًا بسيطًا لقائمة كسول (موجودة في GitHub) مع الصور. قد يكون من المفيد لشخص ما. يقوم بتنزيل الصور في مؤشر ترابط الخلفية. يتم تخزين الصور مؤقتًا على بطاقة SD وفي الذاكرة. تطبيق ذاكرة التخزين المؤقت بسيط جدًا ويكفي لعرضه التوضيحي. أقوم بفك شفرة الصور باستخدام inSampleSize لتقليل استهلاك الذاكرة. أحاول أيضا التعامل مع وجهات النظر المعاد تدويرها بشكل صحيح.


I can recommend a different way that works like a charm: Android Query.

You can download that JAR file from here

AQuery androidAQuery = new AQuery(this);

كمثال:

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

It's very fast and accurate, and using this you can find many more features like animation when loading, getting a bitmap (if needed), etc.


إلقاء نظرة على Shutterbug ، SDLebImage أبليديوم خفيفة الوزن (مكتبة لطيفة على دائرة الرقابة الداخلية) إلى الروبوت. وهو يدعم التخزين المؤقت غير المتزامن ، يخزن عناوين المواقع الفاشلة ، ويعالج التزامن بشكل جيد ، ويتم تضمين الفئات الفرعية المساعدة.

طلبات السحب (وتقارير الأخطاء) هي موضع ترحيب أيضًا!


بيكاسو

استخدم مكتبة بيكاسو لجيك واريتون. (مكتبة مثالية ImageLoading شكل المطور من ActionBarSherlock)

صورة قوية تحميل مكتبة والتخزين المؤقت لالروبوت.

تضيف الصور السياق والحاجة الماسة إلى تطبيقات Android. يسمح بيكاسو بتحميل صور خالية من المتاعب في تطبيقك - غالبًا في سطر واحد من الكود!

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

تتم معالجة العديد من المخاطر الشائعة لتحميل الصور على Android تلقائيًا بواسطة بيكاسو:

التعامل مع إعادة تدوير ImageView وتحميل الإلغاء في محول. تحويلات الصور المعقدة بأقل استخدام للذاكرة. الذاكرة التلقائية والتخزين المؤقت للقرص.

مكتبة بيكاسو جيك وارتون

زحلقة

Glide هو إطار إدارة وسائط مفتوحة المصدر سريع وفعال للأندرويد يلتف على فك تشفير الوسائط ، التخزين المؤقت للذاكرة والقرص ، وتجميع الموارد إلى واجهة بسيطة وسهلة الاستخدام.

يدعم الإنزلاق جلب صور الفيديو والصور وملفات GIF المتحركة. يتضمن Glide واجهة برمجة تطبيقات مرنة تسمح للمطورين بالتوصيل إلى أي مكدس شبكة تقريبًا. افتراضيًا ، يستخدم Glide مجموعة مكونة من HttpUrlConnection مخصصة ، ولكنه يشتمل أيضًا على مكتبات أدوات مساعدة موصلة بمشروع Google Volley أو مكتبة OkHttp في Square بدلاً من ذلك.

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

ينصب تركيز Glide الأساسي على جعل أي نوع من قائمة الصور من التمرير على نحو سلس وسريع قدر الإمكان ، ولكن Glide فعال أيضًا في أي حالة تحتاج فيها إلى إحضار صورة عن بُعد وتغيير حجمها وعرضها.

الانزلاق صورة تحميل المكتبة

فريسكو من فيسبوك

Fresco هو نظام قوي لعرض الصور في تطبيقات Android.

تعتني Fresco بتحميل الصور وعرضها ، لذلك لا تضطر إلى ذلك. سيتم تحميل الصور من الشبكة ، أو التخزين المحلي ، أو الموارد المحلية ، وعرض العنصر النائب حتى وصول الصورة. له مستويين من ذاكرة التخزين المؤقت؛ واحد في الذاكرة وآخر في التخزين الداخلي.

فريسكو جيثب

في الإصدار 4.x من Android والإصدارات الأقدم ، يضع Fresco الصور في منطقة خاصة من ذاكرة Android. هذا يتيح تشغيل التطبيق الخاص بك بشكل أسرع - ويعاني OutOfMemoryError اللعين أقل في كثير من الأحيان.

وثائق فريسكو


اختراقه من قبل CustomPagerAdapter :

MainActivity.java :

import android.content.Context;
import android.os.Handler;
import android.os.Parcelable;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {

    private List<String> numberList = new ArrayList<String>();
    private CustomPagerAdapter mCustomPagerAdapter;
    private ViewPager mViewPager;
    private Handler handler;
    private Runnable runnable;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        numberList.clear();
        for (int i = 0; i < 10; i++) {
        numberList.add(""+i);
        }

        mViewPager = (ViewPager)findViewById(R.id.pager);
        mCustomPagerAdapter = new CustomPagerAdapter(MainActivity.this);
        EndlessPagerAdapter mAdapater = new EndlessPagerAdapter(mCustomPagerAdapter);
        mViewPager.setAdapter(mAdapater);


        mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

            }

            @Override
            public void onPageSelected(int position) {
                int modulo = position%numberList.size();
                Log.i("Current ViewPager View's Position", ""+modulo);

            }

            @Override
            public void onPageScrollStateChanged(int state) {

            }
        });

        handler = new Handler();
        runnable = new Runnable() {
            @Override
            public void run() {

                mViewPager.setCurrentItem(mViewPager.getCurrentItem()+1);
                handler.postDelayed(runnable, 1000);
            }
        };

        handler.post(runnable);

    }

    @Override
    protected void onDestroy() {
        if(handler!=null){
            handler.removeCallbacks(runnable);
        }
        super.onDestroy();
    }

    private class CustomPagerAdapter extends PagerAdapter {

        Context mContext;
        LayoutInflater mLayoutInflater;

        public CustomPagerAdapter(Context context) {
            mContext = context;
            mLayoutInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        }

        @Override
        public int getCount() {
            return numberList.size();
        }

        @Override
        public boolean isViewFromObject(View view, Object object) {
            return view == ((LinearLayout) object);
        }

        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            View itemView = mLayoutInflater.inflate(R.layout.row_item_viewpager, container, false);

            TextView textView = (TextView) itemView.findViewById(R.id.txtItem);
            textView.setText(numberList.get(position));
            container.addView(itemView);
            return itemView;
        }

        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            container.removeView((LinearLayout) object);
        }
    }

    private class EndlessPagerAdapter extends PagerAdapter {

        private static final String TAG = "EndlessPagerAdapter";
        private static final boolean DEBUG = false;

        private final PagerAdapter mPagerAdapter;

        EndlessPagerAdapter(PagerAdapter pagerAdapter) {
            if (pagerAdapter == null) {
                throw new IllegalArgumentException("Did you forget initialize PagerAdapter?");
            }
            if ((pagerAdapter instanceof FragmentPagerAdapter || pagerAdapter instanceof FragmentStatePagerAdapter) && pagerAdapter.getCount() < 3) {
                throw new IllegalArgumentException("When you use FragmentPagerAdapter or FragmentStatePagerAdapter, it only supports >= 3 pages.");
            }
            mPagerAdapter = pagerAdapter;
        }

        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            if (DEBUG) Log.d(TAG, "Destroy: " + getVirtualPosition(position));
            mPagerAdapter.destroyItem(container, getVirtualPosition(position), object);

            if (mPagerAdapter.getCount() < 4) {
                mPagerAdapter.instantiateItem(container, getVirtualPosition(position));
            }
        }

        @Override
        public void finishUpdate(ViewGroup container) {
            mPagerAdapter.finishUpdate(container);
        }

        @Override
        public int getCount() {
            return Integer.MAX_VALUE; // this is the magic that we can scroll infinitely.
        }

        @Override
        public CharSequence getPageTitle(int position) {
            return mPagerAdapter.getPageTitle(getVirtualPosition(position));
        }

        @Override
        public float getPageWidth(int position) {
            return mPagerAdapter.getPageWidth(getVirtualPosition(position));
        }

        @Override
        public boolean isViewFromObject(View view, Object o) {
            return mPagerAdapter.isViewFromObject(view, o);
        }

        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            if (DEBUG) Log.d(TAG, "Instantiate: " + getVirtualPosition(position));
            return mPagerAdapter.instantiateItem(container, getVirtualPosition(position));
        }

        @Override
        public Parcelable saveState() {
            return mPagerAdapter.saveState();
        }

        @Override
        public void restoreState(Parcelable state, ClassLoader loader) {
            mPagerAdapter.restoreState(state, loader);
        }

        @Override
        public void startUpdate(ViewGroup container) {
            mPagerAdapter.startUpdate(container);
        }

        int getVirtualPosition(int realPosition) {
            return realPosition % mPagerAdapter.getCount();
        }

        PagerAdapter getPagerAdapter() {
            return mPagerAdapter;
        }

    }
}

activity_main.xml :

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
    android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">

    <android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/pager"
        android:layout_width="match_parent"
        android:layout_height="180dp">
    </android.support.v4.view.ViewPager>

</RelativeLayout>

row_item_viewpager.xml :

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent" android:layout_height="match_parent"
    android:gravity="center">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/txtItem"
        android:textAppearance="@android:style/TextAppearance.Large"/>

</LinearLayout>

فعله







android image listview url universal-image-loader