Asynchronous image loader on listview [Android] - java

I'm having problems implementing an asynchronous image loader to the following code. I read some posts around the web about it and I think I understand the logic behind it, but I seem to fail in implementing it.
The code bellow is what I use to simply load the images in my listview.
public class MyCustomAdapter extends ArrayAdapter<RSSItem> {
Bitmap bm;
public MyCustomAdapter(Context context, int textViewResourceId, List<RSSItem> list) {
super(context, textViewResourceId, list);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
BitmapFactory.Options bmOptions;
bmOptions = new BitmapFactory.Options();
bmOptions.inSampleSize = 1;
bm = LoadImage(myRssFeed.getList().get(position).getDescription(), bmOptions);
View row = convertView;
if(row == null) {
LayoutInflater inflater = getLayoutInflater();
row = inflater.inflate(R.layout.rsslist, parent, false);
}
TextView listTitle = (TextView)row.findViewById(R.id.listtitle);
listTitle.setText(myRssFeed.getList().get(position).getTitle());
ImageView listDescription = (ImageView)row.findViewById(R.id.listdescription);
listDescription.setImageBitmap(bm);
TextView listPubdate = (TextView)row.findViewById(R.id.listpubdate);
listPubdate.setText(myRssFeed.getList().get(position).getPubdate());
return row;
}
}

You may use my sample code as reference Lazy load of images in ListView

Have you looked SmartImageView?
http://loopj.com/android-smart-image-view/
It's very simple library to load images asynchronously (:
some Features of this library
Drop-in replacement for ImageView
Load images from a URL
Load images from the phone’s contact address book
Asynchronous loading of images, loading happens outside the UI thread
Images are cached to memory and to disk for super fast loading
SmartImage class is easily extendable to load from other sources

On solution would be to populate a class variable within your adapter, say, an ArrayList with the references all the "ImageView listDescription"
ArrayList<ImageView> allImageViews = new ArrayList<ImageView>();
...
public View getView(int position, View convertView, ViewGroup parent){
...
ImageView listDescription=(ImageView)row.findViewById(R.id.listdescription);
allImageViews.add(listDescription);
...
}
private class ImageDownLoader extends AsyncTask<ArrayList, Void, Void>{
doInBackground(){
for(ImageView imageView: allImageViews){
BitmapFactory.Options bmOptions;
bmOptions = new BitmapFactory.Options();
bmOptions.inSampleSize = 1;
bm = LoadImage(imageNameOrWhatever, bmOptions);
imageView.setImageBitmap(bm);
}
}
Then use an AsyncTask that goes through each ImageView, retrieves the associated Image and removes the ImageView from the ArrayList. It will download one at a time in the background while your gui will still respond.

Related

Android Picasso does not load all image to imageview

I am trying to load images to imageview in my ListAdapter. However while I am passing 10 thumbnail images to listAdapter and set them in imageview, only 1 or none is visible in imageview. As I understand from docs, I dont need to use any asyntask, since picasso library has already working asyntask. Could you please help me how I can handle this issue?
// Calling CustumListAdapter like this;
CustomListAdapter customListAdapter = new CustomListAdapter(this, resultArrayList);
listView = (ListView) findViewById(R.id.listview_score);
listView.setAdapter(customListAdapter)
// And here is my CustomListAdapter class
public class CustomListAdapter extends ArrayAdapter<String> {
private ArrayList<String> resultContent;
//private Integer[] imageid;
private Activity context;
public CustomListAdapter(Activity context, ArrayList<String> resultContent) {
super(context, R.layout.activity_ident_result2, resultContent);
this.context = context;
this.resultContent = resultContent;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = context.getLayoutInflater();
View listViewItem = inflater.inflate(R.layout.activity_ident_result2, null, true);
if (position % 2 == 0) {
TextView textViewName = (TextView) listViewItem.findViewById(R.id.textView_score);
textViewName.setText(resultContent.get(position));
ImageView imageView = (ImageView) listViewItem.findViewById(R.id.imageView_score);
//imageView.setImageBitmap(IdentResultActivity.splittedBitmaps.get(position + 1));
Picasso.with(this.context).load(resultContent.get(position + 1)).into(imageView);
}
return listViewItem;
}
}
EDIT:
I used .placeholder(R.drawble.progress) and I can see one image placed without problem, rest are progress.png
EDIT2:
Here is my imageView xml file;
<ImageView
android:layout_width="75dp"
android:layout_height="75dp"
android:id="#+id/imageView_score" />
I believe the parameters of inflater.inflate should be (R.layout.activity_ident_result2, parent, false)
U need to create loop for adding every image to [] and then u need to show it. Becouse of ur posted code u adding just one image.

Mismatched images in table cells with Picasso Library

I'm trying to fix an issues that I've seen previously and fixed on iOS, but am unable to fix on android. In iOS, I used the SDWebImage library to download and cache images. However, when scrolling through a long list of cells, the images would come up in the wrong cells. I was able ot fix this by doing the following:
#property (weak) id <SDWebImageOperation> imageOperation;
...
- (void)setFriend:(TAGUser *)friend {
...
self.imageOperation = [[SDWebImageManager sharedManager] downloadWithURL:[NSURL URLWithString:friend.profileImageUrl] options:SDWebImageRetryFailed
progress:^(NSInteger receivedSize, NSInteger expectedSize) {
} completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished) {
if(!error) {
self.profileImageView.image = image;
}
}];
...
}
- (void)prepareForReuse {
[super prepareForReuse];
if (self.imageOperation) {
[self.imageOperation cancel];
}
self.imageOperation = nil;
}
On Android, I am using the Picaso Libray and trying to achieve the same result like so:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View vi = convertView;
if (vi == null) {
vi = inflater.inflate(R.layout.friend_row, parent, false);
ViewHolder holder = new ViewHolder();
holder.friendImage = (ImageView) vi.findViewById(R.id.friend_image);
}
final ViewHolder holder = (ViewHolder) vi.getTag(); //Bad naming convention in my project I know, but it's a built-in method
//THIS SHOULD IN THEORY CANCEL THE REQUEST OF THE OLD FRIEND URL
Picasso.with(mActivity.getBaseContext()).cancelRequest(holder.friendImage);
holder.friendImage.setImageDrawable(mActivity.getResources().getDrawable(R.drawable.background_circle));
final TagUser user = (TagUser) getItem(position);
Picasso.with(mActivity.getBaseContext()).load(user.getProfileUrl()).transform(new RoundedTransformation(ViewUtility.convertPxToDp(mActivity, 23), 0)).fit().into(holder.friendImage,
new Callback() {
#Override
public void onSuccess() {
holder.friendInitials.setVisibility(View.INVISIBLE);
}
#Override
public void onError() {
holder.friendInitials.setVisibility(View.VISIBLE);
}
});
}
Even with cancelRequeset getting called, the profile images are still getting mismatched. Any help would be greatly appreciated!
You don't need to call cancel. Picasso automatically sees when views are being re-used and will cancel old downloads for that image view.
I would also recommend using Picasso's .placeholder API for the background circle.
You seem to be missing a call to setTag when the layout is inflated. Hopefully that's just an error in copying to the post.
Lastly, create the RoundedTransformation once and re-use the same instance for all calls to Picasso.
In the end your code should look like this:
private final Transformation roundTransform;
// Set the following in constructor:
// roundTransform = new RoundedTransformation(ViewUtility.convertPxToDp(mActivity, 23), 0)
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View vi = convertView;
if (vi == null) {
vi = inflater.inflate(R.layout.friend_row, parent, false);
ViewHolder holder = new ViewHolder();
vi.setTag(holder)
holder.friendImage = (ImageView) vi.findViewById(R.id.friend_image);
}
final ViewHolder holder = (ViewHolder) vi.getTag(); //Bad naming convention in my project I know, but it's a built-in method
final TagUser user = (TagUser) getItem(position);
Picasso.with(mActivity)
.load(user.getProfileUrl())
.placeholder(R.drawable.background_circle)
.transform(roundTransform)
.fit()
.into(holder.friendImage,
new Callback() {
#Override
public void onSuccess() {
holder.friendInitials.setVisibility(View.INVISIBLE);
}
#Override
public void onError() {
holder.friendInitials.setVisibility(View.VISIBLE);
}
});
}
I would advice to use Volley by Google. I have used it in many projects and it never gave mismatched results even in case I had nearly 1000 images in 3 column gridView. Volley

I need to add a imageview or webview in my listview

I got a problem. I got some code which I'm not going to put all here because it's to big. But I got a listview. And i do it like this:
lv = (ListView) findViewById(R.id.list);
(Here is normally some asynctask code and stuff)
// list adapter
ListAdapter adapter = new SimpleAdapter(MainActivity.this, placesListItems,
R.layout.list_item, new String[] { KEY_REFERENCE, KEY_NAME, KEY_VICINITY, KEY_DISTANCE,
KEY_LOCATION}, new int[] { R.id.reference, R.id.name, R.id.vicinity, R.id.radius, R.id.location});
// Adding data into listview
lv.setAdapter(adapter);
Now the thing is I got an url and the only thing on the site is an image. It's from Google Place Photos. Now I want an image in my listview. So in every item there is another image.
I can do it with an imageview or with a webview.
So let's sey the url is stored in this:
KEY_URL;
And the imageview or webview is this:
R.id.image;
How can I do this?
Thanks in advance!!
At first,
WebView takes more memory than ImageView.
So I recommend you to use ImageView.
At Second,
Check out following URLs.
Lazy load of images in ListView
In this article,
The first library, which I have used, is small and customizable library.
It uses thread pool and seems to control transfers.
The second library, which I haven't used, is larger.
But more methods in this library seem to make it easy to control various configurations.
Finally,
I think you should create your own Adapter, extending SimpleAdapter(or CursorAdapter, or…).
like following pseudo code.
public class MySimpleAdapter extends SimpleAdapter {
private ImageLoader mImageLoader;
private int mResource;
private LayoutInflater inflater;
public static class ViewHolder {
public ImageView img;
public TextView txt;
}
public MySimpleAdapter(Context context, List<? extends Map<String, ?>> data, int resource, String[] from, int[] to) {
super(context, data, resource, from, to);
mResource = resource;
mImageLoader = new ImageLoader(context);
inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = inflater.inflate(R.layout.cell_text, null);
holder = new ViewHolder();
holder.txt = (TextView) convertView.findViewById(R.id.txt);
holder.img = (ImageView) convertView.findViewById(R.id.img);
convertView.setTag(holder);
}
else {
holder = (ViewHolder) convertView.getTag();
}
holder.txt.setText("something text");
mImageLoader.displayImage("url", holder.img);
return convertView;
}
}
You Can use [androidQuery]https://code.google.com/p/android-query/
It has a thread pool. It load images in different ways. Has the option to down sample images to save memory. Made by google :)

Set list view height without TextView with adapter

I have a ListView which is supposed to become a menu with two drawables and two text views per row.
Activity Code:
ArrayList<MenuItem> itemArray = new ArrayList<MenuItem>();
itemArray.add(new MenuItem("Headertexxt", "subbtexdt"));
itemArray.add(new MenuItem("asf", "asf"));
ListView listView = (ListView) findViewById(R.id.listViewCM);
String[] array = getResources().getStringArray(R.array.buttonsCM);
int[] images = new int[] { R.drawable.btn_car, R.drawable.btn_star, R.drawable.btn_bag};
listView.setAdapter(new HomeScreenButtonsAdapterSubtext(this, R.layout.row,
itemArray, images, R.drawable.list_arrow));
Utils.setListViewHeightBasedOnChildren(listView);
listView.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
switch (position) {
case 0:
findViewById(R.id.buttonCreditCompilation).performClick();
break;
case 1:
findViewById(R.id.buttonYourCredits).performClick();
break;
}
}
});
Adapter code:
public class HomeScreenButtonsAdapterSubtext extends ArrayAdapter<MenuItem> {
private Drawable[] drawables;
private Drawable arrowDrawable;
private ArrayList<MenuItem> items;
public HomeScreenButtonsAdapterSubtext(Context context, int resourceId,
ArrayList<MenuItem> items, int[] images, int arrowImage) {
super(context, resourceId, items);
this.items = items;
Resources resources = context.getResources();
if (images != null) {
drawables = new Drawable[images.length];
int i = 0;
for (int id : images) {
Drawable drawable = resources.getDrawable(id);
drawable.setBounds(0, 0, drawable.getIntrinsicWidth(),
drawable.getIntrinsicHeight());
drawables[i++] = drawable;
}
}
arrowDrawable = resources.getDrawable(arrowImage);
arrowDrawable.setBounds(0, 0, arrowDrawable.getIntrinsicWidth(),
arrowDrawable.getIntrinsicHeight());
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = super.getView(position, convertView, parent);
if (v instanceof TextView) {
Drawable dr = drawables != null ? drawables[position %
drawables.length] : null;
((TextView) v).setCompoundDrawables(dr, null, arrowDrawable, null);
Utils.setFont((TextView) v);
}
// View v = convertView;
if (v == null) {
LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.row, null);
}
MenuItem station = items.get(position);
if (station != null) {
TextView tt = (TextView) v.findViewById(R.id.headerText);
TextView bt = (TextView) v.findViewById(R.id.subText);
if (tt != null) {
tt.setText(station.getHeaderText());
}
if (bt != null) {
bt.setText(station.getSubText());
}
}
return v;
}
The problem I have right now is that I can't set the listview height based on the children. I'm trying to do that here: Utils.setListViewHeightBasedOnChildren(listView); but getting the error: arrayadapter requires the resource id to be a textview at this row. Does anyone know a solution for this?
Can I use some other method for setting the ListView height?
Thanks
but getting the error: arrayadapter requires the resource id to be a
textview at this row.
R.layout.row is a layout file which it doesn't have just a TextView. If you call the super constructor you have used and you also call the super.getView(in the getView method) method in the adapter, then ArrayAdapter will complain as it expects a single widget in the layout file passed to it(a single TextView).
I don't understand why you have that piece of code in the getView method(with the super call) when you know precisely that the row can't be an instance of Textview .
I'm not sure about setting the height of the ListView either, if you're trying to show all the rows of the ListView, don't do it(as you make the ListView basically useless). If you still want to do this, then it's better to lose the ListView and build the row layouts manually.
In fact it does not really make sense to set the height of ListView depending on its content.
Because the whole point of a ListView is to make its content scrollable (however big it is)...so it is supposed to have a fixed height.

Bitmap in listview doesn't work [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How do I do a lazy load of images in ListView
i have listview with bitmap and text. When i download picture and i want to view it, it not appears in my app. When i used image from R.drawable.imagename then it works...
My code:
List<HashMap<String, Object> > aList = new ArrayList<HashMap<String, Object> >();
for(int i=0;i<ilosctalentow.size();i++){
if (ilosctalentow.get(i).indexOf("0/")==-1)
{
HashMap<String, Object> hm = new HashMap<String,Object>();
hm.put("txt", "xxx");
hm.put("cur","Currency : " + ilosctalentow.get(i));
Bitmap bmp = DownloadImage("http://www.xxx.pl/xxx/xxx/xhxuxj.png");
hm.put("flag",bmp);
aList.add(hm);
Log.i(TAG,Integer.toString(R.drawable.afghanistan) );
}
}
// Keys used in Hashmap
String[] from = { "flag","txt","cur" };
// Ids of views in listview_layout
int[] to = { R.id.flag,R.id.txt,R.id.cur};
// Instantiating an adapter to store each items
// R.layout.listview_layout defines the layout of each item
SimpleAdapter adapter = new SimpleAdapter(getBaseContext(), aList, R.layout.listview_layout, from, to);
// Getting a reference to listview of main.xml layout file
ListView listView = ( ListView ) findViewById(R.id.listview);
// Setting the adapter to the listView Zaraz mnie huj strzeli
listView.setAdapter(adapter);
Please help!
I think I can post a link to another question as an answer and explain how to apply it to your current solution.
Lazy load of images in ListView
When your application starts, display a simple list without images. Then start a background thread which downloads and creates bitmaps. When the thread completes its job - update the list so that it displays loaded images.
To make this work, you should create a custom adapter. Take the DrawableManager class from this answer (because the class from the accepted answer contains some bugs) and write the adapter like this:
// You should create your own class instead of TestItem
public class TestAdapter extends ArrayAdapter<TestItem> {
private final LayoutInflater mInflater;
private final DrawableBackgroundDownloader mDrawableBackgroundDownloader = new DrawableBackgroundDownloader();
public TestAdapter(Context context, List<TestItem> objects) {
super(context, -1, objects);
mInflater = LayoutInflater.from(context);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
final TestItem item = this.getItem(position);
View view = convertView == null
? mInflater.inflate(R.layout.listview_layout, null)
: convertView;
TextView txtView = (TextView) view.findViewById(R.id.txt);
TextView curView = (TextView) view.findViewById(R.id.cur);
ImageView flagView = (ImageView) view.findViewById(R.id.flag);
txtView.setText(item.getText());
curView.setText(item.getCurrency());
mDrawableBackgroundDownloader.loadDrawable(item.getFlagUrl(), flagView, null);
return view;
}
}
This adapter can be improved by storing found elements in a view bag or using different class for downloading and caching of images. But I will leave it as it is for the sake of simplicity.

Categories