Reputation: 1789
I have a ListView
and I'm playing with Palette
from the support library. When on using BitmapFactory.decodeStream
to generate a bitmap from a url, this throws an exception (Network on UI thread) or possibly very expensive. How do I make this asynchronous? I couldn't think of any efficient way to do this. What's the best approach?
@Override
public View getView(int position, View convertView, ViewGroup viewGroup) {
final ViewHolder holder;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.item_grid, null);
holder = new ViewHolder();
holder.image = (ImageView) convertView.findViewById(R.id.img_photo);
holder.bg = (LinearLayout) convertView.findViewById(R.id.bg_title);
holder.text = (TextView) convertView.findViewById(R.id.txt_title);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
Picasso.with(mContext)
.load(mShows.get(position).poster)
.into(holder.image);
try {
URL url = new URL(mShows.get(position).poster);
Bitmap bitmap = BitmapFactory.decodeStream(
url.openConnection().getInputStream()); // Too expensive!!!
Palette palette = Palette.generate(bitmap);
holder.text.setText(mShows.get(position).title);
holder.text.setTextColor(palette.getVibrantColor().getRgb());
holder.bg.setAlpha(0.4f);
holder.bg.setBackgroundColor(palette.getDarkMutedColor().getRgb());
} catch (IOException e) {
e.printStackTrace();
}
return convertView;
}
Upvotes: 1
Views: 1277
Reputation: 2130
You could use Picasso's into(...)
with a Callback
parameter for when the image has successfully loaded:
Picasso.with(mContext)
.load(mShows.get(position).poster)
.into(holder.image, new Callback() {
@Override public void onSuccess() {
Bitmap bitmap = ((BitmapDrawable)holder.image.getDrawable()).getBitmap();
// do your processing here....
}
@Override public void onError() {
// reset your views to default colors, etc.
}
});
Upvotes: 5
Reputation: 1073
Try to do the network and bitmap decoding stuff in a work thread, and asynchronous notify back when you get the bitmap, and you also need a bitmap cache to avoid duplicate decoding work. A simple implementation is like this:
Interface IBitmapCache {
Bitmap get(String key);
put(String key, Bitmap map);
}
Class YourAdapter {
Class ViewHolder {
//your other views
//use url as key.
String url;
}
IBitmapCache mCache;
//you need to hold an instance of your listview here.
WeakReference<ListView> mAttachedListView;
View getView() {
//... handle other things
Bitmap bitmap = mCache.get(url);
if (bitmap == null) {
//retrieve bitmap asynchronous
}
}
//callback when bitmap is retrieved
void onBitmapRetrived(String url, Bitmap bitmap) {
if (mAttachedListView.get() != null) {
final ListView list = mAttachedListView.get();
final int count = list.getLastVisiblePosition() - list.getFirstVisiblePosition + 1;
for (int i = 0; i < count; i++) {
View v = lv.getChildAt(i);
if (v == null) {
continue;
}
ViewHolder holder = (ViewHolder) v.getTag();
if (url.equals(holder.url)) {
//do your Palette related things here.
break;
}
}
}
}
}
there are 2 more things you should do, put your decoded Bitmap to your bitmap cache, set a callback to your work thread and ensure that it is called on UI thread which can be easily implemented by Handler
.
Upvotes: 0