Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Listview Holder positions shuffled

I have a problem with ListView, or to be more exact - ImageView placed on it. My app is downloading thumbnails from Youtube. Everything to that place is fine. Later, while using getView() a strange behavior appears. When I'm loading data to holder within if condition:

    if(convertView == null){

convertView = mInflater.inflate(R.layout.list_item_user_video, null);
holder = new ViewHolder();  

holder.title = (TextView) convertView.findViewById(R.id.userVideoTitleTextView); 
holder.thumb = (UrlImageView) convertView.findViewById(R.id.userVideoThumbImageView);
Video video = videos.get(position);
holder.title.setText(video.getTitle());
holder.thumb.setImageDrawable(video.getThumbUrl());
                convertView.setTag(holder);
            }

my app is fast, but positions of each pair of ImageView and TextView are shuffled while fast scrolling. When part:

 Video video = videos.get(position);
                holder.title.setText(video.getTitle());
                holder.thumb.setImageDrawable(video.getThumbUrl());

is outside of if(convertView == null) ImageView and TextView are where they should be, but app is very slow. I've checked everything and I have entirely no idea how to solve this problem. Could you help me? If you need extra informations, ask.

Thanks.

VideosActivity.java

    public class VideosAdapter extends BaseAdapter{
    // The list of videos to display
    List<Video> videos;
    // An inflator to use when creating rows
    private LayoutInflater mInflater;


    public VideosAdapter(Context context, List<Video> videos) {
        super();
        this.videos = videos;
        this.mInflater = LayoutInflater.from(context);
    }

    @Override
    public int getCount() {
        return videos.size();
    }

    @Override
    public Object getItem(int position) {
        return videos.get(position);
    }
@Override
    public long getItemId(int position) {
        return position;
    }



    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder;          

        if(convertView == null){

            convertView = mInflater.inflate(R.layout.list_item_user_video, null);
            holder = new ViewHolder();  

            holder.title = (TextView) convertView.findViewById(R.id.userVideoTitleTextView); 
            holder.thumb = (UrlImageView) convertView.findViewById(R.id.userVideoThumbImageView);
            Video video = videos.get(position);
        holder.title.setText(video.getTitle());
        holder.thumb.setImageDrawable(video.getThumbUrl());
            convertView.setTag(holder);
        }

        else {
            holder = (ViewHolder) convertView.getTag();
        }





    return convertView;
    }
    static class ViewHolder{
        UrlImageView thumb;
        TextView title;
        Video video;
        int id;
    }
}

UrlImageView.java

  public class UrlImageView extends LinearLayout {

        private Context mContext;
        private Drawable mDrawable;
        private ProgressBar mSpinner;
        private ImageView mImage;


        public UrlImageView(Context context, AttributeSet attrs) {
            super(context, attrs);
            init(context);
        }

        public UrlImageView(Context context) {
            super(context);
            init(context);
        }


        private void init(final Context context) {
            mContext = context;

            mImage = new ImageView(mContext);
            mImage.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
            mImage.setVisibility(View.GONE);

            mSpinner = new ProgressBar(mContext);
            mSpinner.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));

            mSpinner.setIndeterminate(true);

            addView(mSpinner);
            addView(mImage);
        }


        public void setImageDrawable(final String url) {
            mDrawable = null;
            mSpinner.setVisibility(View.VISIBLE);
            mImage.setVisibility(View.GONE);
            new Thread() {
                public void run() {
                    try {
                        mDrawable = getDrawableFromUrl(url);
                        imageLoadedHandler.sendEmptyMessage(RESULT_OK);
                    } catch (MalformedURLException e) {
                        imageLoadedHandler.sendEmptyMessage(RESULT_CANCELED);
                    } catch (IOException e) {
                        imageLoadedHandler.sendEmptyMessage(RESULT_CANCELED);
                    }

                };
            }.start();
        }


        private final Handler imageLoadedHandler = new Handler(new Callback() {
            @Override
            public boolean handleMessage(Message msg) {
                switch (msg.what) {
                case RESULT_OK:
                    mImage.setImageDrawable(mDrawable);
                    mImage.setVisibility(View.VISIBLE);
                    mSpinner.setVisibility(View.GONE);
                    break;
                case RESULT_CANCELED:
                default:
                    // Could change image here to a 'failed' image
                    // otherwise will just keep on spinning
                    break;
                }
                return true;
            }
        });


        private static Drawable getDrawableFromUrl(final String url) throws IOException, MalformedURLException {

            return Drawable.createFromStream(((InputStream) new URL(url).getContent()), "name");
        }


    }

list_item_user_video.xml

<?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:gravity="center_vertical"
        android:orientation="horizontal" >


        <com.example.example.ui.widget.UrlImageView
            android:id="@+id/userVideoThumbImageView"
            android:layout_width="60dp"
            android:layout_height="45dp"
            android:layout_marginRight="10dp"
            android:contentDescription="YouTube video thumbnail"
            android:src="@drawable/ic_launcher"/>

        <TextView
            android:id="@+id/userVideoTitleTextView"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:text="Video Title Not Found" />

    </LinearLayout>
like image 606
androphone Avatar asked Jan 31 '26 11:01

androphone


2 Answers

Move the following lines from if/else in VideosAdapter's getView() method

holder.title.setText(video.getTitle());
holder.thumb.setImageDrawable(video.getThumbUrl());

to just above

return convertView;
like image 195
Haris ur Rehman Avatar answered Feb 02 '26 00:02

Haris ur Rehman


You're not modifying existing views. If convertView is not null that means Android is recycling the view instead of inflating it, but you still have to update it with the new values. Something like this will work:

public View getView(int position, View convertView, ViewGroup parent) {
    ViewHolder holder;          

    if(convertView == null) {
        convertView = mInflater.inflate(R.layout.list_item_user_video, null);
        holder = new ViewHolder();  
    }

    else {
        holder = (ViewHolder) convertView.getTag();
    }

    holder.title = (TextView) convertView.findViewById(R.id.userVideoTitleTextView); 
    holder.thumb = (UrlImageView) convertView.findViewById(R.id.userVideoThumbImageView);
    Video video = videos.get(position);
    holder.title.setText(video.getTitle());
    holder.thumb.setImageDrawable(video.getThumbUrl());

    convertView.setTag(holder);

    return convertView;

}

P.S. Use Ctrl+Shift+F to format your code nicely. :)

like image 41
Oleg Vaskevich Avatar answered Feb 02 '26 00:02

Oleg Vaskevich



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!