Soru & Cevap

ListView Scroll Esnasında Bitmap Geç Yüklenme Sorunu

10.06.2014 - 11:42

Merhaba arkadaşlar elimde kullanıcının binary data resmi var.WhatsApp tarzı bir ListView'im var.Binary tarzı resmi ayrı bir threadda bitmapa çevirip yüklüyorum.

Aşşağıya doğru scroll yaptığımda kullanıcı resimleri geç(delay,lag)'lı bir şekilde yükleniyor.Imageleri cachelemem mi lazım daha önce başına gelmiş çözüm bulmuş olan var mı?

[code]

    public View getView(int position, View convertView, ViewGroup viewGroup) {
        ViewHolder holder;
        if(convertView==null){
            LayoutInflater inflater = (LayoutInflater) context
                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = inflater.inflate(R.layout.userlist_row,null);

            holder = new ViewHolder();
            holder.userImageIV = (ImageView)convertView.findViewById(R.id.userImageIV);
            holder.userPresenceIV = (ImageView)convertView.findViewById(R.id.presenceImageIV);
            holder.userNameTV = (TextView)convertView.findViewById(R.id.userNameTV);
            holder.userLocationTV = (TextView)convertView.findViewById(R.id.userLocationTV);
            convertView.setTag(holder);
        }else{
            holder = (ViewHolder) convertView.getTag();
        }

        if (userList.get(position).getUserPresence().equals("chat")) {
            holder.userPresenceIV.setImageResource(R.drawable.online_user);
        } else if (userList.get(position).getUserPresence().equals("dnd")) {
            holder.userPresenceIV.setImageResource(R.drawable.busy_user);
        } else if (userList.get(position).getUserPresence().equals("away")) {
            holder.userPresenceIV.setImageResource(R.drawable.away_user);
        } else if (userList.get(position).getUserPresence().equals("offline")) {
            holder.userPresenceIV.setImageResource(R.drawable.offline_user);
        }
        holder.userNameTV.setText(userList.get(position).toString());
        holder.userLocationTV.setText(userList.get(position).getUserLocation());
        if(userList.get(position).getUserPicdt()!=null){
            holder.position = position;
            new LoadProfileImageAsyncTask(position,holder).execute(userList.get(position).getUserPicdt());
        }else{
            holder.userImageIV.setImageResource(R.drawable.default_user);
        }
        return convertView;
    }

[/code]

getView methodum bu şekilde.Dediğim gibi listeyi scrolluyorum resimler yükleniyor ama bu işlem geç oluyor.

20 Görüntülenme

1 Cevap

Sitedeki sorulara cevap verebilmek için giriş yapın ya da üye olun.

picture-1372-1408467635.jpg
ahmtbrk
11.06.2014 - 11:49

Sorunu büyük oranda çözdüm sağolsun android mühendisleri LruCache isimli HashMap'a benzer bir cash mekanizması getirmişler.Entegrasyonunu şöyle özetleyim sıkıntıya düşen arkadaşlar yararlanır.

ListViewde performans için şunları yapmak lazım.

1.View Holder Patterni Kullanılmalı( tekrar tekrar row oluşturmamak için.mesela 1000 satır datanız var ama bu dataların hepsi ekranda görünen kadar(mesela 10 row) üstünde döner.10 tane nesne için bellekte yer açılmış olur).

2.Image işlemlerinde thread kullanılmalı.(Binary -> Bitmap çevrimlerinde vs ui thread kullanılırsa ListView scroll olduğunda en kral telefon bile kasıyor.Bunu aşmak için basit bir asynctask yazıp halledebilirsiniz)

Kişilerin resimlerini userId'lerine göre cacheledim.

[code]

private LruCache<String,Bitmap> imageCache;

[/code]

Adapterimin constructor(oluşum) evresindede değerini verdim.

[code]

final int memClass = ((ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE)).getMemoryClass();
        final int cacheSize = 1024 * 1024 * memClass / 8;
        imageCache = new LruCache<String, Bitmap>(cacheSize){
            @Override
            protected int sizeOf(String key, Bitmap bitmap) {
               return bitmap.getByteCount();
            }
        };

[/code]

İki tane methodumuz var birisi cachelemek için biriside cacheyi okumak için

Ekleme

[code]

public void addBitmapToMemoryCache(String key, Bitmap bitmap) {
        if (getBitmapFromMemCache(key) == null) {
            imageCache.put(key, bitmap);
        }
    }

[/code]

Okuma

[code]

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

[/code]

Yani kısaca userId bazlı cacheleme yapıyorum ve yine userId bazlı cacheyi okuyorum.getView içindede şu değişikliği yaptım.

[code]

 Bitmap bitmap = getBitmapFromMemCache(userList.get(position).getUserId());
            if(bitmap!=null){
                holder.userImageIV.setImageBitmap(bitmap);
            }else{
                holder.position = position;
                new LoadProfileImageAsyncTask(userList.get(position).getUserId(),position,holder).execute(userList.get(position).getUserPicdt());
            }

[/code]

İlk olarak cache var mı diye bakıyor varsa cacheden okuyor ve ImageView'e set ediyor.Eğer yoksa asynctask ile binary & bitmap dönüşümünü yapıp AsyncTask içindede cacheye ekliyor.Bundan sonra dönüp geldiğinde artık cachesi var olduğu için asynctask'a hiç düşmeyecek bu sayede tekrardan dönüşüm işlemleri gerçekleşmeyeceği için ekrana anında yansıma sağlanacak.

Açıklayıcı şekilde yazdım ihtiyacı olan yararlansın diye.