How to set image from Url using AsyncTask?

2020-05-29 01:35发布

问题:

I'm a newbie programmer an I'm making an android program that displays an image on ImageView from a given url. My problem is how do you use this on the AsyncTask?

These codes work on min SDK 2.2 but I switched to min SDK 3.0 so it needs to run on the AsyncTask. Thank you for your help! :)

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    satellite(); //satellite's image from main menu

}

//******satellite url
private void satellite() {
    // TODO Auto-generated method stub
    ImageView imgView =(ImageView)findViewById(R.id.satellite);
    Drawable drawable = LoadImageFromWeb("http://www.pagasa.dost.gov.ph/wb/sat_images/satellite.gif");
    imgView.setImageDrawable(drawable);        
}

private Drawable LoadImageFromWeb(String url){
      try{
          InputStream is = (InputStream) new URL(url).getContent();
          Drawable d = Drawable.createFromStream(is, "src name");
          return d;
      }catch (Exception e) {
          System.out.println("Exc="+e);
          return null;
      }
}

回答1:

well, I dont know why android SDK does not provide support for it (yet) I extended the ImageView class by UrlImageView class with asynchronous loading and caching support. I put the code of my class below, which is plug and play. The class body is at the end of my post, now I write two lines how to use it the convenient way.

Two more methods now are supported:

setImageUrl(URL url) // sets the bitmap by its URL
cancelLoading();     // tell this view to cancel pending load

How to use your java-code:

// [somewhere in your activity]
UrlImageView urlImg = new UrlImageView(this).setImageUrl("http://abc.png");
...
urlImg.setImageUrl("http://abc2.png"); // works like expected

How to bind in your layouts:

<!-- thumbnail -->
<com.gplushub.android.view.UrlImageView
    android:id="@+id/thumbnail"
    android:layout_width="64dp"
    android:layout_height="64dp"
    android:layout_gravity="center_vertical"
    android:layout_marginRight="2dp"
    android:scaleType="fitXY" />

..and again in your activity java code:

((UrlImageView)findViewById(R.id.thumbnail)).setImageUrl("http://foo.bar.png");

I use it in lists with more than 100 entries - flinging very well. Here the class body, you can use it, modify it, extend it, whatever you like:

package com.gplushub.android.view;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.AsyncTask;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.ImageView;

/**
 * an {@link ImageView} supporting asynchronous loading from URL. Additional
 * APIs: {@link #setImageURL(URL)}, {@link #cancelLoading()}.
 * 
 * @author ep@gplushub.com / Eugen Plischke
 * 
 */
public class UrlImageView extends ImageView {
  private static class UrlLoadingTask extends AsyncTask<URL, Void, Bitmap> {
    private final ImageView updateView;
    private boolean         isCancelled = false;
    private InputStream     urlInputStream;

    private UrlLoadingTask(ImageView updateView) {
      this.updateView = updateView;
    }

    @Override
    protected Bitmap doInBackground(URL... params) {
      try {
        URLConnection con = params[0].openConnection();
        // can use some more params, i.e. caching directory etc
        con.setUseCaches(true);
        this.urlInputStream = con.getInputStream();
        return BitmapFactory.decodeStream(urlInputStream);
      } catch (IOException e) {
        Log.w(UrlImageView.class.getName(), "failed to load image from " + params[0], e);
        return null;
      } finally {
        if (this.urlInputStream != null) {
          try {
            this.urlInputStream.close();
          } catch (IOException e) {
            ; // swallow
          } finally {
            this.urlInputStream = null;
          }
        }
      }
    }

    @Override
    protected void onPostExecute(Bitmap result) {
      if (!this.isCancelled) {
        // hope that call is thread-safe
        this.updateView.setImageBitmap(result);
      }
    }

    /*
     * just remember that we were cancelled, no synchronization necessary
     */
    @Override
    protected void onCancelled() {
      this.isCancelled = true;
      try {
        if (this.urlInputStream != null) {
          try {
            this.urlInputStream.close();
          } catch (IOException e) {
            ;// swallow
          } finally {
            this.urlInputStream = null;
          }
        }
      } finally {
        super.onCancelled();
      }
    }
  }

  /*
   * track loading task to cancel it
   */
  private AsyncTask<URL, Void, Bitmap> currentLoadingTask;
  /*
   * just for sync
   */
  private Object                       loadingMonitor = new Object();

  public UrlImageView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
  }

  public UrlImageView(Context context, AttributeSet attrs) {
    super(context, attrs);
  }

  public UrlImageView(Context context) {
    super(context);
  }

  @Override
  public void setImageBitmap(Bitmap bm) {
    cancelLoading();
    super.setImageBitmap(bm);
  }

  @Override
  public void setImageDrawable(Drawable drawable) {
    cancelLoading();
    super.setImageDrawable(drawable);
  }

  @Override
  public void setImageResource(int resId) {
    cancelLoading();
    super.setImageResource(resId);
  }

  @Override
  public void setImageURI(Uri uri) {
    cancelLoading();
    super.setImageURI(uri);
  }

  /**
   * loads image from given url
   * 
   * @param url
   */
  public void setImageURL(URL url) {
    synchronized (loadingMonitor) {
      cancelLoading();
      this.currentLoadingTask = new UrlLoadingTask(this).execute(url);
    }
  }

  /**
   * cancels pending image loading
   */
  public void cancelLoading() {
    synchronized (loadingMonitor) {
      if (this.currentLoadingTask != null) {
        this.currentLoadingTask.cancel(true);
        this.currentLoadingTask = null;
      }
    }
  }
}


回答2:

If the image is not that big you can just use an anonymous class for the async task. This would like this:

ImageView mChart = (ImageView) findViewById(R.id.imageview);
String URL = "http://www...anything ...";

mChart.setTag(URL);
new DownloadImageTask.execute(mChart);

and the task class is

public class DownloadImagesTask extends AsyncTask<ImageView, Void, Bitmap> {
   ImageView imageView = null;
   @Override
   protected Bitmap doInBackground(ImageView... imageViews) {
      this.imageView = imageViews[0];
      return download_Image((String)imageView.getTag());
   }

   @Override
   protected void onPostExecute(Bitmap result) {
      imageView.setImageBitmap(result);
   }

   private Bitmap download_Image(String url) {
       ...
   }


回答3:

Try this code, make your drawable variable global and change your satellite function like this:

private void satellite() {
      // TODO Auto-generated method stub
      ImageView imgView =(ImageView)findViewById(R.id.satellite);
      new yourTask().execute();
}

then create asyncTask class like this:

private class yourTask extends AsyncTask<Integer, Void, Integer> {
    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        //show a progress bar
    }

    @Override
    protected String doInBackground(Integer... params) {
        drawable  =  LoadImageFromWeb("http://www.pagasa.dost.gov.ph/wb/sat_images/satellite.gif"); 
        return 0; 
    }      

    @Override
    protected void onPostExecute(Integer result) {
        super.onPostExecute(result);
        imgView.setImageDrawable(drawable);   
    }
}


回答4:

Here is the code for the Aynctask implementation Make your drawable object as global in Aynctask class.

Class MyDownloader extends AsyncTask<Void,Void,String>{

    Drawable drawable;    
    @Override
    public String doInBackground(Void... args){

        drawable = LoadImageFromWeb("http://www.pagasa.dost.gov.ph/wb/sat_images/satellite.gif");
        return null; // here you can pass any string on response as on error or on success

    }

    public void onPostExecute(String result){

        if(drawable!=null){

            imgView.setImageDrawable(drawable);

        }

    }

}

now create object of this class and execute it

private void satellite() {
    // TODO Auto-generated method stub
  ImageView imgView =(ImageView)findViewById(R.id.satellite);
  new MyDownloader.execute();

}

Here is good example link for caching the image check out this link and example

https://github.com/novoda/ImageLoader



回答5:

You are right when u do any network operation later Android 2.2(Froyo) Must use Asynctask

This is the best example to understand AsyncTask



回答6:

based on the answer from comeGetSome i created my own implementation which works with normal ImageView class instead of creating a new class UrlImageView, also new options are provided like - what to do when the loading completes or cancels

Now load image as you want, like this from any of the three loadImage methods

       UrlImageLoader urlImageLoader=new UrlImageLoader();
       ImageView imageView=new ImageView(context);
       //load and set the image to ImageView
       urlImageLoader.loadImage(imageView, "http://www......com/.....jpg");
       //for loading a image only - load image and do any thing with the bitmap
       urlImageLoader.loadImage("http://www......com/.....jpg", new UrlImageLoader.OnLoadingCompleteListener() {

            @Override
            public void onComplete(ImageView imageView, Bitmap bmp) {
                // do anything with the Bitmap
                // here imageView will be null
            }
            @Override
            public void onCancel(ImageView imageView) {

            }
        });
       urlImageLoader.loadImage(imageView, "http://www......com/.....jpg", new UrlImageLoader.OnLoadingCompleteListener() {

            @Override
            public void onComplete(ImageView imageView, Bitmap bmp) {
                // do anything with the Bitmap
                // here imageView is not null
                imageView.setImageBitmap(bmp);
            }
            @Override
            public void onCancel(ImageView imageView) {

            }
        });

create this class for loading UrlImageLoader

/*special thanks to stackoverflow.com user comeGetSome for UrlImageLoadingTask code
 * question - http://stackoverflow.com/questions/14332296/how-to-set-image-from-url-using-asynctask/15797963
 * comeGetSome - http://stackoverflow.com/users/1005652/comegetsome
 */
package com.GameG.SealTheBox;

import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.util.Log;
import android.widget.ImageView;

public class UrlImageLoader {
    public static interface OnLoadingCompleteListener {
        public void onComplete(ImageView imageView, Bitmap bmp);
        public void onCancel(ImageView imageView);
    }
    ArrayList<UrlImageLoadingTask> loadingList=new ArrayList<UrlImageLoadingTask>();
    /**
     * Loads a image from url and calls onComplete() when finished<br>
     * @Note you should manually set the loaded image to ImageView in the onComplete()
     * @param imageView
     * @param url
     * @param onComplete
     */
    public void loadImage(ImageView imageView, String url, OnLoadingCompleteListener onComplete){
        try {
            URL url2=new URL(url);
            if(imageView!=null){
                for(int i=0;i<loadingList.size();i++){
                    UrlImageLoadingTask tmptask=loadingList.get(i);
                    if(tmptask.updateView!=null && tmptask.updateView.equals(imageView)){
                        tmptask.cancel(true);
                        break;
                    }
                }
            }
            UrlImageLoadingTask loadtask=new UrlImageLoadingTask(imageView,onComplete,url);
            loadtask.execute(url2);
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
    }

    /**
     * Loads a image from url and calls onComplete() when finished
     * @param url
     * @param onComplete
     */
    public void loadImage(String url, OnLoadingCompleteListener onComplete){
        loadImage(null,url,onComplete);
    }
    /**
     * Loads a image from url and sets the loaded image to ImageView
     * @param imageView
     * @param url
     */
    public void loadImage(ImageView imageView, String url){
        loadImage(imageView,url,null);
    }
    /**
     * Cancel loading of a ImageView
     */
    public void cancel(ImageView imageView){
        for(int i=0;i<loadingList.size();i++){
            UrlImageLoadingTask tmptask=loadingList.get(i);
            if(tmptask.updateView.equals(imageView)){
                loadingList.remove(i);
                tmptask.cancel(true);
                break;
            }
        }
    }
    /**
     * Cancel loading of a Url
     */
    public void cancel(String url){
        for(int i=0;i<loadingList.size();i++){
            UrlImageLoadingTask tmptask=loadingList.get(i);
            if(tmptask.url.equals(url)){
                loadingList.remove(i);
                tmptask.cancel(true);
                break;
            }
        }
    }
    /**
     * Cancel all loading tasks 
     */
    public void cancelAll(){
        while(loadingList.size()>0){
            UrlImageLoadingTask tmptask=loadingList.get(0);
            loadingList.remove(tmptask);
            tmptask.cancel(true);
        }
    }

    private class UrlImageLoadingTask extends AsyncTask<URL, Void, Bitmap> {
        public ImageView updateView=null;
        public String url;
        private boolean         isCancelled = false;
        private InputStream     urlInputStream;
        private OnLoadingCompleteListener onComplete=null;

        private UrlImageLoadingTask(ImageView updateView, OnLoadingCompleteListener onComplete, String url) {
          this.updateView=updateView;
          this.onComplete=onComplete;
          this.url=url;
        }

        @Override
        protected Bitmap doInBackground(URL... params) {
          try {
            URLConnection con = params[0].openConnection();
            // can use some more params, i.e. caching directory etc
            con.setUseCaches(true);
            this.urlInputStream = con.getInputStream();
            return BitmapFactory.decodeStream(urlInputStream);
          } catch (IOException e) {
            Log.w(UrlImageView.class.getName(), "failed to load image from " + params[0], e);
            return null;
          } finally {
            if (this.urlInputStream != null) {
              try {
                this.urlInputStream.close();
              } catch (IOException e) {
                ; // swallow
              } finally {
                this.urlInputStream = null;
              }
            }
          }
        }

        @Override
        protected void onPostExecute(Bitmap result) {
          if (!this.isCancelled) {
            // hope that call is thread-safe
              if(onComplete==null){
                  if(updateView!=null)
                  this.updateView.setImageBitmap(result);
              }else{
                  onComplete.onComplete(updateView, result);
              }
          }
          loadingList.remove(this);
        }

        /*
         * just remember that we were cancelled, no synchronization necessary
         */
        @Override
        protected void onCancelled() {
          this.isCancelled = true;
          try {
            if (this.urlInputStream != null) {
              try {
                this.urlInputStream.close();
              } catch (IOException e) {
                ;// swallow
              } finally {
                this.urlInputStream = null;
              }
            }
          } finally {
            super.onCancelled();
            if(onComplete!=null)
                onComplete.onCancel(updateView);
            loadingList.remove(this);
          }
        }
      }

}


回答7:

Just create a new class "DownloadImageTask" like following one and put it at the same folder where you have your Activity.

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.Log;
import android.widget.ImageView;
import android.os.AsyncTask;
import java.io.*;


public class DownloadImageTask extends AsyncTask<String, Void, Bitmap> {
    ImageView bmImage;

    public DownloadImageTask(ImageView bmImage) {
        this.bmImage = bmImage;
    }

    protected Bitmap doInBackground(String... urls) {
        String urldisplay = urls[0];
        Bitmap myImage = null;
        try {
            InputStream in = new java.net.URL(urldisplay).openStream();
            myImage = BitmapFactory.decodeStream(in);
        } catch (Exception e) {
            Log.e("Error", e.getMessage());
            e.printStackTrace();
        }
        return myImage;
    }

    protected void onPostExecute(Bitmap result) {
        bmImage.setImageBitmap(result);
    }
}

After this add line to crate that class in your Activity.

import android.graphics.Bitmap;
import android.os.AsyncTask;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.util.Log;
import android.widget.ImageView;


public class HomeScreen extends ActionBarActivity {

    private final String TAG = "test1";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d(TAG, "onCreate");
        setContentView(R.layout.activity_home_screen);
        InitHomeScreen();
    }

    protected void InitHomeScreen()
    {
        String imageUrl = "http://s20.postimg.org/4t9w2pdct/logo_android_png.png";
        Log.d(TAG, "Get an Image");
        // Get an Image
        try{
            AsyncTask<String, Void, Bitmap> execute = new DownloadImageTask((ImageView) findViewById(R.id.imageView))
                    .execute(imageUrl);
              // R.id.imageView  -> Here imageView is id of your ImageView
        }
        catch(Exception ex)
        {
        }
    }

   // Other code...

Don't forget to allow access to INTERNET to your Android app.

Check your manifest file.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.dmitry.myapplication1" >

    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.INTERNET" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".HomeScreen"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>