Javier
Javier

Reputation: 1695

Async load Image in contact list

Hi i can't find a way to load in async mode contact picture, my code seems its ok in hight end phones but phones with less memory and processor are slow this is my code in my activity, i use onScrollchanged for avoid retrieving contact picture on scroll

mAdapter = new DialerContactsAdapter(contactos,getActivity());
            listaContactos.setAdapter(mAdapter);
            listaContactos.setFastScrollEnabled(true);
            listaContactos.setOnScrollListener(new OnScrollListener() {
                @Override
                public void onScrollStateChanged(AbsListView view, int scrollState) {
                    switch (scrollState) {
                    case OnScrollListener.SCROLL_STATE_IDLE:
                    mAdapter.mBusy = false;
                    mAdapter.notifyDataSetChanged();
                    break;
                    case OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:
                        mAdapter.mBusy = false;
                        mAdapter.notifyDataSetChanged();
                    break;
                    case OnScrollListener.SCROLL_STATE_FLING:
                        mAdapter.mBusy = true;
                    break;
                    }
                }

                @Override
                public void onScroll(AbsListView view, int firstVisibleItem,
                        int visibleItemCount, int totalItemCount) {
                    // TODO Auto-generated method stub

                }
            });

this is my custom adapter, i "load the image from Database always and i do the resize, i save into LruCache class

@Override  
  public View getView(int position, View convertView, ViewGroup parent) { 
        ViewHolder holder =null; 
      View v = convertView;
      if (v == null) {
          LayoutInflater vi = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
          v = vi.inflate(R.layout.dialer_contact_list, null);
          holder = new ViewHolder();
          holder.Picture =  (ImageView) v.findViewById(R.id.imgContactDialer);
          holder.Desc =(TextView) v.findViewById(R.id.txtContactNameDialer);
          holder.phone =(TextView)v.findViewById(R.id.txtContactNumberDialer);
          v.setTag(holder);
      }else
      {
          holder = (ViewHolder)v.getTag();
      }
      final ViewHolder holder2 = holder;
      final ContactInfo ci = (ContactInfo) getItem(position);
      holder2.Picture.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Intent contact = new Intent(context, ShowSingleContactFragment.class);
            contact.putExtra("id", ci.get_id());
            contact.putExtra("name", ci.getDisplayName());
            context.startActivity(contact);
        }
    });
      //genera PlaceHolder
      Bitmap cacheImg =  cache.getBitmapFromMemCache(ci.get_id());
      if(cacheImg==null)
      {
          if(!mBusy)
          {
             new Thread(new Runnable() {
                public void run() {

                    final Bitmap photo= Contacts.loadContactPhoto(ci.get_id(),context.getBaseContext(),context.getResources().getInteger(R.integer.contact_picture_size));
                    cache.addBitmapToMemoryCache(ci.get_id(), photo);
                    holder2.Picture.post(new Runnable() {
                    public void run() {
                        holder2.Picture.setImageBitmap(photo);
                    }
                  });
                }
              }).start();
          }else
          {
              holder.Picture.setImageResource(R.drawable.ic_contact_picture);
          }
      }else
      {
          holder2.Picture.setImageBitmap(cacheImg);
      }
}

This is my BitmapCache class

public class BitmapCache {
    public  LruCache<String, Bitmap> mMemoryCache;
    public BitmapCache(Context mContext)
    {
         final int memClass = ((ActivityManager) mContext.getSystemService(
                    Context.ACTIVITY_SERVICE)).getMemoryClass();

            // Use 1/8th of the available memory for this memory cache.
            final int cacheSize = 1024 * 1024 * memClass / 8;
            mMemoryCache = new LruCache <String, Bitmap>(cacheSize) {
                @Override
                protected int sizeOf(String key, Bitmap bitmap) {
                    // The cache size will be measured in bytes rather than number of items.
                    return getByteCount(bitmap);
                }
            };
    }
    @SuppressLint("NewApi")
    private int getByteCount(Bitmap bitmap)
    {
        if(Utils.isHoneyComb())
        {
            return bitmap.getByteCount();

        }else
        {
            return bitmap.getRowBytes() * bitmap.getHeight();
        }
    }
    public void addBitmapToMemoryCache(String key, Bitmap bitmap) {
        if (getBitmapFromMemCache(key) == null) {
            mMemoryCache.put(key, bitmap);
        }
    }

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

}

i can't find the stock android contact list, can someone help me please? thanks a lot.

Upvotes: 0

Views: 714

Answers (1)

boburShox
boburShox

Reputation: 2630

As @Janmejoy said, lazy loader is better choice, at least I think so. Because I had the same issue few weeks ago. What I did was use Lazy loader, and ViewHolder. For a start, I didn't have any problems with loading small images. However, I found that larger images seemed not to be scaled correctly, and shown badly. Then I made some changes to Lazy loader so it can scale images properly. My scaling code is based on this

In the ImageLoader class, I defined a variable DisplayMetrics disMetrics; and inside the constructor I did this: disMetrics = new DisplayMetrics();

Next step was making some changes in decodeFile(File file) method:

//decodes image and scales it to reduce memory consumption
private Bitmap decodeFile(File f){
    try {
        //decode image size
        BitmapFactory.Options o = new BitmapFactory.Options();
        o.inJustDecodeBounds = true;
        FileInputStream stream1=new FileInputStream(f);
        BitmapFactory.decodeStream(stream1,null,o);
        stream1.close();

                   // my custom scaling
        int tw = disMetrics.widthPixels;
        int th = disMetrics.heightPixels;
        int targetWidth = tw <= 0 ? Integer.MAX_VALUE : tw;
        int targetHeight = th <= 0 ? Integer.MAX_VALUE : th;

        int scale = 0;
        while ((o.outWidth >> scale) > targetWidth || (o.outHeight >> scale) > targetHeight) {
            scale++;
        }
                 // native scaling
        //Find the correct scale value. It should be the power of 2.
        //final int REQUIRED_SIZE=70;
        //int width_tmp=o.outWidth, height_tmp=o.outHeight;
        //int scale=1;
        //while(true){
        //  if(width_tmp/2<REQUIRED_SIZE || height_tmp/2<REQUIRED_SIZE)
        //      break;
        //  width_tmp/=2;
        //  height_tmp/=2;
        //  scale*=2;
        //}

        //decode with inSampleSize
        BitmapFactory.Options o2 = new BitmapFactory.Options();
        o2.inSampleSize=scale;
        o2.inSampleSize = 1 << scale;
        FileInputStream stream2=new FileInputStream(f);
        Bitmap bitmap=BitmapFactory.decodeStream(stream2, null, o2);
        stream2.close();
        return bitmap;
    } catch (FileNotFoundException e) {
    }
    catch (IOException e) {
        e.printStackTrace();
    }
    return null;
}

Eventually, I got the result I wanted. I hope it helps you too.

Cheers.

Upvotes: 2

Related Questions