Reputation: 7131
How do i set the images in this layout?
The ListView will contain 3 of the above entries, each image will be downloaded in an AsyncTask
(See Below) and the text will be filled in by a String array of preset Strings eg
String[] values = {"string one", "string two", "String three"};
I want to be able to first set the String content values of all 3 entries using the adapter below, then have AsyncTasks running in the background downloading and setting the icons for each entry.
The Strings are more important than the icons so i dont want the user to have to wait for each icon to download before the string is set.
I have a ListView Layout:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:paddingBottom="@dimen/small_8dp"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/small_8dp" >
<ImageView
android:id="@+id/logo"
android:layout_width="50dp"
android:layout_height="50dp"
android:contentDescription="@string/loading"
android:scaleType="fitXY"
android:src="@drawable/image" >
</ImageView>
<TextView
android:id="@+id/label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="@dimen/small_8dp"
android:text="@string/loading"
android:textSize="@dimen/medium_15dp" >
</TextView>
</LinearLayout>
Which is in a Layout:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/color_white"
android:orientation="vertical" >
<ListView
android:id="@android:id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:entries="@array/list_headlines">
</ListView>
</LinearLayout>
Ive been working with this custom adapter:
private class ArticleAdapter extends ArrayAdapter<String>{
private final Context context;
private final String[] values;
public ArticleAdapter(Context context, String[] values) {
super(context, R.layout.list_entry, values);
this.context=context;
this.values=values;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View rowView = inflater.inflate(R.layout.list_entry,parent,false);
TextView tv = (TextView) rowView.findViewById(R.id.label);
tv.setText(values[position]);
return rowView;
}
}
LoadThumbnail AsyncTask:
protected class LoadThumbnail extends AsyncTask<String, Void, String> {
private String url;
private boolean loaded; //if loaded set the bitmap image to whats downloaded
private Bitmap icon;
private int iconIndex;
public LoadThumbnail(int iconIndex, String url){
loaded = false;
this.url = url; //url of the icon to download
this.iconIndex=iconIndex; //Which icon in the listview were downloading
}
@Override
protected String doInBackground(String... params) {
Download download = new Download(url); //My Download Class
try {
icon = download.downloadImage(); //Returns A Bitmap image
loaded=true; //If no errors caught
} catch (Exceptions e) {
//Various Exception Handling Here
}
return null;
}
@Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
}
}
Can you tell me which functions i have to adapt to achieve this? Thanks!
Upvotes: 1
Views: 3982
Reputation: 2987
This answer is late but may be helpful for others.
In your code, if your AsyncTask<>
is located as separate class then you can simply instantiate it with giving it ImageView
in you adapter class, like
new LoadThumbnail(imageView).execute(url);
then in your LoadThumbnail
class simply set bitmap in imageView
.
i am writing this roughly, please make it as you want;
@Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View rowView = inflater.inflate(R.layout.list_entry,parent,false);
TextView tv = (TextView) rowView.findViewById(R.id.label);
ImageView imageView = (ImageView)rowView.findViewById(R.id.logo);
tv.setText(values[position]);
//Instantiate LoadThumbnail giving it imageView to set bitmap in.
new LoadThumbnail(imageView).execute(url);
return rowView;
}
Now in LoadThumbnail
simply set bitmap in onPostExecute()
method.
protected class LoadThumbnail extends AsyncTask<String, Void, Bitmap> {
private ImageView imageView;
public LoadThumbnail(ImageView imageView){
this.imageView = imageView;
}
@Override
protected String doInBackground(String... url) {
Bitmap icon = null;
Download download = new Download(url[0]); //My Download Class
try {
icon = download.downloadImage(); //Returns A Bitmap image
loaded=true; //If no errors caught
} catch (Exceptions e) {
//Various Exception Handling Here
}
return icon;
}
@Override
protected void onPostExecute(Bitmap icon) {
super.onPostExecute(icon);
//here set bitmap in imageView;
if(icon != null){
imageView.setImageBitmap(icon);
}
}
}
Upvotes: 0
Reputation: 873
In getView(), you should start a new task to download the image for that list item. Pass a reference of the ImageView you want populated to the AsyncTask, and then set the source for that ImageView to the downloaded bitmap (icon) in onPostExecute().
This does get a little complicated as you will have to deal with Views being recycled by the ListView (by cancelling the tasks to download the images). I like to use this library for all my downloading and caching of images: http://square.github.io/picasso/
Upvotes: 1
Reputation: 7663
The easiest way to do this is to download your images to some Collection
and then for the list to update when the downloads are complete by calling notifyDatasetChanged
on the Adapter
.
Before we get started - I don't know where your AsyncTask
is located. If its a separate class you need to use an Interface
to set up a call back to the place you're starting it from. If its an inner class within your Adaper
you can do this localy.
What you're going to do is set up your Adapter
to (1) check if the image you want is available (2) if not download the image and add it to a collection (3) when the image is downloaded refresh the list (or when all images are downloaded depening how long this list is).
This all happens when you set the content for a specific list item
if(logo != null){
if(imageCollection.contains(key){
logo.setImageBitmap(imageCollection.get(key));
} else {
thumbnailDownloader.execute;
}
}
If you're AsyncTask
is an inner class witin your adapater then within onPostExecute
you will (1) add the image to this collection (2) update the ListView
using notifyDatasetChanged
. If your AsyncTask
is it's own class you would add the image to the collction in your callback and update the list from there as well.
For the collection
it's easier if you use the LruCache
built into android but you could use a HashMap
or something else. Just depending on your implementation.
Upvotes: 2
Reputation: 2482
Firstly I'd suggest to give a reference of the ArticleAdapter
to the AsyncTask
.
Then create a Bitmap
array or map in ArticleAdapter
, and create an add(Bitmap bmp)
method for the ArticleAdapter, which puts a bitmap object into the array/map.
Because you have reference in the AsyncTask
, you can call the add() method in the onPostExecute()
method, with the downloaded icon Bitma
p.
Then you can call the ArticleAdapter
's notifyDataSetChanged()
, so it can refresh its views.
Of course your Adapter's getView
should check its bitmap array/map, if the bitmap for the given key is already downloaded. if it's reference is null, then put a placeholder, if it is downloaded already, place the bitmap which is put in the array/map by the asynctask.
Upvotes: 1