如何使用AsyncTask从URL设置图像?

5

我是一名新手程序员,正在制作一个在给定的url上显示图像的Android程序。我的问题是如何在AsyncTask上使用它?

这些代码可以在最低SDK 2.2上运行,但我切换到了最低SDK 3.0,因此需要在AsyncTask上运行。谢谢你的帮助!:)

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;
      }
}

Tol,SDK 2.2?SDK 3.0?你是指Froyo和Honeycomb吗? - user948620
是的。因为在3.0以上版本中,当我从互联网获取数据时,需要运行一个单独的线程。而在2.2中则没有这个问题。所以我遇到了这个问题。 - Kkeevv Siena Alejandrino
7个回答

3

好的,我不知道为什么Android SDK(目前)不支持它,但我通过UrlImageView类扩展了ImageView类,实现了异步加载和缓存支持。我在下面放置了我的类代码,这是即插即用的。类的主体在我的帖子末尾,现在我写两行方便使用的方法。

现在支持两种更多的方法:

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

如何使用你的 Java 代码:

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

如何在布局中进行绑定:
<!-- 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" />

再次在你的活动java代码中:

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

我在包含100多个条目的列表中使用它——很好地滑动。这里是类体,你可以使用它,修改它,扩展它,任何你喜欢的。

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;
      }
    }
  }
}

感谢您精心编排的代码,我会使用并稍作修改。谢谢。 - Diljeet
我将自己的定制实现作为新答案发布给其他用户,我们可以使用普通的ImageView来加载图片,而不是UrlImageView。它还支持onComplete和onCancel等操作。 - Diljeet

2

如果图像不是太大,您可以为异步任务使用匿名类。代码如下:

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

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

任务类是:

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) {
       ...
   }

1

尝试这段代码,将你的drawable变量设为全局变量,并将你的卫星函数更改为以下内容:

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

然后创建这样的asyncTask类:

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);   
    }
}

0
只需创建一个名为“DownloadImageTask”的新类,就像下面这个示例一样,并将其放在与您的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);
    }
}

在此之后,将该行添加到您的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...

别忘了为你的Android应用程序允许INTERNET访问。

检查你的清单文件。

<?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>

0
这是Aynctask实现的代码 在Aynctask类中将您的可绘制对象设为全局变量。
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);

        }

    }

}

现在创建该类的对象并执行它

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

}

这里有一个很好的示例链接,可以缓存图像,请查看此链接和示例

https://github.com/novoda/ImageLoader


我在 new MyDownloader.execute(); 上遇到了一个错误,它说: MyDownloader 无法解析为类型。而且我已经将 Class MyDownloader extends AsyncTask<Void,Void,String>{ 更改为: public class MyDownloader extends AsyncTask<Void,Void,String>{ 因为在 Class 部分显示了错误。 我这样做对吗? - Kkeevv Siena Alejandrino

0

基于comeGetSome的答案,我创建了自己的实现,使用普通的ImageView类而非创建新的UrlImageView类,还提供了新的选项,例如加载完成或取消时要执行何种操作。

现在可以根据需要加载图像,可以使用任意三个loadImage方法中的任一个,就像这样:

       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) {

            }
        });

创建这个类来加载UrlImageLoader。
/*special thanks to stackoverflow.com user comeGetSome for UrlImageLoadingTask code
 * question - https://dev59.com/QG3Xa4cB1Zd3GeqPcDeG#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);
          }
        }
      }

}

0

当您进行任何网络操作时,您是正确的,后面必须使用Android 2.2(Froyo) Asynctask

这是理解AsyncTask的最佳示例


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接