Frage

I am working on a image downloader , which is a async downloader. I call it whenever need to display the image on the internet

Image async downloader (Input are the target imageview, image url)

public class ImageLoader extends AsyncTask<Object, Void, Bitmap> {

    private static String TAG = "ImageLoader";
    public InputStream input;
    public ImageView view;
    public String imageURL;

    @Override
    protected Bitmap doInBackground(Object... params) {
        try {

            view = (ImageView) params[0];
            imageURL = (String) params[1];

            URL url = new URL(imageURL);
            HttpURLConnection connection = (HttpURLConnection) url
                    .openConnection();
            connection.setDoInput(true);
            connection.connect();
            input = connection.getInputStream();
            Bitmap myBitmap = BitmapFactory.decodeStream(input);
            return myBitmap;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        } finally {
            try {
                if (input != null)
                    input.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

        }

    }

    @Override
    protected void onPostExecute(Bitmap result) {
        if (result != null && view != null) {
            view.setImageBitmap(result);
            view.setBackgroundResource(android.R.color.transparent);
            view.getBackground().setAlpha(255);
        }
    }
}

And the structure of my app is a tabhost , when I switch to a particular tab e.g. at the section 4 , there is a gridview and it will trigger the imageloader asynctask

The fragment:

gridView.setAdapter(new GalleryAdapter(getActivity() , images));

The adapter:

public class GalleryAdapter extends BaseAdapter {
    private Context mContext;
    public ArrayList<GalleryImage> images;

    // Constructor
    public GalleryAdapter(Context c, ArrayList<GalleryImage> _images) {
        mContext = c;
        images = _images;
    }

    @Override
    public int getCount() {
        return images.size();
    }

    @Override
    public Object getItem(int position) {
        return images.get(position);
    }

    @Override
    public long getItemId(int position) {
        return 0;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        if( convertView == null ){
            convertView = (ImageView)new ImageView(mContext);
            int size = (int)(Utility.getScreenWidth(mContext) / 3) - 1; 
            AbsListView.LayoutParams params = new AbsListView.LayoutParams(size, size);
            convertView.setLayoutParams(params);
            convertView.setBackgroundResource(android.R.color.darker_gray);
            convertView.getBackground().setAlpha(204); // = 0.8 alpha
        }

        new ImageLoader().execute(convertView,images.get(position).thumbUrl);

        return convertView;
    }
}

I would like to know are there any way to cancel the downloading task when I change the tab? (Since the user leave the tab before all the download is finish , so it is unnecessary to download anymore)

War es hilfreich?

Lösung

A task can be cancelled at any time by invoking cancel(boolean). Invoking this method will cause subsequent calls to isCancelled() to return true. After invoking this method, onCancelled(Object), instead of onPostExecute(Object) will be invoked after doInBackground(Object[]) returns. To ensure that a task is cancelled as quickly as possible, you should always check the return value of isCancelled() periodically from doInBackground(Object[]), if possible (inside a loop for instance.)

In your case, there is no loop in your doInBackground() code. In fact it would be better if you turn it into a loop by reading the response stream buffered. This would be more performant and enable you to call isCancelled() in the loop.

Example: Use ByteArrayOutputStream to read bytes in chunks and check isCancelled() periodically in the loop.

protected Bitmap doInBackground(Object... params) {
            try {

                URL url = new URL(imageURL);
                HttpURLConnection connection = (HttpURLConnection) url
                        .openConnection();
                input = connection.getInputStream();

                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                byte[] byteChunk = new byte[4096];
                int n;

                while ( (n = input.read(byteChunk)) > 0 ) {
                     if(isCancelled()) {
                        return null;
                     }
                     baos.write(byteChunk, 0, n);
                }

                Bitmap myBitmap = BitmapFactory.decodeByteArray(baos.toByteArray(), 0, baos.size());

                return myBitmap;
            } catch (IOException e) {
                e.printStackTrace();
                return null;
            } finally {
                try {
                    if (input != null)
                        input.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }

            }

   }

Of course you should keep a reference to your AsyncTask object to be able to call cancel method on it.

    private ImageLoader loader;
    ...
    ...
    loader = new ImageLoader();
    loader.execute();
    ...
    ...
    loader.cancel()
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top