0

I'd like to customized the size of the image used to cover up the real image to be displayed. In the UIL(Universal-Image-Loader) config, we can have .showStubImage(R.drawable.temp_drawable) as a display option.

My problem is, I am implementing a pinterest like view. By the time I scroll from the images, there is this unstable positions of the images because they are still being downloaded and covered up by a temp drawable. For example, the temporary drawable is 45 X 45, then the image to be displayed is 100 x 50. By the time the real image is showed there is this displacement effect of the images while scrolling because the temp image being replaced by the real one. Is there any way that we can detect the real image height and width to be displayed while is it still being downloaded, and using the width and height this can be used by the temp image to temporarily display the image size?

    options = new DisplayImageOptions.Builder()
    .showStubImage(R.drawable.ic_stub)
    .showImageForEmptyUri(R.drawable.ic_empty)
    .showImageOnFail(R.drawable.ic_error)
    .cacheInMemory(true)
    .cacheOnDisc(true)

  imageLoader.displayImage(imageUrls[position], hold.image, options);

enter image description here


Update Code from the Universal-Image-Loader.jar

public void displayImage(String uri, ImageView imageView, DisplayImageOptions options, ImageLoadingListener listener) {
    checkConfiguration();
    if (imageView == null) {
        throw new IllegalArgumentException(ERROR_WRONG_ARGUMENTS);
    }
    if (listener == null) {
        listener = emptyListener;
    }
    if (options == null) {
        options = configuration.defaultDisplayImageOptions;
    }

    if (TextUtils.isEmpty(uri)) {
        engine.cancelDisplayTaskFor(imageView);
        listener.onLoadingStarted(uri, imageView);
        if (options.shouldShowImageForEmptyUri()) {
            imageView.setImageResource(options.getImageForEmptyUri());
        } else {
            imageView.setImageDrawable(null);
        }
        listener.onLoadingComplete(uri, imageView, null);
        return;
    }

    ImageSize targetSize = ImageSizeUtils.defineTargetSizeForView(imageView, configuration.maxImageWidthForMemoryCache, configuration.maxImageHeightForMemoryCache);
    String memoryCacheKey = MemoryCacheUtil.generateKey(uri, targetSize);
    engine.prepareDisplayTaskFor(imageView, memoryCacheKey);

    listener.onLoadingStarted(uri, imageView);
    Bitmap bmp = configuration.memoryCache.get(memoryCacheKey);
    if (bmp != null && !bmp.isRecycled()) {
        if (configuration.writeLogs) L.d(LOG_LOAD_IMAGE_FROM_MEMORY_CACHE, memoryCacheKey);

        if (options.shouldPostProcess()) {
            ImageLoadingInfo imageLoadingInfo = new ImageLoadingInfo(uri, imageView, targetSize, memoryCacheKey, options, listener, engine.getLockForUri(uri));
            ProcessAndDisplayImageTask displayTask = new ProcessAndDisplayImageTask(engine, bmp, imageLoadingInfo, options.getHandler());
            engine.submit(displayTask);
        } else {
            options.getDisplayer().display(bmp, imageView, LoadedFrom.MEMORY_CACHE);
            listener.onLoadingComplete(uri, imageView, bmp);
        }
    } else {
        if (options.shouldShowStubImage()) {
            imageView.setImageResource(options.getStubImage());
        } else {
            if (options.isResetViewBeforeLoading()) {
                imageView.setImageDrawable(null);
            }
        }

        ImageLoadingInfo imageLoadingInfo = new ImageLoadingInfo(uri, imageView, targetSize, memoryCacheKey, options, listener, engine.getLockForUri(uri));
        LoadAndDisplayImageTask displayTask = new LoadAndDisplayImageTask(engine, imageLoadingInfo, options.getHandler());
        engine.submit(displayTask);
    }
}

I like to have `.showStubImage(getImageDimension())'

Additional

new DownloadFilesTask().execute(imageUrls[position]);

private class DownloadFilesTask extends AsyncTask<String, String, String> {

    @Override
    protected String doInBackground(String... params) {
        // TODO Auto-generated method stub


        URL uri = null;
        try {
            uri = new URL(params[0].toString());
        } catch (MalformedURLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

         InputStream in=null;
      try
        {
          //URL oracle = new URL(url);
        URLConnection urlConnection = uri.openConnection();
        in = new BufferedInputStream(urlConnection.getInputStream());
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeStream(in , null, options);
        //return options;
        } catch (MalformedURLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
      finally
        {
        if(in!=null)
             IoUtils.closeSilently(in);

        }
        return null;
    }
}
rahstame
  • 2,148
  • 4
  • 23
  • 53
  • 1
    if you are downloading images and the data related to images from you server then you could maintain a image height and width in the server, first pull height and width info for all the images from server and create the image view according the height and width info you have. – Suru Aug 17 '13 at 09:49
  • hhhm. not sure if I can do that. The images also auto adjust to the device screen so for example if there is a small screen, the images also adjust to that so that they can also fit. So in this case I need the image's size to be `displayed` and use it for the temp image. – rahstame Aug 17 '13 at 09:59
  • Check this [answer](http://stackoverflow.com/a/18372834/2405196). – Mihir Aug 22 '13 at 06:10

2 Answers2

2

This is not really related to Android. It's about design of your app.

If it's your server, you should decide on the sizes of the images and how to manage them, and put the correct placeholder accordingly.

If it's not your server, you can't know the size of the images without contacting the server in any way, so you will either have to set a static size that images will fit into, or get the sizes of the images before even showing the placeholders.

getting the image resolution is done with server files the same way as with other files, using inJustDecodeBounds while decoding.

EDIT:here's a sample code of how to get the size of a bitmap from the internet:

public static BitmapFactory.Options getBitmapOptions(final String url) 
  {
  InputStream in=null;
  try
    {
    URLConnection urlConnection = url.openConnection();
    in = new BufferedInputStream(urlConnection.getInputStream());
    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeStream(in , null, options);
    return options;
    }
  finally
    {
    if(in!=null)
      IOUtils.closeQuietly(in);        
    }
  return null;
  }
android developer
  • 114,585
  • 152
  • 739
  • 1,270
  • I rather choose to get the sizes of the images before even showing the placeholders, but my problem is, I am using Universal-Image-Loader library to handle the display, so I am not sure how to deal with the getting of the sizes. I added the code from .jar Library. – rahstame Aug 19 '13 at 01:34
  • it's simple. i will now put some code to show you how to get the sizes. – android developer Aug 19 '13 at 06:41
  • The `url` is not working sir coz it is a string. I added an update above for my progress, and the `showStubImage` only accepts `int` – rahstame Aug 19 '13 at 08:52
  • @lordzden it has nothing to do with what i've written. you first need to get the sizes, then put the correct image. if showStubImage doesn't allow you to set a bitmap and not just a resource drawable, then you shouldn't use it. you could use volley library instead. – android developer Aug 19 '13 at 12:48
2

Usually you are allowed to give only resource id as per the library like below.

options = new DisplayImageOptions.Builder().showStubImage(R.drawable.stubImage)....

If at all you need to put your dynamically changing sized stub image, you need to tweak in the source code such that your options should accept sized bitmap rather than int. To do that I have just looked into the source code. Below are the steps:

  1. Fist thing you need to do is to include it as library project instead of adding .jar in the libs folder.

  2. In the ImageLoader class and then in the public void displayImage(String uri, ImageView imageView, DisplayImageOptions options, ImageLoadingListener listener) method, replace this line imageView.setImageResource(options.getImageForEmptyUri()); with imageView.setImageBitmap(sizedBitmap);

  3. In the showStubImage(int stubImageRes) in DisplayImageOptions class, change the paramater as Bitmap and do necessary changes in that class.

  4. Take care of all the things that need to be changed at where this feature gets reflected in different parts.

Changing the size of Bitmap:

 Bitmap icon = BitmapFactory.decodeResource(context.getResources(),
                               R.drawable.stub_image);
  bitmap = Bitmap.createScaledBitmap(stub, width, height, false);
Kanth
  • 6,681
  • 3
  • 29
  • 41
  • 1
    In addition to above answer I would suggest one more thing.as per your requirement,you will need to create scaled bitmap every time.so I suggest you to cache the original Bitmap instead of fetching it everytime.and then do the scaling on that cached bitmap as long as you need. – Mehul Joisar Aug 19 '13 at 11:34