Use ViewHolder pattern on all list view adapters

This commit is contained in:
Joshua Bahnsen 2014-01-23 01:50:49 -07:00
parent f6313d3008
commit bc114521c4
10 changed files with 249 additions and 119 deletions

View File

@ -223,7 +223,7 @@ public class ImageLoader implements Runnable
}
}
private void setUnknownImage(View view, boolean large)
public void setUnknownImage(View view, boolean large)
{
if (large)
{

View File

@ -40,25 +40,21 @@ import com.thejoshwa.ultrasonic.androidapp.util.Util;
*/
public class AlbumView extends UpdateView
{
private static final String TAG = AlbumView.class.getSimpleName();
private static Drawable starDrawable;
private static Drawable starHollowDrawable;
private static String theme;
private TextView titleView;
private TextView artistView;
private View coverArtView;
private ImageView starImageView;
private Context context;
private MusicDirectory.Entry entry;
private EntryAdapter.AlbumViewHolder viewHolder;
private ImageLoader imageLoader;
public AlbumView(Context context)
public AlbumView(Context context, ImageLoader imageLoader)
{
super(context);
this.context = context;
LayoutInflater.from(context).inflate(R.layout.album_list_item, this, true);
this.imageLoader = imageLoader;
String theme = Util.getTheme(context);
boolean themesMatch = theme.equals(AlbumView.theme);
@ -73,11 +69,24 @@ public class AlbumView extends UpdateView
{
starDrawable = Util.getDrawableFromAttribute(context, R.attr.star_full);
}
}
titleView = (TextView) findViewById(R.id.album_title);
artistView = (TextView) findViewById(R.id.album_artist);
coverArtView = findViewById(R.id.album_coverart);
starImageView = (ImageView) findViewById(R.id.album_star);
public void setLayout()
{
LayoutInflater.from(context).inflate(R.layout.album_list_item, this, true);
viewHolder = new EntryAdapter.AlbumViewHolder();
viewHolder.title = (TextView) findViewById(R.id.album_title);
viewHolder.artist = (TextView) findViewById(R.id.album_artist);
viewHolder.cover_art = (ImageView) findViewById(R.id.album_coverart);
viewHolder.star = (ImageView) findViewById(R.id.album_star);
setTag(viewHolder);
}
public void setViewHolder(EntryAdapter.AlbumViewHolder viewHolder)
{
this.viewHolder = viewHolder;
this.viewHolder.cover_art.invalidate();
setTag(this.viewHolder);
}
public MusicDirectory.Entry getEntry()
@ -85,7 +94,7 @@ public class AlbumView extends UpdateView
return this.entry;
}
public void setAlbum(final MusicDirectory.Entry album, ImageLoader imageLoader)
public void setAlbum(final MusicDirectory.Entry album)
{
this.entry = album;
@ -93,19 +102,19 @@ public class AlbumView extends UpdateView
String artist = album.getArtist();
boolean starred = album.getStarred();
titleView.setText(title);
artistView.setText(artist);
artistView.setVisibility(artist == null ? View.GONE : View.VISIBLE);
starImageView.setImageDrawable(starred ? starDrawable : starHollowDrawable);
imageLoader.loadImage(this.coverArtView, album, false, 0, false, true);
viewHolder.title.setText(title);
viewHolder.artist.setText(artist);
viewHolder.artist.setVisibility(artist == null ? View.GONE : View.VISIBLE);
viewHolder.star.setImageDrawable(starred ? starDrawable : starHollowDrawable);
imageLoader.loadImage(viewHolder.cover_art, album, false, 0, false, true);
if (Util.isOffline(this.context) || "-1".equals(album.getId()))
{
starImageView.setVisibility(View.GONE);
viewHolder.star.setVisibility(View.GONE);
}
else
{
starImageView.setOnClickListener(new View.OnClickListener()
viewHolder.star.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View view)
@ -115,12 +124,12 @@ public class AlbumView extends UpdateView
if (!isStarred)
{
starImageView.setImageDrawable(starDrawable);
viewHolder.star.setImageDrawable(starDrawable);
album.setStarred(true);
}
else
{
starImageView.setImageDrawable(starHollowDrawable);
viewHolder.star.setImageDrawable(starHollowDrawable);
album.setStarred(false);
}

View File

@ -58,36 +58,18 @@ public class ChatAdapter extends ArrayAdapter<ChatMessage>
if (convertView == null)
{
holder = new ViewHolder();
holder.layout = layout;
convertView = LayoutInflater.from(activity).inflate(holder.layout, parent, false);
TextView usernameView;
TextView timeView;
TextView messageView;
if (convertView != null)
{
usernameView = (TextView) convertView.findViewById(R.id.chat_username);
timeView = (TextView) convertView.findViewById(R.id.chat_time);
messageView = (TextView) convertView.findViewById(R.id.chat_message);
messageView.setMovementMethod(LinkMovementMethod.getInstance());
Linkify.addLinks(messageView, Linkify.EMAIL_ADDRESSES);
Linkify.addLinks(messageView, Linkify.WEB_URLS);
Linkify.addLinks(messageView, phoneMatcher, "tel:");
holder.message = messageView;
holder.username = usernameView;
holder.time = timeView;
convertView.setTag(holder);
}
convertView = inflateView(layout, parent);
holder = createViewHolder(layout, convertView);
}
else
{
holder = (ViewHolder) convertView.getTag();
if (holder.layout != layout)
{
convertView = inflateView(layout, parent);
holder = createViewHolder(layout, convertView);
}
}
DateFormat timeFormat = android.text.format.DateFormat.getTimeFormat(activity);
@ -100,6 +82,41 @@ public class ChatAdapter extends ArrayAdapter<ChatMessage>
return convertView;
}
private View inflateView(int layout, ViewGroup parent)
{
return LayoutInflater.from(activity).inflate(layout, parent, false);
}
private static ViewHolder createViewHolder(int layout, View convertView)
{
ViewHolder holder = new ViewHolder();
holder.layout = layout;
TextView usernameView;
TextView timeView;
TextView messageView;
if (convertView != null)
{
usernameView = (TextView) convertView.findViewById(R.id.chat_username);
timeView = (TextView) convertView.findViewById(R.id.chat_time);
messageView = (TextView) convertView.findViewById(R.id.chat_message);
messageView.setMovementMethod(LinkMovementMethod.getInstance());
Linkify.addLinks(messageView, Linkify.EMAIL_ADDRESSES);
Linkify.addLinks(messageView, Linkify.WEB_URLS);
Linkify.addLinks(messageView, phoneMatcher, "tel:");
holder.message = messageView;
holder.username = usernameView;
holder.time = timeView;
convertView.setTag(holder);
}
return holder;
}
private static class ViewHolder
{
int layout;

View File

@ -21,6 +21,9 @@ package com.thejoshwa.ultrasonic.androidapp.view;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.CheckedTextView;
import android.widget.ImageView;
import android.widget.TextView;
import com.thejoshwa.ultrasonic.androidapp.activity.SubsonicTabActivity;
import com.thejoshwa.ultrasonic.androidapp.domain.MusicDirectory.Entry;
@ -58,22 +61,25 @@ public class EntryAdapter extends ArrayAdapter<Entry>
if (convertView != null && convertView instanceof AlbumView)
{
AlbumView currentView = (AlbumView) convertView;
if (currentView.getEntry().equals(entry))
{
currentView.update();
return currentView;
}
else
{
view = new AlbumView(activity);
AlbumViewHolder viewHolder = (AlbumViewHolder) currentView.getTag();
view = currentView;
view.setViewHolder(viewHolder);
}
}
else
{
view = new AlbumView(activity);
view = new AlbumView(activity, imageLoader);
view.setLayout();
}
view.setAlbum(entry, imageLoader);
view.setAlbum(entry);
return view;
}
else
@ -83,6 +89,7 @@ public class EntryAdapter extends ArrayAdapter<Entry>
if (convertView != null && convertView instanceof SongView)
{
SongView currentView = (SongView) convertView;
if (currentView.getEntry().equals(entry))
{
currentView.update();
@ -90,16 +97,39 @@ public class EntryAdapter extends ArrayAdapter<Entry>
}
else
{
view = new SongView(activity);
SongViewHolder viewHolder = (SongViewHolder) convertView.getTag();
view = currentView;
view.setViewHolder(viewHolder);
}
}
else
{
view = new SongView(activity);
view.setLayout(entry);
}
view.setSong(entry, checkable, false);
return view;
}
}
public static class SongViewHolder
{
CheckedTextView check;
TextView track;
TextView title;
TextView status;
TextView artist;
TextView duration;
ImageView star;
ImageView drag;
}
public static class AlbumViewHolder
{
TextView artist;
ImageView cover_art;
ImageView star;
TextView title;
}
}

View File

@ -3,6 +3,7 @@ package com.thejoshwa.ultrasonic.androidapp.view;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;
import com.thejoshwa.ultrasonic.androidapp.R;
import com.thejoshwa.ultrasonic.androidapp.activity.SubsonicTabActivity;
@ -32,7 +33,21 @@ public class PlaylistAdapter extends ArrayAdapter<Playlist>
{
Playlist entry = getItem(position);
PlaylistView view;
view = convertView != null && convertView instanceof PlaylistView ? (PlaylistView) convertView : new PlaylistView(activity);
if (convertView != null && convertView instanceof PlaylistView)
{
PlaylistView currentView = (PlaylistView) convertView;
ViewHolder viewHolder = (ViewHolder) convertView.getTag();
view = currentView;
view.setViewHolder(viewHolder);
}
else
{
view = new PlaylistView(activity);
view.setLayout();
}
view.setPlaylist(entry);
return view;
}
@ -52,6 +67,10 @@ public class PlaylistAdapter extends ArrayAdapter<Playlist>
Collections.sort(playlists, new PlaylistComparator());
return playlists;
}
}
static class ViewHolder
{
TextView name;
}
}

View File

@ -32,19 +32,32 @@ import com.thejoshwa.ultrasonic.androidapp.domain.Playlist;
*/
public class PlaylistView extends UpdateView
{
private TextView titleView;
private Context context;
private PlaylistAdapter.ViewHolder viewHolder;
public PlaylistView(Context context)
{
super(context);
LayoutInflater.from(context).inflate(R.layout.playlist_list_item, this, true);
this.context = context;
}
titleView = (TextView) findViewById(R.id.playlist_name);
public void setLayout()
{
LayoutInflater.from(context).inflate(R.layout.playlist_list_item, this, true);
viewHolder = new PlaylistAdapter.ViewHolder();
viewHolder.name = (TextView) findViewById(R.id.playlist_name);
setTag(viewHolder);
}
public void setViewHolder(PlaylistAdapter.ViewHolder viewHolder)
{
this.viewHolder = viewHolder;
setTag(this.viewHolder);
}
public void setPlaylist(Playlist playlist)
{
titleView.setText(playlist.getName());
viewHolder.name.setText(playlist.getName());
update();
}
}

View File

@ -3,6 +3,7 @@ package com.thejoshwa.ultrasonic.androidapp.view;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;
import com.thejoshwa.ultrasonic.androidapp.R;
import com.thejoshwa.ultrasonic.androidapp.activity.SubsonicTabActivity;
@ -32,7 +33,21 @@ public class ShareAdapter extends ArrayAdapter<Share>
{
Share entry = getItem(position);
ShareView view;
view = convertView != null && convertView instanceof ShareView ? (ShareView) convertView : new ShareView(activity);
if (convertView != null && convertView instanceof ShareView)
{
ShareView currentView = (ShareView) convertView;
ViewHolder viewHolder = (ViewHolder) convertView.getTag();
view = currentView;
view.setViewHolder(viewHolder);
}
else
{
view = new ShareView(activity);
view.setLayout();
}
view.setShare(entry);
return view;
}
@ -52,6 +67,11 @@ public class ShareAdapter extends ArrayAdapter<Share>
Collections.sort(shares, new ShareComparator());
return shares;
}
}
static class ViewHolder
{
TextView url;
TextView description;
}
}

View File

@ -28,26 +28,38 @@ import com.thejoshwa.ultrasonic.androidapp.domain.Share;
/**
* Used to display playlists in a {@code ListView}.
*
* @author Sindre Mehus
* @author Joshua Bahnsen
*/
public class ShareView extends UpdateView
{
private TextView titleView;
private TextView descriptionView;
private Context context;
private ShareAdapter.ViewHolder viewHolder;
public ShareView(Context context)
{
super(context);
LayoutInflater.from(context).inflate(R.layout.share_list_item, this, true);
this.context = context;
}
titleView = (TextView) findViewById(R.id.share_url);
descriptionView = (TextView) findViewById(R.id.share_description);
public void setLayout()
{
LayoutInflater.from(context).inflate(R.layout.share_list_item, this, true);
viewHolder = new ShareAdapter.ViewHolder();
viewHolder.url = (TextView) findViewById(R.id.share_url);
viewHolder.description = (TextView) findViewById(R.id.share_description);
setTag(viewHolder);
}
public void setViewHolder(ShareAdapter.ViewHolder viewHolder)
{
this.viewHolder = viewHolder;
setTag(this.viewHolder);
}
public void setShare(Share share)
{
titleView.setText(share.getName());
descriptionView.setText(share.getDescription());
viewHolder.url.setText(share.getName());
viewHolder.description.setText(share.getDescription());
update();
}
}

View File

@ -38,12 +38,15 @@ public class SongListAdapter extends ArrayAdapter<DownloadFile>
}
else
{
view = new SongView(this.context);
EntryAdapter.SongViewHolder viewHolder = (EntryAdapter.SongViewHolder) convertView.getTag();
view = currentView;
view.setViewHolder(viewHolder);
}
}
else
{
view = new SongView(this.context);
view.setLayout(entry);
}
view.setSong(entry, false, true);

View File

@ -59,10 +59,6 @@ public class SongView extends UpdateView implements Checkable
private static String theme;
private static LayoutInflater inflater;
private CheckedTextView checkedTextView;
private ImageView starImageView;
private TextView titleTextView;
private TextView statusTextView;
private Entry song;
private Context context;
private Drawable leftImage;
@ -74,6 +70,7 @@ public class SongView extends UpdateView implements Checkable
private DownloadService downloadService;
private DownloadFile downloadFile;
private boolean playing;
private EntryAdapter.SongViewHolder viewHolder;
public SongView(Context context)
{
@ -120,12 +117,33 @@ public class SongView extends UpdateView implements Checkable
}
}
public void setLayout(final Entry song)
{
inflater.inflate(song.isVideo() ? R.layout.video_list_item : R.layout.song_list_item, this, true);
viewHolder = new EntryAdapter.SongViewHolder();
viewHolder.check = (CheckedTextView) findViewById(R.id.song_check);
viewHolder.star = (ImageView) findViewById(R.id.song_star);
viewHolder.drag = (ImageView) findViewById(R.id.song_drag);
viewHolder.track = (TextView) findViewById(R.id.song_track);
viewHolder.title = (TextView) findViewById(R.id.song_title);
viewHolder.artist = (TextView) findViewById(R.id.song_artist);
viewHolder.duration = (TextView) findViewById(R.id.song_duration);
viewHolder.status = (TextView) findViewById(R.id.song_status);
setTag(viewHolder);
}
public void setViewHolder(EntryAdapter.SongViewHolder viewHolder)
{
this.viewHolder = viewHolder;
setTag(this.viewHolder);
}
public Entry getEntry()
{
return this.song;
}
protected void setSong(final Entry song, boolean checkable, boolean dragable)
protected void setSong(final Entry song, boolean checkable, boolean draggable)
{
updateBackground();
@ -136,17 +154,6 @@ public class SongView extends UpdateView implements Checkable
this.downloadFile = downloadService.forSong(song);
}
inflater.inflate(song.isVideo() ? R.layout.video_list_item : R.layout.song_list_item, this, true);
checkedTextView = (CheckedTextView) findViewById(R.id.song_check);
starImageView = (ImageView) findViewById(R.id.song_star);
ImageView songDragImageView = (ImageView) findViewById(R.id.song_drag);
TextView trackTextView = (TextView) findViewById(R.id.song_track);
titleTextView = (TextView) findViewById(R.id.song_title);
TextView artistTextView = (TextView) findViewById(R.id.song_artist);
TextView durationTextView = (TextView) findViewById(R.id.song_duration);
statusTextView = (TextView) findViewById(R.id.song_status);
StringBuilder artist = new StringBuilder(60);
String bitRate = null;
@ -178,51 +185,51 @@ public class SongView extends UpdateView implements Checkable
int trackNumber = song.getTrack();
if (trackTextView != null)
if (viewHolder.track != null)
{
if (Util.shouldShowTrackNumber(this.context) && trackNumber != 0)
{
trackTextView.setText(String.format("%02d.", trackNumber));
viewHolder.track.setText(String.format("%02d.", trackNumber));
}
else
{
trackTextView.setVisibility(View.GONE);
viewHolder.track.setVisibility(View.GONE);
}
}
titleTextView.setText(song.getTitle());
viewHolder.title.setText(song.getTitle());
if (artistTextView != null)
if (viewHolder.artist != null)
{
artistTextView.setText(artist);
viewHolder.artist.setText(artist);
}
Integer duration = song.getDuration();
if (duration != null)
{
durationTextView.setText(Util.formatTotalDuration(duration));
viewHolder.duration.setText(Util.formatTotalDuration(duration));
}
if (checkedTextView != null)
if (viewHolder.check != null)
{
checkedTextView.setVisibility(checkable && !song.isVideo() ? View.VISIBLE : View.GONE);
viewHolder.check.setVisibility(checkable && !song.isVideo() ? View.VISIBLE : View.GONE);
}
if (songDragImageView != null)
if (viewHolder.drag != null)
{
songDragImageView.setVisibility(dragable ? View.VISIBLE : View.GONE);
viewHolder.drag.setVisibility(draggable ? View.VISIBLE : View.GONE);
}
if (Util.isOffline(this.context))
{
starImageView.setVisibility(View.GONE);
viewHolder.star.setVisibility(View.GONE);
}
else
{
starImageView.setImageDrawable(song.getStarred() ? starDrawable : starHollowDrawable);
viewHolder.star.setImageDrawable(song.getStarred() ? starDrawable : starHollowDrawable);
starImageView.setOnClickListener(new View.OnClickListener()
viewHolder.star.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View view)
@ -232,12 +239,12 @@ public class SongView extends UpdateView implements Checkable
if (!isStarred)
{
starImageView.setImageDrawable(starDrawable);
viewHolder.star.setImageDrawable(starDrawable);
song.setStarred(true);
}
else
{
starImageView.setImageDrawable(starHollowDrawable);
viewHolder.star.setImageDrawable(starHollowDrawable);
song.setStarred(false);
}
@ -312,9 +319,9 @@ public class SongView extends UpdateView implements Checkable
if (downloadFile.isDownloading() && !downloadFile.isDownloadCancelled() && partialFile.exists())
{
if (this.statusTextView != null)
if (this.viewHolder.status != null)
{
this.statusTextView.setText(Util.formatLocalizedBytes(partialFile.length(), this.context));
this.viewHolder.status.setText(Util.formatLocalizedBytes(partialFile.length(), this.context));
}
this.rightImageType = ImageType.downloading;
@ -325,13 +332,13 @@ public class SongView extends UpdateView implements Checkable
this.rightImageType = ImageType.none;
this.rightImage = null;
if (this.statusTextView != null)
if (this.viewHolder.status != null)
{
CharSequence statusText = this.statusTextView.getText();
CharSequence statusText = this.viewHolder.status.getText();
if (statusText != "" || statusText != null)
{
this.statusTextView.setText(null);
this.viewHolder.status.setText(null);
}
}
}
@ -341,9 +348,9 @@ public class SongView extends UpdateView implements Checkable
this.previousLeftImageType = leftImageType;
this.previousRightImageType = rightImageType;
if (this.statusTextView != null)
if (this.viewHolder.status != null)
{
this.statusTextView.setCompoundDrawablesWithIntrinsicBounds(leftImage, null, rightImage, null);
this.viewHolder.status.setCompoundDrawablesWithIntrinsicBounds(leftImage, null, rightImage, null);
if (rightImage == downloadingImage)
{
@ -355,21 +362,21 @@ public class SongView extends UpdateView implements Checkable
if (!song.getStarred())
{
if (starImageView != null)
if (viewHolder.star != null)
{
if (starImageView.getDrawable() != starHollowDrawable)
if (viewHolder.star.getDrawable() != starHollowDrawable)
{
starImageView.setImageDrawable(starHollowDrawable);
viewHolder.star.setImageDrawable(starHollowDrawable);
}
}
}
else
{
if (starImageView != null)
if (viewHolder.star != null)
{
if (starImageView.getDrawable() != starDrawable)
if (viewHolder.star.getDrawable() != starDrawable)
{
starImageView.setImageDrawable(starDrawable);
viewHolder.star.setImageDrawable(starDrawable);
}
}
}
@ -381,7 +388,7 @@ public class SongView extends UpdateView implements Checkable
if (!this.playing)
{
this.playing = true;
titleTextView.setCompoundDrawablesWithIntrinsicBounds(playingImage, null, null, null);
viewHolder.title.setCompoundDrawablesWithIntrinsicBounds(playingImage, null, null, null);
}
}
else
@ -389,7 +396,7 @@ public class SongView extends UpdateView implements Checkable
if (this.playing)
{
this.playing = false;
titleTextView.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
viewHolder.title.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
}
}
}
@ -397,19 +404,19 @@ public class SongView extends UpdateView implements Checkable
@Override
public void setChecked(boolean b)
{
checkedTextView.setChecked(b);
viewHolder.check.setChecked(b);
}
@Override
public boolean isChecked()
{
return checkedTextView.isChecked();
return viewHolder.check.isChecked();
}
@Override
public void toggle()
{
checkedTextView.toggle();
viewHolder.check.toggle();
}
public enum ImageType