2011-08-08 24 views
2

我有一個ListView,每個元素有一個圖像和兩行文本(由RelativeLayout組織)。它工作正常,但速度太慢,我知道問題來自哪裏!Android - 列表視圖scrollig太慢

這是自定義適配器getView()方法,我使用:

public View getView(int position, View convertView, ViewGroup parent) { 
      if (convertView == null) { 
       convertView = mLayoutInflater.inflate(R.layout.list_view_item, parent, false); 
       mViewHolder = new ViewHolder(); 
       mViewHolder.cover = (ImageView) convertView.findViewById(R.id.app_icon); 
       mViewHolder.title = (TextView) convertView.findViewById(R.id.selection); 
       mViewHolder.description = (TextView) convertView.findViewById(R.id.app_short_description); 
       convertView.setTag(mViewHolder); 
      } else { 
       mViewHolder = (ViewHolder) convertView.getTag(); 
      } 

      // Here is the origin of the issue ! 
      final Feed currentFeed = getItem(position); 
      mViewHolder.title.setText(currentFeed.getTitle()); 
      mViewHolder.description.setText(currentFeed.getDescription()); 

      try { 
       if(currentFeed.getThumbnailUrl() != null) { 
        downloadThumbnail(mViewHolder.cover, currentFeed.getThumbnailUrl()); 
       } 
      } catch(Exception e) { 
       e.printStackTrace(); 
      } 

      return convertView; 
} 

private static class ViewHolder { 
     TextView title; 
     TextView description; 
     ImageView cover; 
} 

所以我做了一些人工標杆,看來,分配的Feed一個實例是這個緩慢的來源:

final Feed currentFeed = getItem(position); 

我知道這是因爲我寫的這另一個版本來比較兩個:

// Here is the origin of the issue ! 
      //final Feed currentFeed = getItem(position); 
      mViewHolder.title.setText("Title"); 
      mViewHolder.description.setText("Description"); 

      try { 
      if(currentFeed.getThumbnailUrl() != null) { 
       downloadThumbnail(mViewHolder.cover, "some url"); 
      } 
     } catch(Exception e) { 
      e.printStackTrace(); 
     } 

這一個更順利(即使downloadThumbnail()方法工作)。

我也確切地說,我的ListView只有15個項目。

我知道分配對象是非常昂貴的,因爲垃圾收集,但我不能以任何其他方式來做到這一點!

有什麼想法?

謝謝!

編輯

不要過分在意的downloadThumbnail()方法,它已經做了一些緩存。實際上即使沒有任何圖片,它仍然很慢。

+0

什麼的getItem()和downloadThumbnail()方法做? – Maxim

回答

4

當用戶滾動列表時,getView會在適配器上被調用。確保你不重複做同樣的事情,例如生成縮略圖。如果項目數量有限(例如視頻內容),則可以創建所有視圖並保持準備好以便獲取視圖。否則,你可能不得不實現緩存。

下面的代碼顯示了一個適配器和listView的實現,其中在所有的listview中創建並存儲在內存中。由於這是用於視頻瀏覽,所以內存不會造成任何問題。(數量有限的內容,最大100)

視頻列表適配器

import java.util.ArrayList; 
import java.util.Formatter; 
import java.util.HashMap; 
import java.util.List; 
import java.util.Locale; 

import android.content.ContentResolver; 
import android.content.Context; 
import android.content.res.Resources; 
import android.database.Cursor; 
import android.graphics.Bitmap; 
import android.graphics.Color; 
import android.provider.MediaStore; 
import android.util.Log; 
import android.view.LayoutInflater; 
import android.view.View; 
import android.view.ViewGroup; 
import android.widget.BaseAdapter; 
import android.widget.ImageView; 
import android.widget.LinearLayout; 
import android.widget.TextView; 
import android.widget.LinearLayout.LayoutParams; 

public class VideoListAdapter extends BaseAdapter { 
    private Context mContext = null; 
    private HashMap<String, VideoListItem> mHashedItems = new HashMap<String, VideoListItem>(); 
    private static final String TAG = "VideoListAdapter"; 

    public static final int VIDEO_CONTENT_ID  = 0; 
    public static final int VIDEO_CONTENT_TITLE = 1; 
    public static final int VIDEO_CONTENT_DURATION = 2; 
    public static final int VIDEO_CONTENT_RESOLUTION = 3; 
    public static final int VIDEO_CONTENT_MIME = 4; 

    private Cursor mCursorForVideoList = null; 
    private ContentResolver mContentResolver = null; 
    private int mListCount = 0; 

    VideoListAdapter(Context context, ContentResolver cr) { 
     mContext   = context; 
     mContentResolver = cr; 
     Log.i(TAG, "In the Constructor"); 

     mCursorForVideoList = 
      mContentResolver.query(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, 
            new String[] { MediaStore.MediaColumns._ID, 
               MediaStore.MediaColumns.TITLE, 
               MediaStore.Video.VideoColumns.DURATION, 
               MediaStore.Video.VideoColumns.RESOLUTION 
               }, 
            null, 
            null, 
            null); 
     mListCount = mCursorForVideoList.getCount(); 
    } 

    @Override 
    public int getCount() { 
     return mListCount; 
    } 

    @Override 
    public Object getItem(int arg0) { 
     return getVideoListItem(arg0); 
    } 

    @Override 
    public long getItemId(int position) { 
     //Log.i(TAG, "position : " + position); 
     return position; 
    } 

    @Override 
    public View getView(int position, View convertView, ViewGroup parent) { 
     //Log.i(TAG, "GetView :: Position : " + position); 
     return getVideoListItem(position); 
    } 

    private VideoListItem getVideoListItem(int position) 
    { 
     //Log.i(TAG, "getVideoListItem :: Position : " + position); 
     String key = Integer.toString(position); 
     VideoListItem item = mHashedItems.get(key); 
     if(item == null) 
     { 
      //Log.i(TAG, "New getVideoListItem :: Position : " + position); 
      mCursorForVideoList.moveToPosition(position); 
      mHashedItems.put(key, new VideoListItem(mContext, mContentResolver, mCursorForVideoList)); 
     } 
     return mHashedItems.get(key); 
    } 

}; 

視頻列表視圖

import java.util.Formatter; 
import java.util.Locale; 

import android.content.ContentResolver; 
import android.content.Context; 
import android.content.res.Resources; 
import android.database.Cursor; 
import android.graphics.Bitmap; 
import android.graphics.Color; 
import android.graphics.Typeface; 
import android.provider.MediaStore; 
import android.util.Log; 
import android.view.LayoutInflater; 
import android.view.View; 
import android.widget.ImageView; 
import android.widget.LinearLayout; 
import android.widget.TableLayout; 
import android.widget.TextView; 
import android.widget.LinearLayout.LayoutParams; 

class VideoListItem extends LinearLayout 
{ 
    private static final String TAG = "VideoListAdapter"; 

    private ImageView mThumbnail = null; 
    private TextView mDuration = null; 
    private TextView mTitle  = null; 
    private TextView mResolution = null; 

    private LayoutInflater mLayoutFactory = null; 

    private long mContentId = 0; 

    public VideoListItem(Context context, ContentResolver cr, Cursor cursor) { 
     super(context); 
     LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT); 
     params.setMargins(10, 10, 10, 10); 

     mLayoutFactory = LayoutInflater.from(context); 
     View thisView = mLayoutFactory.inflate(R.layout.videolistitem, null); 
     addView(thisView); 

     mThumbnail = (ImageView) findViewById(R.id.thumbnail); 
     mDuration = (TextView) findViewById(R.id.DDuration); 
     mTitle  = (TextView) findViewById(R.id.DTitle); 
     mResolution = (TextView) findViewById(R.id.DResolution); 

     mThumbnail.setLayoutParams(new LinearLayout.LayoutParams(144, 144)); 

     Resources r = this.getResources(); 
     Bitmap bMap = MediaStore.Video.Thumbnails.getThumbnail(cr, cursor.getLong(VideoListAdapter.VIDEO_CONTENT_ID), MediaStore.Video.Thumbnails.MINI_KIND, null); 
     if(bMap != null) 
     { 
      mThumbnail.setImageBitmap(Bitmap.createScaledBitmap(bMap, 128, 128, true)); 
     } 
     else 
     { 
      mThumbnail.setImageDrawable(r.getDrawable(R.drawable.error)); 
     } 
     mThumbnail.setPadding(16, 16, 16, 16); 
     mTitle.setText(cursor.getString(VideoListAdapter.VIDEO_CONTENT_TITLE)); 
     mTitle.setSingleLine(); 
     mTitle.setTextColor(Color.GREEN); 

     mResolution.setText(cursor.getString(VideoListAdapter.VIDEO_CONTENT_RESOLUTION)); 
     mResolution.setSingleLine(); 
     mResolution.setTextColor(Color.RED); 

     mDuration.setText(stringForTime(cursor.getInt(VideoListAdapter.VIDEO_CONTENT_DURATION))); 
     mDuration.setSingleLine(); 
     mDuration.setTextColor(Color.CYAN); 

     mContentId = cursor.getLong(VideoListAdapter.VIDEO_CONTENT_ID); 
    } 

    public long getContentId() 
    { 
     return mContentId; 
    } 

    private StringBuilder mFormatBuilder = null; 
    private Formatter mFormatter = null; 

    private String stringForTime(int timeMs) { 
     int totalSeconds = timeMs/1000; 

     mFormatBuilder = new StringBuilder(); 
     mFormatter = new Formatter(mFormatBuilder, Locale.getDefault()); 

     int seconds = totalSeconds % 60; 
     int minutes = (totalSeconds/60) % 60; 
     int hours = totalSeconds/3600; 

     mFormatBuilder.setLength(0); 
     if (hours > 0) { 
      return mFormatter.format("%d:%02d:%02d", hours, minutes, seconds).toString(); 
     } else { 
      return mFormatter.format("%02d:%02d", minutes, seconds).toString(); 
     } 
    } 

}; 

詞shash

1

不要在您的視圖持有者中分配或存儲Feed對象,而只是存儲位置(位置)。當您需要引用對象時,請從ViewHolder中獲取參考索引並相應地執行操作。

編輯
當然,我錯過了你使用的對象以後......你也可以創建一個數最小,靜態方法,你就輸對象只返回特定的東西,比如標題等等。然後在getView方法中調用這些方法來設置UI元素,而不用完全創建Feed本身。

+0

是的,我之前從View持有者中刪除了Feed對象。將嘗試使用靜態方法。謝謝。 –