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>
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;
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. :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With