Setting up a loop in AsyncTask to retrieve the next iteration of a sequence
-
29-10-2019 - |
Question
I'm downloading several images and names from a Collection
and applying them in a GridView
. I've run into a few problems getting my AsyncTask
working correctly. I need to return two different values, an image and name, from one url. At the moment, I can correctly download everything and apply the info to my ImageView
and TextView
, but my method for doing this only works while I call it in my Adapter
.
Problem:
When I set up my AsyncTask
to download everything, it only applies the first value of the sequence to the Views
in my grid. When I log "artistImages", it prints out the other urls of the sequence an enormous number of times, I don't know why this happens, but none of the data from the urls is actually applied in my Adapter
.
What I've tried:
I've tried setting up a loop in doInBackground()
to run through my Iterator
n times.
I've tried using a Boolean
to stop my iterator before it applies the data from the first set in the sequence to all my Views
.
I've tried setting my up Adapter
in my AsyncTask
.
I've tried setting my a new AsyncTask
in my Adapter
, rather than creating a new class.
I've tried setting my ImageView
in onPostExecute()
and in my Adapter
.
I've tried using different parameters in my AsyncTask
.
I've tried setting up a AsyncTask
for my Views
, so that my Iterator
can run functionally and the images and name are applied asynchronously.
I've done a lot of research on stopping the loop or AsyncTask
at a certain point, setting up AsyncTaks
in a GridView
or with an Adapter
, and a lot more reading on Threads
, Handlers
, and AsyncTask
in general.
All of these attempts either result in only the first set of the sequence being used or nothing being downloaded and applied at all. So, I'm having a pretty difficult time using my Iterator
in my AsyncTask
.
This is the code I'm using to download the images and names. This works as long as I'm using it within the getView
method my Adapter
.
Used to download images and names:
i++;
artistImage = Artist.getSimilar("Bon Iver", i, key);
new ArrayList<Artist>();
itr = artistImage.iterator();
while (itr.hasNext()) {
Artist temp = itr.next();
artistImages = ((ImageHolder) temp).getImageURL(ImageSize.MEGA);
artistName = ((MusicEntry) temp).getName();
}
Just to show what everything is:
private Iterator<Artist> itr;
private Collection<Artist> artistImage;
private String artistImages = null;
private String artistName = null;
private int i = 0;
AsyncTask: I'm calling this in getView
of my Adapter
. new loadImages().execute()
public class loadImages extends AsyncTask<String, Integer, String> {
@Override
protected String doInBackground(String... params) {
try {
Thread.sleep(50);
for (int i = 0; i <= 10; i++) {
artistImage = Artist.getSimilar("Bon Iver", i, key);
new ArrayList<Artist>();
itr = artistImage.iterator();
while (itr.hasNext()) {
Artist temp = itr.next();
artistImages = ((ImageHolder) temp)
.getImageURL(ImageSize.MEGA);
artistName = ((MusicEntry) temp).getName();
}
}
} catch (Exception e) {
Log.i("images", e.getMessage());
}
return artistImages;
}
}
So, I'm unsure how to set this up correctly and it's time to ask for some help. After my fair share of failed attempts, on the plus side I've learned a lot about making my app more efficient. I'd appreciate some advice.
Solution
Below is the code that should give you fair idea on how you should deal with adapter and async task. Like @ABentSpoon and @Fixpoint, I'm also confused how you are using these variables. But I'm ignoring these and focusing on ideally how the code structure should be for your case.
Adapter.getView() method is called once for each cell or item in the grid. If your going to run async task from within getView() it will be executed for each item. I think that is why you are seeing enormouse amount of prints.
public class ArtistImage {
public String image;
public String name;
}
public class LoadImages extends AsyncTask<String, Integer, List<ArtistImage>> {
private List<ArtistImage> artistImages = new ArrayList<ArtistImage>();
private ArtistAdapter artistAdapter;
public LoadImages(ArtistAdapter adapter) {
artistAdapter = adapter;
}
@Override
protected List<ArtistImage> doInBackground(String... params) {
try {
for (int i = 0; i <= 10; i++) {
Collection<Artist> artistImage = Artist.getSimilar("Bon Iver", i, key);
Iterator<Artist> itr = artistImage.iterator();
while (itr.hasNext()) {
Artist temp = itr.next();
ArtistImage ai = new ArtistImage();
ai.image = ((ImageHolder) temp).getImageURL(ImageSize.MEGA);
ai.name = ((MusicEntry) temp).getName();
artistImages.add(ai);
}
}
} catch (Exception e) {
Log.i("images", e.getMessage());
}
return artistImages;
}
@Override
protected void onPostExecute(List<ArtistImage> result) {
artistAdapter.setArtistImages(result);
}
}
public class ArtistAdapter extends ... {
private List<ArtistImage> artistImages = new ArrayList<ArtistImage>();
public void setArtistImages(List<ArtistImage> images) {
this.artistImages = images;
super.notifyDataSetChanged();
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ArtistImage image = artistImages.get(position);
// render stuff here
}
}
In your activity, either onCreate or some event:
ArtistAdapter aa = new ArtistAdapter();
LoadImages loadImages = new LoadImages(aa);
loadImages.execute();