异步加载联系人列表中的图像

Posted

技术标签:

【中文标题】异步加载联系人列表中的图像【英文标题】:Async load Image in contact list 【发布时间】:2012-12-24 11:06:25 【问题描述】:

您好,我找不到在异步模式下加载联系人图片的方法,我的代码在高端手机中似乎没问题,但内存和处理器较少的手机速度很慢 这是我在活动中的代码,我使用onScrollchanged 来避免在滚动条上检索联系人图片

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

                
            );

这是我的自定义适配器,我“总是从数据库加载图像并调整大小,我保存到 LruCache 类中

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

这是我的 BitmapCache 类

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


我找不到股票 android 联系人列表,有人可以帮我吗?非常感谢。

【问题讨论】:

使用这个...demo 来延迟加载图片...github.com/thest1/LazyList 这会将图像存储在缓存中,因此每次加载所有图像都不需要时间,并且它还保存了低处理器和低内存手机中的内存不足错误.. 尝试使用惰性适配器加载图像.. 这是链接...它可能对您有所帮助.. thinkandroid.wordpress.com/2012/06/13/… 我尝试了lazyLoad和终极加载器,但它们速度慢且不稳定:s我开始认为我手机上的文件读取不太好:s(Htc one x)但atm我当前的代码似乎工作更好:(在我的设备上运行良好,但在其他设备上运行速度较慢:( 【参考方案1】:

正如@Janmejoy 所说,惰性加载器是更好的选择,至少我是这么认为的。因为几周前我有同样的issue。我所做的是使用 Lazy loader 和 ViewHolder。首先,我在加载小图像时没有任何问题。但是,我发现较大的图像似乎没有正确缩放,并且显示效果很差。然后我对 Lazy loader 进行了一些更改,以便它可以正确缩放图像。我的缩放代码基于this

在 ImageLoader 类中,我定义了一个变量 DisplayMetrics disMetrics;,在构造函数中我这样做了:disMetrics = new DisplayMetrics();

下一步是对decodeFile(File file) 方法进行一些更改:

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

最终,我得到了我想要的结果。 希望对你也有帮助。

干杯。

【讨论】:

以上是关于异步加载联系人列表中的图像的主要内容,如果未能解决你的问题,请参考以下文章

java 此类可帮助您将SD卡中的图像异步加载到列表视图中

在PySide中异步加载图像

uitableview 中的异步图像加载

异步加载图像不断导致图像闪烁?

UITableViewCell 内存问题中的异步图像加载

Swift 在 UITableView 中异步加载图像 - 顶部单元格没有图片