2011-08-08 12 views
2

私はListViewを持っています。これは、各要素に対して1つのイメージと2行のテキスト(RelativeLayoutで編成されています)を持っています。それは正常に動作しますが、それは遅すぎると私は問題がどこから来るのか知っています!Android - ListViewスクロールが遅すぎる

これは私が使用しているカスタムアダプタの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); 

私は2つを比較するには、この別のバージョンを書かれているので、私はこれを知っている:

// 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項目しかありません。

ガベージコレクションのためにオブジェクトを割り当てるのは非常に高価ですが、それ以外の方法はありません。

ありがとうございます!

EDIT

はdownloadThumbnail()メソッドについてはあまり気にしないでください、それはすでにいくつかのキャッシングを行います。実際には写真がなくても、それはまだ遅いです。

+0

何のgetItem()およびdownloadThumbnail()メソッド行う? – Maxim

答えて

4

ユーザーがリストをスクロールすると、getViewがアダプタで呼び出されます。あなたがサムネイルを生成するなど、繰り返し同じことをしないことを確認してください。アイテムの数が限られている場合(たとえば、ビデオコンテンツ)、すべてのビューを作成して、ビューを取得できる状態に保つことができます。それ以外の場合は、キャッシュを実装する必要があります。

以下のコードは、すべてのリストビューで作成されてメモリに格納される、アダプタと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オブジェクトをViewホルダーに割り当てたり保存したりしないで、代わりにその位置(ポジション)のみを保存しないでください。オブジェクトを参照する必要があるときは、ViewHolderから参照インデックスを取得し、それに応じて動作させます。

編集私はあなたが後で上のオブジェクトを使用していることを見逃しもちろん
...あなたはまた、タイトルなど、特定のものを返すフィードオブジェクトのための最小限の、静的メソッドの数を作成することができます次に、getViewメソッドでこれらのメソッドを呼び出して、フィード自体を完全に作成せずにUI要素を設定します。

+0

私は以前、ViewホルダーからFeedオブジェクトを削除しました。静的メソッドを使用してみます。ありがとう。 –