Giter Site home page Giter Site logo

android-universal-image-loader's People

Contributors

aiurlano avatar akurni avatar aporat avatar benelog avatar carlonzo avatar chogos avatar chrisjenx avatar ericeche avatar fatkun avatar googolmo avatar jlleitschuh avatar johanols avatar johnjohndoe avatar lukestclair avatar mente avatar mkhan07 avatar mrleolink avatar mvdan avatar ncoolz avatar nostra13 avatar qualtagh avatar ray-ni avatar rom1v avatar sangkwon avatar sherifelkhatib avatar talklittle avatar vitaly-olshevsky avatar vivekkiran avatar xiphirx avatar yanchenko avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

android-universal-image-loader's Issues

Class FuzzyKeyMemoryCache occurs ConcurrentModificationException.

Hi.

Thank you for your efforts with this wonderful image loader. :)

But sometimes, image loading fails for an unknown reason.

I found that the 'for' loop in FuzzyKeyMemoryCache.put(K, V) method occurs ConcurrentModificationException in that case.
I guess that this error kills the running thread instantly without calling callback method of ImageLoadingListener.

Please fix this bug.
Thank you.

Support for "aging" images

Thanks for the UniveralImageLoader - exactly what I needed!

Currently, I'm using TotalSizeLimitedDiscCache. I could, however, use one more feature: In my use case, I'm caching pics which may occasionally change. As such, I'd like to be able to tell UniversalImageLoader to only receive images from file cache if they have been stored not longer ago then a certain time period (say, a week). If the image in the cache is older than that, just receive it again from the url.

I am aware of the possibility to provide my own DscCache implementation, but I thought my use case might very well be a common one...

Http connection work improvements

May be this code will be useful:

public static void setClient() {
        HttpParams params = new BasicHttpParams();
        // Turn off stale checking. Our connections break all the time anyway,
        // and it's not worth it to pay the penalty of checking every time.
        HttpConnectionParams.setStaleCheckingEnabled(params, false);
        // Default connection and socket timeout of 10 seconds. Tweak to taste.
        HttpConnectionParams.setConnectionTimeout(params, 10 * 1000);
        HttpConnectionParams.setSoTimeout(params, 10 * 1000);
        HttpConnectionParams.setSocketBufferSize(params, 8192);

        // Don't handle redirects -- return them to the caller. Our code
        // often wants to re-POST after a redirect, which we must do ourselves.
        HttpClientParams.setRedirecting(params, false);
        // Set the specified user agent and register standard protocols.
        HttpProtocolParams.setUserAgent(params, "bigbuzzy business");
        SchemeRegistry schemeRegistry = new SchemeRegistry();
        schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
        schemeRegistry.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));

        ClientConnectionManager manager = new ThreadSafeClientConnManager(params, schemeRegistry);

        AndroidApplication.client = new DefaultHttpClient(manager, params);
    }

    //И загрузку через него (нет сети - берем из кеша иначе грузим):
    public static String retrieve(String url, boolean cache) {
        StringBuilder sb = new StringBuilder();
        sb.append(AndroidApplication.DOMEN);
        sb.append(url);
        url = sb.toString();
        Log.d("retrieve", url);
        String md5 = Md5.md5(url);
        File casheDir = AndroidApplication.cacheDir;//context.getCacheDir();

        File f = null;
        if (casheDir != null && cache) {
            f = new File(casheDir, md5);
            final long time = new Date().getTime() / 1000;
            if (f.exists()) {
                if ((f.lastModified() / 1000 + 600) > time) {
                    return readFile(f);
                }
            }
        }

        HttpGet getRequest = new HttpGet(url);

        try {
            HttpResponse getResponse = AndroidApplication.getClient().execute(getRequest);
            final int statusCode = getResponse.getStatusLine().getStatusCode();
            if (statusCode != HttpStatus.SC_OK) {
                Log.e("statusCode", statusCode + "");
            }

            HttpEntity getResponseEntity = getResponse.getEntity();

            if (getResponseEntity != null && statusCode == HttpStatus.SC_OK) {
                String s = EntityUtils.toString(getResponseEntity);
                if (statusCode != HttpStatus.SC_OK && f != null) {
                    BufferedOutputStream os = new BufferedOutputStream(new FileOutputStream(f));
                    os.write(s.getBytes());
                    os.close();
                }
                return s;
            }
        } catch (IOException e) {
            getRequest.abort();
            if (f != null) {
                if (f.exists()) {
                    return readFile(f);
                }
            }
            Log.e("NetUtils error", e.toString());
        }
        return null;
    }

    public static String readFile(File file) {
        String data = null;
        try {
            FileInputStream fis = null;
            InputStreamReader isr = null;
            fis = new FileInputStream(file);
            isr = new InputStreamReader(fis);
            char[] inputBuffer;
            inputBuffer = new char[fis.available()];
            isr.read(inputBuffer);
            data = new String(inputBuffer);
            isr.close();
            fis.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return data;
    }

FileUtils.copyStream() exception handling

Я не знаю как у вас используется FileUtils#copyStream(), но, что-то мне подсказывает, что скрывать IoException не правильно. Достаточно задать вопрос: будет ли приложение работать дальше нормально, если потоки не откопировались?

Cash directory path

I think that writing into sd-cards root is not the best practice. It woould be better to use
appCacheDir = new File(context.getExternalCacheDir(), cacheDirPath);
instead of
appCacheDir = new File(Environment.getExternalStorageDirectory(), cacheDirPath);

Undesired effect when using the library to load images in a Gallery

Hi,

i am using your library in my app to load images coming from an Internet server in a Gallery (android.widget.Gallery) and I am experiencing an strange behaviour, when I swipe my finger on it the scrolling is not smooth at all, there is some short of constant flickering.

This is the layout of my gallery:

<Gallery
    android:id="@+id/gallery"
    style="@style/Carousel.Gallery"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content" >
</Gallery>

And this is the layout of a gallery item:

@dimen/thumbnail_height and @dimen/thumbnail_width are some dimensions defined by me (120dip for xhdpi devices).

And this is the adapter I am using for the gallery

public class GalleryAdapter extends BaseAdapter {

    private int layoutId;
    protected Context context;
    private List<String> items;

    public GalleryAdapter(Context context, int layoutId) {
        this.layoutId = layoutId;
        this.items = new ArrayList<String>();
        this.context = context;
    }

    public void append(List<String> items) {
        this.items.addAll(items);
        notifyDataSetChanged();
    }

    public View getView(int position, View convertView, ViewGroup parent) {
        View view = convertView;
        if (view == null) {
            view = getView(layoutId, parent);
        }
        updateView(getItem(position), view);
        return view;
    }

    private View getView(int viewId, ViewGroup parent) {
        LayoutInflater inflater = (LayoutInflater) context
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        return inflater.inflate(viewId, parent, false);
    }

    private void updateView(Object item, View view) {
        String url = (String) item;
        ImageLoader imageLoader = ImageLoader.getInstance();
        ImageView imageView = (ImageView) view.findViewById(R.id.image);
        DisplayImageOptions options = new DisplayImageOptions.Builder()
                .showImageForEmptyUrl(placeholder)
                .showStubImage(placeholder).cacheOnDisc()
                .decodingType(DecodingType.MEMORY_SAVING).build();
        imageLoader.displayImage(url, imageView, options);
    }

The placeholder image has the same dimensions as the ones set for the ImageView.

I have initiated the ImageLoader in my class extending from Application in the following way

ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(
getApplicationContext()).threadPoolSize(3)
.threadPriority(Thread.NORM_PRIORITY - 2)
.memoryCacheSize(1500000) // 1.5 Mb
.discCacheSize(50000000) // 50 Mb
.httpReadTimeout(10000) // 10 s
.denyCacheImageMultipleSizesInMemory().build();
ImageLoader.getInstance().init(config);

I am using your library also with a ListView and a GridView and in those cases everything works perfectly in those cases.

For testing purposes I am using a Samsung Galaxy Nexus.

Have you also experienced this problem?

Your support would be much appreciated.

Thanks

M.

Image quality for cached images

I'm spanish, sorry if my english is bad. I don't know if this is the best place to put this doubt/request.
I have just started using this amazing loader. I was trying to do something similar for myself but this is far better.

Is it possible to choose the image quality (compression) for cached images? It would improve speed. I haven't seen any option for this. Thanks.

Ability to load song album tumbnails

Given an albumId load its thumbnail. Now its not possible due to that url needed is:
content://media/external/audio/albumart/20 -> 20 (albumId)

content protocol is not recognised, so it fails.

Something like that will be needed:

ContentResolver res = context.getContentResolver();
Uri uri = Uri.parse("content://media/external/audio/albumart/20");
InputStream is = res.openInputStream(uri);

Content Resolver is not passed to decode functions and i don't know if it can make a memory leak.

Crash on clear cache

The clear cache function crashes if the cache folder doesn't exists.
This is beacuse in DiskCache.java, line 27
cacheDir.listFiles();
returns null.

HTTP cache options

Investigate HTTP possibilities for caching. Maybe apply its to project.

ImageLoader log message not formatted

In ImageLoader displayImage() method, log string LOG_LOAD_IMAGE_FROM_MEMORY_CACHE is not formatted which leads to placeholder (%s) appearing in logs, instead of cache related information.

        Bitmap bmp = configuration.memoryCache.get(memoryCacheKey);
        if (bmp != null && !bmp.isRecycled()) {
            Log.i(TAG, LOG_LOAD_IMAGE_FROM_MEMORY_CACHE);
            imageView.setImageBitmap(bmp);
        } else {
            listener.onLoadingStarted();
            if (imageLoadingExecutor.isShutdown()) {
                imageLoadingExecutor = Executors.newFixedThreadPool(configuration.threadPoolSize);
            }

I'm not sure what you thought should be there, but I'm using memoryCacheKey now.

Log.i(TAG, String.format(LOG_LOAD_IMAGE_FROM_MEMORY_CACHE, memoryCacheKey));

Use Of Semaphore for avoiding unnecessary downloads/loads

I'm looking into new ways to improve speed significantly. Apart from creating a sized cache version of the image, that i know you're working on, i have new ideas.

I haven't made any test of that one:
Think on a listView full of Images. If they were cached alternatively, one on external disk cache and the other on internal disk cache, the read speed would be greatly improved.

Also there is an issue when you have a list with allways the same url repeated. Imagine that there are 10 image thumbnails on screen.The first time it is downloaded from internet/disk up to 5 times! that is due to there is any request control over the same url. The requests over the same url should be blocked until the image is downloaded to memory/disk cache. This can be achieved using semaphores. I will post some sample code later from the last issue!.

Problems when recycling listview items

First of all, nice work here, very professional and work out of the box. Thanks!

Then the issue I'm having. Maybe I just missed it, but I couldn't find a way in the current API to check whether the ImageView is still a valid target for the loaded image. The use case is recycled listview items: when the user scrolls, the list item view (and the associated ImageView) may have been assigned to a new list item.

Do you see the problem?

After the image has been loaded, I would like to control whether it is still ok to assign to the original ImageView or not. Or use some alternative API that doesn't require using an ImageView at all.

Field softMap in Cache visibility

Зачем поле softMap объявлено protected? Даже если нужен доступ у наследников (в данном случае я думаю не нужен) лучше написать модификатор private и добавить protected метод getCache

Can't attach lib to project + How get cached image file?

Hi,

I downloaded your latest jar (1.5.4). When I put it into "libs" folder and refresh the project, compiler says something is wrong in this project. When I delete the jar file then my application works fine.
I tried to use version 1.2.3 of your jar file and it is working well. Therefore, I think last version has problem.
My eclipse is Juno, OS: win32, Android SDK v20

Thanks

Display images in Widgets

Hi,

How can the ImageLoader be used to load images on an application widget?

Because the displayImage method takes an ImageView as parameter and in a widget we have to use RemoteViews.

Thanks.

Regards,

M

OutOfMemoryError when I download Images from internet

I have listView in which I display images , this is a snippet from Adapters' getView method

            ImageView imageView = (ImageView) v.findViewById(R.id.ivSmallImage);
    File cacheDir = StorageUtils.getOwnCacheDirectory(mContext, "alrawda/Cache");
    ImageLoader imageLoader = ImageLoader.getInstance();

    ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(mContext)
        .threadPoolSize(3)
        .threadPriority(Thread.NORM_PRIORITY - 2)
        .memoryCache(new UsingFreqLimitedMemoryCache(2000000))
        .memoryCacheSize(1500000) // 1.5 Mb

        .denyCacheImageMultipleSizesInMemory()
        .discCache(new UnlimitedDiscCache(cacheDir))
        .discCacheFileNameGenerator(new Md5FileNameGenerator())
        .enableLogging() // Not necessary in common


        .build();
    imageLoader.init(config);

    options = new DisplayImageOptions.Builder()

    .showStubImage(R.drawable.stub_image)
    .cacheInMemory()
    .cacheOnDisc()
    .build();
    final ProgressBar spinner = new ProgressBar(mContext);
    imageLoader.displayImage(o.getSmallImage(), imageView,options,new ImageLoadingListener() {

        @Override
        public void onLoadingStarted() {
            spinner.setVisibility(View.VISIBLE);

        }

        @Override
        public void onLoadingFailed(FailReason failReason) {
            spinner.setVisibility(View.INVISIBLE);

        }

        @Override
        public void onLoadingComplete() {
            spinner.setVisibility(View.INVISIBLE);

        }

        @Override
        public void onLoadingCancelled() {

        }
    });

After some images displayed , the Logcat shows me an error :

07-12 18:01:05.885: E/dalvikvm-heap(5680): Out of memory on a 1120016-byte allocation.
07-12 18:01:05.895: I/dalvikvm(5680): "Thread-9724" prio=3 tid=14 RUNNABLE
07-12 18:01:05.950: I/dalvikvm(5680): | group="main" sCount=0 dsCount=0 obj=0x419b7e98 self=0xc2c698
07-12 18:01:05.950: I/dalvikvm(5680): | sysTid=5709 nice=13 sched=0/0 cgrp=bg_non_interactive handle=12568832
07-12 18:01:05.950: I/dalvikvm(5680): | schedstat=( 4136736133 1474479795 2225 ) utm=383 stm=30 core=0
07-12 18:01:05.970: I/dalvikvm(5680): at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
07-12 18:01:05.970: I/dalvikvm(5680): at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:587)
07-12 18:01:05.975: I/dalvikvm(5680): at com.nostra13.universalimageloader.core.ImageDecoder.decode(ImageDecoder.java:61)
07-12 18:01:05.990: I/dalvikvm(5680): at com.nostra13.universalimageloader.core.LoadAndDisplayImageTask.decodeWithOOMHandling(LoadAndDisplayImageTask.java:163)
07-12 18:01:05.995: I/dalvikvm(5680): at com.nostra13.universalimageloader.core.LoadAndDisplayImageTask.decodeImage(LoadAndDisplayImageTask.java:150)
07-12 18:01:06.000: I/dalvikvm(5680): at com.nostra13.universalimageloader.core.LoadAndDisplayImageTask.tryLoadBitmap(LoadAndDisplayImageTask.java:104)
07-12 18:01:06.005: I/dalvikvm(5680): at com.nostra13.universalimageloader.core.LoadAndDisplayImageTask.run(LoadAndDisplayImageTask.java:58)
07-12 18:01:06.010: I/dalvikvm(5680): at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:442)
07-12 18:01:06.030: I/dalvikvm(5680): at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
07-12 18:01:06.030: I/dalvikvm(5680): at java.util.concurrent.FutureTask.run(FutureTask.java:137)
07-12 18:01:06.035: I/dalvikvm(5680): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
07-12 18:01:06.040: I/dalvikvm(5680): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
07-12 18:01:06.045: I/dalvikvm(5680): at java.lang.Thread.run(Thread.java:856)
07-12 18:01:06.055: D/skia(5680): --- decoder->decode returned false
07-12 18:01:06.095: E/ImageLoader(5680): null
07-12 18:01:06.095: E/ImageLoader(5680): java.lang.OutOfMemoryError
07-12 18:01:06.095: E/ImageLoader(5680): at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
07-12 18:01:06.095: E/ImageLoader(5680): at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:587)
07-12 18:01:06.095: E/ImageLoader(5680): at com.nostra13.universalimageloader.core.ImageDecoder.decode(ImageDecoder.java:61)
07-12 18:01:06.095: E/ImageLoader(5680): at com.nostra13.universalimageloader.core.LoadAndDisplayImageTask.decodeWithOOMHandling(LoadAndDisplayImageTask.java:163)
07-12 18:01:06.095: E/ImageLoader(5680): at com.nostra13.universalimageloader.core.LoadAndDisplayImageTask.decodeImage(LoadAndDisplayImageTask.java:150)
07-12 18:01:06.095: E/ImageLoader(5680): at com.nostra13.universalimageloader.core.LoadAndDisplayImageTask.tryLoadBitmap(LoadAndDisplayImageTask.java:104)
07-12 18:01:06.095: E/ImageLoader(5680): at com.nostra13.universalimageloader.core.LoadAndDisplayImageTask.run(LoadAndDisplayImageTask.java:58)
07-12 18:01:06.095: E/ImageLoader(5680): at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:442)
07-12 18:01:06.095: E/ImageLoader(5680): at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
07-12 18:01:06.095: E/ImageLoader(5680): at java.util.concurrent.FutureTask.run(FutureTask.java:137)
07-12 18:01:06.095: E/ImageLoader(5680): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
07-12 18:01:06.095: E/ImageLoader(5680): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
07-12 18:01:06.095: E/ImageLoader(5680): at java.lang.Thread.run(Thread.java:856)
07-12 18:01:06.180: D/dalvikvm(5680): GC_EXPLICIT freed 54K, 7% free 61470K/65479K, paused 3ms+16ms

How can I get out from this error ,

Cache Expires and big problem image is not compress

if i try get 106dip image,but server is not 106dip , i set config :

    public static ImageLoaderConfiguration get106DipConfig(){
        ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(KShareApplication.getInstance())
        .memoryCacheExtraOptions((int)(106 * UIUtil.getInstance().getDensity()),(int)(106 * UIUtil.getInstance().getDensity())) // Can slow ImageLoader, use it carefully (Better don't use it)
        .threadPoolSize(5)
        .threadPriority(Thread.MIN_PRIORITY + 2)
        .denyCacheImageMultipleSizesInMemory()
        .offOutOfMemoryHandling()
        .memoryCache( new FIFOLimitedMemoryCache(2 * 1024 * 1024)) // You can pass your own memory cache implementation
        .discCache(new UnlimitedDiscCache(new File(CommonUtil.getCacheDir()))) // You can pass your own disc cache implementation
        .discCacheFileNameGenerator(new HashCodeFileNameGenerator())
        .defaultDisplayImageOptions(DisplayImageOptions.createSimple())
        .enableLogging()
        .build();
        return config;
    }

i find imageview setbitmap is not compress!! so if we layout hava many imageview , this layout's Mem hava many.
so i think maybe you fix it.

you can allow this method:

 /**
     * Utility function for decoding an image resource. The decoded bitmap will
     * be optimized for further scaling to the requested destination dimensions
     * and scaling logic.
     *
     * @param res The resources object containing the image data
     * @param resId The resource id of the image data
     * @param dstWidth Width of destination area
     * @param dstHeight Height of destination area
     * @param scalingLogic Logic to use to avoid image stretching
     * @return Decoded bitmap
     */
    public static Bitmap decodeResource(Resources res, int resId, int dstWidth, int dstHeight,ScalingLogic scalingLogic) {
        Options options = new Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeResource(res, resId, options);
        options.inJustDecodeBounds = false;
        options.inSampleSize = calculateSampleSize(options.outWidth, options.outHeight, dstWidth,
                dstHeight, scalingLogic);
        Bitmap unscaledBitmap = BitmapFactory.decodeResource(res, resId, options);

        return unscaledBitmap;
    }
    /**
     * 
     * @param pathName 文件地址
     * @param dstWidth 需要显示的宽度
     * @param dstHeight 需要显示高度
     * @param scalingLogic 缩放类型,crop等比缩放并裁剪,fit原图等比缩放填充
     * @return Decoded bitmap
     */
    public static Bitmap decodeFile(String pathName,int dstWidth,int dstHeight,ScalingLogic scalingLogic){
        Options options = new Options();
        options.inJustDecodeBounds = true;

        BitmapFactory.decodeFile(pathName, options);
        options.inJustDecodeBounds = false;
        options.inSampleSize = calculateSampleSize(options.outWidth, options.outHeight, dstWidth,dstHeight, scalingLogic);

        Bitmap unscaledBitmap = BitmapFactory.decodeFile(pathName, options);

        return unscaledBitmap;
    }

    public static Bitmap decodeFile(byte[] bs,int dstWidth,int dstHeight,ScalingLogic scalingLogic){
        Options options = new Options();
        options.inJustDecodeBounds = true;

        BitmapFactory.decodeByteArray(bs, 0 , bs.length,options);
        options.inJustDecodeBounds = false;
        options.inSampleSize = calculateSampleSize(options.outWidth, options.outHeight, dstWidth,dstHeight, scalingLogic);

        Bitmap unscaledBitmap =  BitmapFactory.decodeByteArray(bs, 0 , bs.length,options);
        bs = null;
        return unscaledBitmap;
    }


    /**
     * Utility function for creating a scaled version of an existing bitmap
     *
     * @param unscaledBitmap Bitmap to scale
     * @param dstWidth Wanted width of destination bitmap
     * @param dstHeight Wanted height of destination bitmap
     * @param scalingLogic Logic to use to avoid image stretching
     * @return New scaled bitmap object
     */
    public static Bitmap createScaledBitmap(Bitmap unscaledBitmap, int dstWidth, int dstHeight,
            ScalingLogic scalingLogic) {
        Rect srcRect = calculateSrcRect(unscaledBitmap.getWidth(), unscaledBitmap.getHeight(),
                dstWidth, dstHeight, scalingLogic);
        Rect dstRect = calculateDstRect(unscaledBitmap.getWidth(), unscaledBitmap.getHeight(),
                dstWidth, dstHeight, scalingLogic);
        Bitmap scaledBitmap = Bitmap.createBitmap(dstRect.width(), dstRect.height(),
                Config.ARGB_8888);
        Canvas canvas = new Canvas(scaledBitmap);
        canvas.drawBitmap(unscaledBitmap, srcRect, dstRect, new Paint(Paint.FILTER_BITMAP_FLAG));

        return scaledBitmap;
    }

    /**
     * ScalingLogic defines how scaling should be carried out if source and
     * destination image has different aspect ratio.
     *
     * CROP: Scales the image the minimum amount while making sure that at least
     * one of the two dimensions fit inside the requested destination area.
     * Parts of the source image will be cropped to realize this.
     *
     * FIT: Scales the image the minimum amount while making sure both
     * dimensions fit inside the requested destination area. The resulting
     * destination dimensions might be adjusted to a smaller size than
     * requested.
     */
    public static enum ScalingLogic {
        CROP, FIT
    }

    /**
     * Calculate optimal down-sampling factor given the dimensions of a source
     * image, the dimensions of a destination area and a scaling logic.
     *
     * @param srcWidth Width of source image
     * @param srcHeight Height of source image
     * @param dstWidth Width of destination area
     * @param dstHeight Height of destination area
     * @param scalingLogic Logic to use to avoid image stretching
     * @return Optimal down scaling sample size for decoding
     */
    public static int calculateSampleSize(int srcWidth, int srcHeight, int dstWidth, int dstHeight,
            ScalingLogic scalingLogic) {
        if (scalingLogic == ScalingLogic.FIT) {
            final float srcAspect = (float)srcWidth / (float)srcHeight;
            final float dstAspect = (float)dstWidth / (float)dstHeight;

            if (srcAspect > dstAspect) {
                return srcWidth / dstWidth;
            } else {
                return srcHeight / dstHeight;
            }
        } else {
            final float srcAspect = (float)srcWidth / (float)srcHeight;
            final float dstAspect = (float)dstWidth / (float)dstHeight;

            if (srcAspect > dstAspect) {
                return srcHeight / dstHeight;
            } else {
                return srcWidth / dstWidth;
            }
        }
    }

    /**
     * Calculates source rectangle for scaling bitmap
     *
     * @param srcWidth Width of source image
     * @param srcHeight Height of source image
     * @param dstWidth Width of destination area
     * @param dstHeight Height of destination area
     * @param scalingLogic Logic to use to avoid image stretching
     * @return Optimal source rectangle
     */
    public static Rect calculateSrcRect(int srcWidth, int srcHeight, int dstWidth, int dstHeight,
            ScalingLogic scalingLogic) {
        if (scalingLogic == ScalingLogic.CROP) {
            final float srcAspect = (float)srcWidth / (float)srcHeight;
            final float dstAspect = (float)dstWidth / (float)dstHeight;

            if (srcAspect > dstAspect) {
                final int srcRectWidth = (int)(srcHeight * dstAspect);
                final int srcRectLeft = (srcWidth - srcRectWidth) / 2;
                return new Rect(srcRectLeft, 0, srcRectLeft + srcRectWidth, srcHeight);
            } else {
                final int srcRectHeight = (int)(srcWidth / dstAspect);
                final int scrRectTop = (int)(srcHeight - srcRectHeight) / 2;
                return new Rect(0, scrRectTop, srcWidth, scrRectTop + srcRectHeight);
            }
        } else {
            return new Rect(0, 0, srcWidth, srcHeight);
        }
    }

    /**
     * Calculates destination rectangle for scaling bitmap
     *
     * @param srcWidth Width of source image
     * @param srcHeight Height of source image
     * @param dstWidth Width of destination area
     * @param dstHeight Height of destination area
     * @param scalingLogic Logic to use to avoid image stretching
     * @return Optimal destination rectangle
     */
    public static Rect calculateDstRect(int srcWidth, int srcHeight, int dstWidth, int dstHeight,
            ScalingLogic scalingLogic) {
        if (scalingLogic == ScalingLogic.FIT) {
            final float srcAspect = (float)srcWidth / (float)srcHeight;
            final float dstAspect = (float)dstWidth / (float)dstHeight;

            if (srcAspect > dstAspect) {
                return new Rect(0, 0, dstWidth, (int)(dstWidth / srcAspect));
            } else {
                return new Rect(0, 0, (int)(dstHeight * srcAspect), dstHeight);
            }
        } else {
            return new Rect(0, 0, dstWidth, dstHeight);
        }
    }

if you can use,i think is very power!
use it :
1:decode
2:scale

Bitmap unscaledBitmap = decodeFile(bs, CommonUtil.dipToPixel(250), CommonUtil.dipToPixel(300), ScalingLogic.FIT);
                        Bitmap scaledBitmap = createScaledBitmap(unscaledBitmap, 250, 300, ScalingLogic.FIT);
                        unscaledBitmap.recycle();

                        if (scaledBitmap != null) {
                             imageView.setImageBitmap(scaledBitmap);
                        }

Using from Fragment raises : ERROR_IMAGEVIEW_CONTEXT

Using universal-image-loader-1.1.1.jar
Using android support package

Main activity is a FragmentActivity containing a ViewPager.
ViewPager contains Fragments. Fragment contains ListView.

When I attempt to use ImageLoader from the Fragment ListViews Adapter I receive the logged exception
ImageView context must be of Activity type

from
public class ImageLoader ...

private void tryRunOnUiThread(Runnable runnable) {
Context context = imageLoadingInfo.imageView.getContext();
if (context instanceof Activity) {
((Activity) context).runOnUiThread(runnable);
} else {
Log.e(TAG, ERROR_IMAGEVIEW_CONTEXT);
imageLoadingInfo.listener.onLoadingFailed(FailReason.WRONG_CONTEXT);
}
}

Add ability to pass an object to the listener methods

I would like to be able to associate an arbitrary object with a download request that gets passed to the listener callback methods. Here is why:

In my ListView, I use a ViewSwitcher to switch between an indeterminate progress bar and and ImageView. The idea is to display the progress bar whilst the image is downloading. To do this, I would like to pass the ViewSwitcher reference to the onLoadingStarted() and onLoadingComplete() to control whether the ProgressBar or ImageView is currently displayed.

I could imaging passing an object into the call to the displayImage() method that is then passed as an argument to the listener callbacks.

I would be willing to implement and submit a patch, although not too familiar with git operation...

Can't get it to load and display images in a list

Hi!

I have installed it, put the imageLoader in my Static class as a static property. Then i ran the init with the default config.

Now i have an adapter called twitterAdapter that loads twitters into a list.

I tried this (inside getView of my adapter class) to load the users image:

Image above is created like this:

final ImageView image = (ImageView) v.findViewById(R.id.avatar);

DisplayImageOptions options = new DisplayImageOptions.Builder()
            .build();           
// Load and display image
StaticResources.imageLoader.displayImage(tweet.image_url, image, options, new ImageLoadingListener() {
    public void onLoadingStarted() {               
                }
    public void onLoadingFailed(FailReason failReason) {

                }
    public void onLoadingComplete(Bitmap loadedImage) {
                    notifyDataSetChanged();
                }
    public void onLoadingCancelled() {
                            }
});

The twitters show up in the list but the images never loads. Any ideas?

Refactor PhotosQueue.clean()

PhotosQueue#clean(): гораздо красивее и более читабельно писать такие шутки через iterator:
Iterator it = photosToLoad.iterator();
while ( it.hasNext() ) {
final ImageView imageView = it.next();
if ( imageView == imageForRemove ) {
it.remove();
}
}

В вашем случае, по-моему, возможно падение с ConcurrentModificationException

Consider screen orientation

Consider screen orientation for cases when ImageView havn't specified size (width and height and maxWidth and maxHeight parameters).

Filecache not limited

I looked at the function saveImageOnDisc() and its usage in loadBitmap(). It looks like the file is always written to the cache, even if TotalSizeLimitedDiscCache is used. And files are never removed. Only the hashmap is updated. This is in line with what I experience looking at the cache directory.

Is this indeed a bug?

Greetings,
Michiel

Crash in displayImage() in ListView

I have everything wired up pretty much like the samples, but when I call imageLoader.displayImage(), I get an immediate crash in ListView.layoutChildren().

I do not have the Android sources attached so I don't know specifically what it doesn't like.

I am debugging on a phone (Android 2.3.4) without external storage, so I tried removing "cacheOnDisc()" but that didn't make any difference.

This is inside a ListFragment inside a FragmentActivity, using the compat library. I am initializing my Adapter using "getActivity()".

Any suggestions on what I am doing wrong?

Aspect ratio as display image option?

First of all thanks for sharing this nice stuff :)

I'm trying to implement the image loader into a gridview.
Therefore I need the images to be cropped to a aspect ratio of 1:1.

Is it possible to do this with your current state of code?

Image decoding sample size

Provide possibility to choose image decoding parameter "sample size":

  • fast : scale image with power of 2
  • reduce memory usage : scale image with exact size

Reloading image into larger image view does not work (divide by zero)

My application consists of a grid view and a detail view. The thumbnails are loaded using this library into the thumbnail view, then when a grid item is clicked, a detail view is shown with the same image in a larger image view. Both images are retrieved from the same URL.

No matter the configuration options I try, the images load successfully in the grid view but never load in the larger detail view - onLoadingStarted() is called, but no other callback is fired, not even onLoadingFailed(...).

My config:

config = new ImageLoaderConfiguration.Builder(getApplicationContext()) .threadPoolSize(3) .threadPriority(Thread.NORM_PRIORITY - 2) .memoryCacheSize(1500000) // 1.5 Mb .discCacheFileNameGenerator(new Md5FileNameGenerator()) .enableLogging() // Not necessary in common .build();

My options:

options = new DisplayImageOptions.Builder() .showStubImage(R.drawable.smile_placeholder) .showImageForEmptyUri(R.drawable.smile_placeholder) .cacheInMemory() .build();

Memory cache clear

I looked function "decodeImage" in ImageLoader class.
This function try clear memory in case OutOfMemoryError thrown.

But memory are not always cleared.
I have this messages in my logs:

05-03 08:38:13.202: INFO/dalvikvm-heap(462): Clamp target GC heap from 24.527MB to 24.000MB
05-03 08:38:15.931: ERROR/dalvikvm-heap(462): 816000-byte external allocation too large for this process.
05-03 08:38:16.011: INFO/dalvikvm-heap(462): Clamp target GC heap from 24.550MB to 24.000MB
05-03 08:38:16.011: ERROR/GraphicsJNI(462): VM won't let us allocate 816000 bytes

And new images are not shown. Are you use bitmap.recycle method?

I suggest to use recycle for all images in the memory cache. Such as in this solution http://blog.pseudoblue.com/2010/08/15/android-bitmaps-and-memory-leaks/

HashMap<Integer, Bitmap> mBitmaps;

public void recycleBitmaps() {
        Iterator itr = mBitmaps.entrySet().iterator();
        while (itr.hasNext()) {
            Map.Entry e = (Map.Entry)itr.next();
            ((Bitmap) e.getValue()).recycle();
        }
        mBitmaps.clear();
    }

'Out of memory' on images with a specific resolution

In a photo gallery application I am working on, I noticed that on images of a certain resolution (2272x1704) the application went 'out of memory'. The problem was that this particular size of images and the size of the display used (1280x800) caused the method computeImageScale() in the ImageDecoder class to return 1 instead of an appropriate scale factor. Changing the condition in the while loop of this method from AND to OR solved the problem.

Potential NPE in Cache.get()

Потенциальный NPE в методе get(): не сихронизованы методы clear() и get(). Более подробно: cointaisKey() возвращает true, вызывается метод clear(), get() от Map возвращает null.

Решение без synchronized: внутри метода Cache#get() использовать сразу Map#get() и проверять результат на null. В таком случае нужно поле Map нужно делать private и запрещать любые доступы к нему извне

when i reinstall the apk, the disc cache directory will be changed

in StorageUtils.java

public static File getOwnCacheDirectory(Context context, String cacheDir) {
File appCacheDir = null;
if (Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)) {
appCacheDir = new File(Environment.getExternalStorageDirectory(), cacheDir);
}
if (!appCacheDir.mkdirs()) {
appCacheDir = context.getCacheDir();
}
return appCacheDir;
}

when i reinstall the apk, the disc cache already exists, and the appCacheDir.mkdirs() return false. so the disc cache directory change to context.getCacheDir();

i think there should be add the appCacheDir.exists() to judge

Where is address of "DefaultImageDownloader"?

Hi again dear Nostra,

During configuration of ImageLoader, I found this problem.

ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(context)
.imageDownloader(new DefaultImageDownloader(5 * 1000, 30 * 1000)) // connectTimeout (5 s), readTimeout (30 s)

When I paste above line into my code, compiler cannot find the library of "DefaultImageDownloader". What is solution?

Also, there is same situation with
DisplayImageOptions options = new DisplayImageOptions.Builder()
.transform(matrix)

What is matrix?

Thanks Nostra,

Loading images from filesystem fails

Hi Nostra13,

Thanks for the very nice code you made.

I try to use it for loading images from the filesystem. I get an error. And loading fails. If I inspect the code, functions for loading from the (original) picture from the filesystem seem to be missing. Is that correct? Or is something else happening?

See below.

Michiel

I get the error:
03-29 09:41:01.230: E/ImageLoader(10716): java.lang.ClassCastException: org.apache.harmony.luni.internal.net.www.protocol.file.FileURLConnection cannot be cast to java.net.HttpURLConnection

It is sparked in the saveImageOnDisc function. First line:
HttpURLConnection conn = (HttpURLConnection) new URL(imageLoadingInfo.url).openConnection();

The function saveImageOnDisc is called from the loadBitmap function.
This functions checks if there is a cached image on the cache part of the filesystem. There isn't (which is correct.) Then it tries to load the image from the web. There I get the error (which is logical.)

Add ability to cancel a download for a given ImageView

I have a ListView with each row containing an ImageView. Not all of the rows have an associated URL for an image so in my adapter, if there is no URL, I assign a default image to the ImageView.

However, when flinging the list quickly such that ImageViews are recycled, I can end up with one of the rows that should have a default image being assigned a downloaded image because I cannot cancel a pending download. I think it goes like this:

  1. Start a download on an ImageView with imageLoader.displayImage()
  2. ImageView is recycled and for this row, the adapter now assigns a default image because it has no URL
  3. Download completes, isConsistent() function returns true, and downloaded image is assigned.

I would like in step 2 to be able to indicate to the ImageLoader that the download associated with an ImageView should not be assigned to the ImageView when it completes please.

Nice library by the way!

Preload into memory cache

It would be a very nice freature to can preload an image to memory cache. Very useful when scrolling in listviews.
All the code for loading the image woud be the same, but without putting it in the imageview.

LimitedDiscCache NPEs when device is connected as USB storage

When my Samsung Galexy S2 (2.3.6) is plugged into my computer via USB, the device is mounted as a storage device, then my app using the LimitedDiscCache (1.2.3) will NPE.

E/AndroidRuntime(7276): Caused by: java.lang.NullPointerException
E/AndroidRuntime(7276):     at com.nostra13.universalimageloader.cache.disc.LimitedDiscCache.calculateCacheSizeAndFillUsageMap(LimitedDiscCache.java:41)
E/AndroidRuntime(7276):     at com.nostra13.universalimageloader.cache.disc.LimitedDiscCache.<init>(LimitedDiscCache.java:35)
E/AndroidRuntime(7276):     at com.nostra13.universalimageloader.cache.disc.impl.FileCountLimitedDiscCache.<init>(FileCountLimitedDiscCache.java:25)
E/AndroidRuntime(7276):     at myapp.android.MyModule.configure(MyModule.java:38)

Workaround: Just unmount the device as USB storage.

Possible optimization / error for compression

I have seen that the image is decoded 2 times and read from disc unnecersarily. Also image is downloaded 2 times and overwritting the compressed one?

After compressing the compressed bitmap can be retrieved this way:

Bitmap original ...;
OutputStream discCacheOs = new BufferedOutputStream(new FileOutputStream(targetFile));
ByteArrayOutputStream out = new ByteArrayOutputStream();
original.compress(configuration.imageCompressFormatForDiscCache, configuration.imageQualityForDiscCache, out);
Bitmap decoded = BitmapFactory.decodeStream(new ByteArrayInputStream(out.toByteArray()));

then...

out.close();
original.recycle();
decoded.compress(configuration.imageCompressFormatForDiscCache,100, discCacheOs); (Or way you want)

After doing that, it is already on disc cache and you have the compressed bitmap on the var decoded.
Why is the input stream copyed again to de outputstream?
Also after saveImaseOnDisc the bitmap is decoded again unnecesarily.

private void saveImageOnDisc(File targetFile) throws MalformedURLException, IOException {
        int width = configuration.maxImageWidthForDiscCache;
        int height = configuration.maxImageHeightForDiscCache;
        if (width > 0 || height > 0) {
            // Download, decode, compress and save image
            ImageSize targetImageSize = new ImageSize(width, height);
            ImageDecoder decoder = new ImageDecoder(new URL(imageLoadingInfo.url), configuration.downloader, targetImageSize, ImageScaleType.EXACT);
            Bitmap bmp = decoder.decode();
            OutputStream os = new BufferedOutputStream(new FileOutputStream(targetFile));
            boolean compressedSuccessfully = bmp.compress(configuration.imageCompressFormatForDiscCache, configuration.imageQualityForDiscCache, os);
            if (compressedSuccessfully) {
                bmp.recycle();
                return;
            }
        }
                                                                                    (COMPRESSED BITMAP CAN BE RESTORED FROM OUTPUTSTREAM HERE)

// Download and save original image                                                                       (FROM HERE IS ANYTHING NEEDED?)
        InputStream is = configuration.downloader.getStream(new URL(imageLoadingInfo.url));
        try {
            OutputStream os = new BufferedOutputStream(new FileOutputStream(targetFile));
            try {
                FileUtils.copyStream(is, os);
            } finally {
                os.close();
            }
        } finally {
            is.close();
        }
    }

Also when returning to Bitmap loadBitmap there is that code:

} else {
        imageUrlForDecoding = new URL(imageLoadingInfo.url);
}

bitmap = decodeImage(imageUrlForDecoding);  //(DECODED AGAIN)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.