Android: 使用Asynctask从网络加载图片

36

如何使用Asynctask替换以下代码行?如何从Asynctask中“获取”位图?谢谢。

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

mChart.setImageBitmap(download_Image(URL));

public static Bitmap download_Image(String url) {

        //---------------------------------------------------
        Bitmap bm = null;
        try {
            URL aURL = new URL(url);
            URLConnection conn = aURL.openConnection();
            conn.connect();
            InputStream is = conn.getInputStream();
            BufferedInputStream bis = new BufferedInputStream(is);
            bm = BitmapFactory.decodeStream(bis);
            bis.close();
            is.close();
        } catch (IOException e) {
            Log.e("Hub","Error getting the image from server : " + e.getMessage().toString());
        } 
        return bm;
        //---------------------------------------------------

    }
我考虑了这样的方案:
替换:
mChart.setImageBitmap(download_Image(graph_URL));

通过类似于以下方式:

mChart.setImageBitmap(new DownloadImagesTask().execute(graph_URL));
并且
public class DownloadImagesTask extends AsyncTask<String, Void, Bitmap> {

@Override
protected Bitmap doInBackground(String... urls) {
    return download_Image(urls[0]);
}

@Override
protected void onPostExecute(Bitmap result) {
    mChart.setImageBitmap(result);              // how do I pass a reference to mChart here ?
}


private Bitmap download_Image(String url) {
    //---------------------------------------------------
    Bitmap bm = null;
    try {
        URL aURL = new URL(url);
        URLConnection conn = aURL.openConnection();
        conn.connect();
        InputStream is = conn.getInputStream();
        BufferedInputStream bis = new BufferedInputStream(is);
        bm = BitmapFactory.decodeStream(bis);
        bis.close();
        is.close();
    } catch (IOException e) {
        Log.e("Hub","Error getting the image from server : " + e.getMessage().toString());
    } 
    return bm;
    //---------------------------------------------------
}


}

但是,我如何在onPostExecute(Bitmap result)中传递对mChart的引用?是否需要以某种方式将其与URL一起传递?我想替换掉所有代码行:

但如何在onPostExecute(Bitmap result)中传递对mChart的引用?是否需要通过URL以某种方式进行传递?我希望替换掉我的所有代码行:

mChart1.setImageBitmap(download_Image(URL_1));
mChart2.setImageBitmap(download_Image(URL_2));

使用类似的方法...但采用异步任务方式!

mChart1.setImageBitmap(new DownloadImagesTask().execute(graph_URL_1));
mChart2.setImageBitmap(new DownloadImagesTask().execute(graph_URL_2));

有没有简单的解决方案? 我这里做错了什么吗?


这是一个相当基础的问题,但我认为对像我一样的许多初学者都会有所帮助...如果您有,请发布一些代码。 - Hubert
相关:ImageDownloader示例 - idbrii
@Hubert,你能否提及一下这段代码 private Bitmap download_Image(String url) { ... } ? - Erum
如果您正在使用Glide和Kotlin,那么这个链接可能会对您有所帮助。 - Kishan Solanki
4个回答

75

如果没有下载图像的充分理由,我建议使用Picasso

Picasso 可以帮助您解决所有与下载、设置和缓存图像相关的问题。一个简单示例所需的全部代码如下:

Picasso.with(context).load(url).into(imageView);

如果你真的想要完全自己实现,可以使用我下面以前的答案。


如果图像并不是很大,你可以使用匿名类来执行异步任务。代码如下:

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

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

Task类:

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) {
   ...
}
隐藏标签中的URL有些棘手,但如果您有许多要用这种方式填充的图像视图,则在调用类中看起来更好。如果您在ListView内使用ImageView并且想知道在下载图片期间是否回收了ImageView,这也会有所帮助。
我写了"如果您的图像不是那么大",因为这将导致任务具有对底层活动的隐式指针,从而导致垃圾回收器在任务完成之前将整个活动保存在内存中。如果用户在位图正在下载时移动到应用程序的另一个屏幕,那么内存无法被释放,这可能会使您的应用程序和整个系统变慢。

我的图片大约是45.2千字节(46,384字节)的GIF类型,如果有任何区别的话? - Hubert
只有在下载图片花费超过20秒且您的活动对系统内存占用较大时,才会出现问题。 - Janusz
谢谢Janusz,我编辑了我的问题并添加了一些内容。你觉得怎么样?事实上,我想在不同的ImageView上使用这个AsyncTask。在onPostExecute中如何传递正确的ImageView引用?非常感谢你的帮助。 - Hubert
非常感谢,这个很好用。这是我第一次尝试使用AsyncTask(我已经做了一年的Android开发了,你能相信吗!),它看起来确实比使用线程更好/更灵活。 - Hubert
@SwapAndroid 答案中的第一个代码部分展示了如何启动任务。你需要一个图片视图和一个URL地址,将URL赋值给imageView标签,并将imageView作为任务参数传递。 - A-Live
显示剩余2条评论

24
尝试这段代码:
ImageView myFirstImage = (ImageView) findViewById(R.id.myFirstImage);
ImageView mySecondImage = (ImageView) findViewById(R.id.mySecondImage);
ImageView myThirdImage = (ImageView) findViewById(R.id.myThirdImage);

String URL1 = "http://www.google.com/logos/2013/estonia_independence_day_2013-1057005.3-hp.jpg";
String URL2 = "http://www.google.com/logos/2013/park_su-geuns_birthday-1055005-hp.jpg";
String URL3 = "http://www.google.com/logos/2013/anne_cath_vestlys_93rd_birthday-1035005-hp.jpg";


myFirstImage.setTag(URL1);
mySecondImage.setTag(URL2);
myThirdImage.setTag(URL3);


new DownloadImageTask.execute(myFirstImage);
new DownloadImageTask.execute(mySecondImage);
new DownloadImageTask.execute(myThirdImage);



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

        Bitmap bmp =null;
        try{
            URL ulrn = new URL(url);
            HttpURLConnection con = (HttpURLConnection)ulrn.openConnection();
            InputStream is = con.getInputStream();
            bmp = BitmapFactory.decodeStream(is);
            if (null != bmp)
                return bmp;

            }catch(Exception e){}
        return bmp;
    }
}

2
return download_Image((String)imageView.getTag()); gives error. getTag must be called from the UI thread - sagar suri
尽管我在浏览器中访问URL时能够接收到图像,但在位图中却得到了空结果。你能告诉我可能出现这种情况的原因吗? - Anubhav
使用方法必须像这样:new DownloadImageTask().execute(myFirstImage); new DownloadImageTask().execute(mySecondImage); new DownloadImageTask().execute(myThirdImage); - xevser

2

您可以创建一个类,例如BkgProcess,其中包含一个扩展AsyncTask的内部类。在实例化BkgProcess时,在构造函数中传递您的Activity类的上下文。例如:

public class BkgProcess {

 String path;   
 Context _context;

public Download(Downloader downloader, String path2){

 this.path = path2;
    _context = downloader;

}

public void callProgressDialog(){

new BkgProcess().execute((Void)null);
}
class Downloads extends AsyncTask<Void, Void, Boolean> {
    private ProgressDialog dialog = new ProgressDialog(_context);
    protected void onPreExecute(){
        dialog.setMessage("Downloading image..");
        dialog.show();
    }

    protected void onPostExecute(Boolean success) {
        dialog.dismiss();
        if(success)
            Toast.makeText(_context, "Download complete", Toast.LENGTH_SHORT).show();
    }

@Override
protected Boolean doInBackground(Void... params) {
    return(startDownload(path));

    }


public boolean startDownload(String img_url) {

// download img..

      return true;
}
}
}

从您的活动类中...

BkgProcess dwn = new BkgProcess (Your_Activity_class.this, img_path);

dwn.callProgressDialog();

1

这将为您获取任何大小的图像... 如果您不想要进度对话框,只需在onPreExecute()中注释掉代码即可。

for(int i = 0 ; i < no_of_files ; i++ )
 new FetchFilesTask().execute(image_url[i]);


private class FetchFilesTask extends AsyncTask<String, Void, Bitmap> {

    private ProgressDialog dialog = new ProgressDialog(FileExplorer.this);
    Bitmap bitmap[];
    protected void onPreExecute(){
        dialog.setMessage("fetching image from the server");
        dialog.show();
    }

     protected Bitmap doInBackground(String... args) {

             bitmap = getBitmapImageFromServer();
         return bitmap;
     }

     protected void onPostExecute(Bitmap m_bitmap) {
         dialog.dismiss();
         if(m_bitmap != null)
             //store the images in an array or do something else with all the images.   
     }
 }

public Bitmap getBitmapImageFromServer(){

    // fetch image form the url using the URL and URLConnection class
}

2
谢谢Umesh提供的建议。也许我应该添加一个ProgressDialog,以防万一!但是,你怎么将上下文(FileExplorer.this)传递给AsyncTask呢?我希望我的DownloadImagesTask()可以从应用程序的任何活动中访问...所以我为它创建了一个单独的类。 - Hubert

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