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.

Was it helpful?

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();
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top