如何在Android中通过URL加载ImageView?

572

如何在ImageView中使用通过URL引用的图片?


1
尝试这个:https://dev59.com/QG3Xa4cB1Zd3GeqPcDeG#15797963 - comeGetSome
2
使用Picasso...https://dev59.com/h3E95IYBdhLWcg3wEpvo#23865531 - chiragkyada
公共类ImageDownloader { private final Executor executor = Executors.newSingleThreadExecutor(); public void download(String url, Consumer<Bitmap> onSuccess, Consumer<Exception> onError) { Handler handler = new Handler(); executor.execute(() -> { try (InputStream in = new URL(url).openStream()) { Bitmap result = BitmapFactory.decodeStream(in); handler.post(() -> onSuccess.accept(result)); } catch (Exception e) { handler.post(() -> onError.accept(e)); } }); } } - Sarsaparilla
23个回答

735

来自Android开发者

// show The Image in a ImageView
new DownloadImageTask((ImageView) findViewById(R.id.imageView1))
            .execute("http://java.sogeti.nl/JavaBlog/wp-content/uploads/2009/04/android_icon_256.png");

public void onClick(View v) {
    startActivity(new Intent(this, IndexActivity.class));
    finish();

}

private 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 mIcon11 = null;
        try {
            InputStream in = new java.net.URL(urldisplay).openStream();
            mIcon11 = BitmapFactory.decodeStream(in);
        } catch (Exception e) {
            Log.e("Error", e.getMessage());
            e.printStackTrace();
        }
        return mIcon11;
    }

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

请确保您在AndroidManifest.xml中设置了以下权限,以便访问互联网。

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

43
太棒了!这应该在列表中排名更高。使用异步任务可以在不冻结用户界面的情况下加载它! - Kyle Clegg
3
AsyncTasks 使用串行执行器,意味着每个图像将一次加载一个,而不是并行线程加载。 - Blundell
2
源链接已失效... - hecvd
11
你的示例中未关闭输入流。最好在try/catch的finally块中完成。 - Risadinha
2
这个方法还有用吗?我对OnClick()方法及其目的有点困惑。 - tccpg288
显示剩余12条评论

219

1. Picasso 允许在您的应用程序中轻松加载图像,通常只需一行代码!

使用 Gradle:

implementation 'com.squareup.picasso:picasso:(insert latest version)'

只需要一行代码!

Picasso.get().load("http://i.imgur.com/DvpvklR.png").into(imageView);

2. Glide 是一款专注于实现流畅滚动的 Android 图片加载和缓存库。

使用 Gradle:

repositories {
   mavenCentral() 
   google()
}

dependencies {
   implementation 'com.github.bumptech.glide:glide:4.11.0'
   annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
}

// For a simple view:
Glide.with(this).load("http://i.imgur.com/DvpvklR.png").into(imageView);

3. Fresco 是一款在 Android 应用程序中显示图像的强大系统。Fresco 负责图像加载和显示,因此您无需操心。

开始使用 Fresco

4. Coil 是一款由 Kotlin 协程支持的 Android 图像加载库。

implementation("io.coil-kt:coil:2.3.0")

要将图像加载到 ImageView 中,请使用 load 扩展函数:

imageView.load("https://example.com/image.jpg")

3
如果URL是本地主机(localhost),那么意味着图片存储在开发系统的本地服务器数据库中,例如xampp,我仍然能够从URL获取图片。 - blackjack
3
如果应用程序中的@blackjack - localhost指的是智能手机本身。要访问您的开发系统,智能手机和开发系统必须在同一个网络中,并且您需要使用该网络中开发系统的IP地址。请注意,此翻译并未更改原文的含义。 - Ridcully
1
使用 Picasso 在按钮上加载图片是否可行? - mahdi
1
我认为这应该是被接受的答案。 - Udo
1
除非fit()无缘无故地导致图像随机失败,否则请勿改变程序。 - Juan Carlos Ospina Gonzalez
显示剩余6条评论

151

首先你需要先下载该图片

public static Bitmap loadBitmap(String url) {
    Bitmap bitmap = null;
    InputStream in = null;
    BufferedOutputStream out = null;

    try {
        in = new BufferedInputStream(new URL(url).openStream(), IO_BUFFER_SIZE);

        final ByteArrayOutputStream dataStream = new ByteArrayOutputStream();
        out = new BufferedOutputStream(dataStream, IO_BUFFER_SIZE);
        copy(in, out);
        out.flush();

        final byte[] data = dataStream.toByteArray();
        BitmapFactory.Options options = new BitmapFactory.Options();
        //options.inSampleSize = 1;

        bitmap = BitmapFactory.decodeByteArray(data, 0, data.length,options);
    } catch (IOException e) {
        Log.e(TAG, "Could not load Bitmap from: " + url);
    } finally {
        closeStream(in);
        closeStream(out);
    }

    return bitmap;
}
然后使用 ImageView.setImageBitmap 将位图设置到 ImageView 中。

127
你说得对,但是这三行代码足以解决问题。URL newurl = new URL(photo_url_str); mIcon_val = BitmapFactory.decodeStream(newurl.openConnection().getInputStream()); profile_photo.setImageBitmap(mIcon_val); 谢谢你的回复。 - Praveen
2
对于URL - 导入java.net.URL; 私有静态最终int IO_BUFFER_SIZE = 4 * 1024;最后一个是什么? - Steve
12
请参见此处的代码:https://dev59.com/ZHA75IYBdhLWcg3wxcDV - OneWorld
@steve 谢谢... 但是还有一些问题。虽然我把 'closeStream(in);' 改成了 'in.close();',但是我不知道该怎么处理 'copy(in, out);' ??? - ABS
1
嘿@史蒂夫,不要低估自己! :) 我找到了伪代码部分的实现。这行“copy(in,out)”必须替换为以下内容:int bytesRead; byte[] buffer = new byte[IO_BUFFER_SIZE]; while ((bytesRead = in.read(buffer)) != -1) { out.write(buffer, 0, bytesRead); } - ABS
显示剩余7条评论

75

无论如何,人们要求我发表评论作为答案。 我正在发布。

URL newurl = new URL(photo_url_str); 
mIcon_val = BitmapFactory.decodeStream(newurl.openConnection().getInputStream());
profile_photo.setImageBitmap(mIcon_val);

这很简短也很棒,谢谢。 - Nactus
21
抱歉,这不能通过 UI 线程完成。 - Guy
2
对于遇到“Malformed URL Exeption”问题的人,可以在上面的代码行中加入try/catch语句块来解决。https://dev59.com/d2Af5IYBdhLWcg3wqEHp#24418607 - Riot Goes Woof
1
这应该使用如上所述的AsyncTask完成。 - B-GangsteR

70

我编写了一个类来处理这个问题,因为在我的各种项目中似乎有这种常见需求:

https://github.com/koush/UrlImageViewHelper

UrlImageViewHelper可以填充一个ImageView,并显示从URL找到的图像。

该示例将执行Google Image Search并异步加载/显示结果。

UrlImageViewHelper将自动下载、保存和缓存所有图像URL BitmapDrawables。重复的URL不会被加载两次到内存中。使用弱引用哈希表管理位图内存,因此一旦您不再使用图像,它就会被自动垃圾回收。


顺便问一下,这个有许可证吗? - Ehtesh Choudhury
@Shurane - Apache。稍后我会记下来的。 - koush
1
看起来我们需要使用这个 https://github.com/koush/ion,因为 UrlImageViewHelper 已经被弃用了,如在 github 项目页面 https://github.com/koush/UrlImageViewHelper 上所示。 - Svetoslav Marinov

65

如果您是通过按钮点击加载图像,上面的接受回答非常好。但是,如果您在一个新的活动中执行此操作,它会冻结UI一两秒钟。我发现使用简单的asynctask可以解决这个问题。

为了使用asynctask,请在您的活动末尾添加以下类:

private 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 mIcon11 = null;
        try {
            InputStream in = new java.net.URL(urldisplay).openStream();
            mIcon11 = BitmapFactory.decodeStream(in);
        } catch (Exception e) {
            Log.e("Error", e.getMessage());
            e.printStackTrace();
        }
        return mIcon11;
    }

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

并从您的 onCreate() 方法中调用:

new DownloadImageTask((ImageView) findViewById(R.id.imageView1))
        .execute(MY_URL_STRING);

结果是一个快速加载的活动和一个ImageView,取决于用户的网络速度,后者会在一瞬间显示出来。


这很快速和紧凑。完美地满足了我的需求!谢谢! - Mark Murphy
截至我的时间戳,这对我有效! - Carpk
AsyncTask自Android 11起已被弃用。 - Mattwmaster58

25
您还可以使用LoadingImageView视图从URL加载图像: http://blog.blundellapps.com/imageview-with-loading-spinner/ 一旦您添加了该链接中的类文件,就可以实例化一个url image view:
在xml中:
<com.blundell.tut.LoaderImageView
  android:id="@+id/loaderImageView"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  image="http://developer.android.com/images/dialog_buttons.png"
 />

在代码中:

final LoaderImageView image = new LoaderImageView(this, "http://developer.android.com/images/dialog_buttons.png");

然后使用以下方式进行更新:

image.setImageDrawable("http://java.sogeti.nl/JavaBlog/wp-content/uploads/2009/04/android_icon_256.png");

不错的示例,但我不认为这是线程安全的。我试图在Async onPostExecute中使用它,然而有时候onPostExecute可能会在回调接收之前结束,导致图像为空。 - Jimmy
这个程序能够自己管理线程。因此,为什么不在ASyncTask完成后回调UI,告知所需的URL呢?这样就不会产生新的线程了。 - Blundell

12

我认为这项任务中最好的现代库是由Square提供的 Picasso。它可以通过一行代码从URL加载图像到ImageView:

Picasso.with(context).load("http://i.imgur.com/DvpvklR.png").into(imageView);

10
public class LoadWebImg extends Activity {

String image_URL=
 "http://java.sogeti.nl/JavaBlog/wp-content/uploads/2009/04/android_icon_256.png";

   /** Called when the activity is first created. */
   @Override
   public void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.main);

       ImageView bmImage = (ImageView)findViewById(R.id.image);
    BitmapFactory.Options bmOptions;
    bmOptions = new BitmapFactory.Options();
    bmOptions.inSampleSize = 1;
    Bitmap bm = LoadImage(image_URL, bmOptions);
    bmImage.setImageBitmap(bm);
   }

   private Bitmap LoadImage(String URL, BitmapFactory.Options options)
   {       
    Bitmap bitmap = null;
    InputStream in = null;       
       try {
           in = OpenHttpConnection(URL);
           bitmap = BitmapFactory.decodeStream(in, null, options);
           in.close();
       } catch (IOException e1) {
       }
       return bitmap;               
   }

private InputStream OpenHttpConnection(String strURL) throws IOException{
 InputStream inputStream = null;
 URL url = new URL(strURL);
 URLConnection conn = url.openConnection();

 try{
  HttpURLConnection httpConn = (HttpURLConnection)conn;
  httpConn.setRequestMethod("GET");
  httpConn.connect();

  if (httpConn.getResponseCode() == HttpURLConnection.HTTP_OK) {
   inputStream = httpConn.getInputStream();
  }
 }
 catch (Exception ex)
 {
 }
 return inputStream;
}
}

非常感谢,这正是我一直在寻找的完美例子................, 但是放错了主题,应该在这里 ==> 如何从字符串设置imageView的图像? - VenomVendor

10

嗨,我有一段最简单的代码,请试试

    public class ImageFromUrlExample extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);  
            ImageView imgView =(ImageView)findViewById(R.id.ImageView01);
            Drawable drawable = LoadImageFromWebOperations("http://www.androidpeople.com/wp-content/uploads/2010/03/android.png");
            imgView.setImageDrawable(drawable);

    }

    private Drawable LoadImageFromWebOperations(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;
      }
    }
   }
  <LinearLayout 
    android:id="@+id/LinearLayout01"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    xmlns:android="http://schemas.android.com/apk/res/android">
   <ImageView 
       android:id="@+id/ImageView01"
       android:layout_height="wrap_content" 
       android:layout_width="wrap_content"/>

试试这个


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