Android 从 URL 加载到位图
Posted
技术标签:
【中文标题】Android 从 URL 加载到位图【英文标题】:Android load from URL to Bitmap 【发布时间】:2012-02-18 01:28:44 【问题描述】:我有一个关于从网站加载图片的问题。我使用的代码是:
Display display = getWindowManager().getDefaultDisplay();
int width = display.getWidth();
int height = display.getHeight();
Bitmap bit=null;
try
bit = BitmapFactory.decodeStream((InputStream)new URL("http://www.mac-wallpapers.com/bulkupload/wallpapers/Apple%20Wallpapers/apple-black-logo-wallpaper.jpg").getContent());
catch (Exception e)
Bitmap sc = Bitmap.createScaledBitmap(bit,width,height,true);
canvas.drawBitmap(sc,0,0,null);
但是它总是返回一个空指针异常并且程序崩溃了。 该 URL 有效,并且似乎对其他人都有效。 我正在使用 2.3.1。
【问题讨论】:
您收到什么崩溃信息?堆栈跟踪是什么?你知道哪一行导致它崩溃吗? createScalesBitmap 抛出 NullPointerException 因为 bit 为空。 需要互联网权限...添加<uses-permission android:name="android.permission.INTERNET" />
到androidmanifest.xml
【参考方案1】:
public static Bitmap getBitmapFromURL(String src)
try
URL url = new URL(src);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoInput(true);
connection.connect();
InputStream input = connection.getInputStream();
Bitmap myBitmap = BitmapFactory.decodeStream(input);
return myBitmap;
catch (IOException e)
// Log exception
return null;
【讨论】:
如何从 https 加载一个? 注意阻塞主线程。这应该在 AsyncTask 派生类中使用。 代码没问题。但是“主线程上的网络”会有例外。尝试在“异步任务”中使用它。 如何检测引发的IOException是否是因为无法上网? 对 Android 6.0 友好加 1【参考方案2】:public Drawable loadImageFromURL(String url, String name)
try
InputStream is = (InputStream) new URL(url).getContent();
Drawable d = Drawable.createFromStream(is, name);
return d;
catch (Exception e)
return null;
【讨论】:
【参考方案3】:试试这个:
AQuery aq = new AQuery(getActivity());
aq.id(view.findViewById(R.id.image)).image(imageUrl, true, true, 0, 0,
new BitmapAjaxCallback()
@Override
public void callback(String url, ImageView iv, Bitmap bm, AjaxStatus status)
iv.setImageBitmap(bm);
.header("User-Agent", "android"));
【讨论】:
【参考方案4】:非常快的方法,这个方法效果非常好:
private Bitmap getBitmap(String url)
File f=fileCache.getFile(url);
//from SD cache
Bitmap b = decodeFile(f);
if(b!=null)
return b;
//from web
try
Bitmap bitmap=null;
URL imageUrl = new URL(url);
HttpURLConnection conn = (HttpURLConnection)imageUrl.openConnection();
conn.setConnectTimeout(30000);
conn.setReadTimeout(30000);
conn.setInstanceFollowRedirects(true);
InputStream is=conn.getInputStream();
OutputStream os = new FileOutputStream(f);
Utils.CopyStream(is, os);
os.close();
bitmap = decodeFile(f);
return bitmap;
catch (Exception ex)
ex.printStackTrace();
return null;
//decodes image and scales it to reduce memory consumption
private Bitmap decodeFile(File f)
try
//decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(new FileInputStream(f),null,o);
//Find the correct scale value. It should be the power of 2.
final int REQUIRED_SIZE=70;
int width_tmp=o.outWidth, height_tmp=o.outHeight;
int scale=1;
while(true)
if(width_tmp/2<REQUIRED_SIZE || height_tmp/2<REQUIRED_SIZE)
break;
width_tmp/=2;
height_tmp/=2;
scale*=2;
//decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize=scale;
return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
catch (FileNotFoundException e)
return null;
【讨论】:
Util.copyStream(is, os);【参考方案5】:传递您的图片网址: 试试这个:
private Bitmap getBitmap(String url)
File file=fileCache.getFile(url);
Bitmap bm = decodeFile(file);
if(bm!=null)
return bm;
try
Bitmap bitmap=null;
URL ImageUrl = new URL(url);
HttpURLConnection conn = (HttpURLConnection)ImageUrl.openConnection();
conn.setConnectTimeout(50000);
conn.setReadTimeout(50000);
conn.setInstanceFollowRedirects(true);
InputStream is = conn.getInputStream();
OutputStream os = new FileOutputStream(file);
Utils.CopyStream(is, os);
os.close();
bitmap = decodeFile(file);
return bitmap;
catch (Exception ex)
ex.printStackTrace();
return null;
private Bitmap decodeFile(File file)
try
BitmapFactory.Options opt = new BitmapFactory.Options();
opt.inJustDecodeBounds = true;
BitmapFactory.decodeStream(new FileInputStream(file),null,opt);
final int REQUIRED_SIZE=70;
int width_tmp=opt.outWidth, height_tmp=opt.outHeight;
int scale=1;
while(true)
if(width_tmp/2<REQUIRED_SIZE || height_tmp/2<REQUIRED_SIZE)
break;
width_tmp/=2;
height_tmp/=2;
scale*=2;
BitmapFactory.Options opte = new BitmapFactory.Options();
opte.inSampleSize=scale;
return BitmapFactory.decodeStream(new FileInputStream(file), null, opte);
catch (FileNotFoundException e)
return null;
创建类实用程序:
public class Utils
public static void CopyStream(InputStream is, OutputStream os)
final int buffer_size=1024;
try
byte[] bytes=new byte[buffer_size];
for(;;)
int count=is.read(bytes, 0, buffer_size);
if(count==-1)
break;
os.write(bytes, 0, count);
catch(Exception ex)
【讨论】:
【参考方案6】:我更喜欢这些:
从 InputStream 创建位图并返回它:
public static Bitmap downloadImage(String url)
Bitmap bitmap = null;
InputStream stream = null;
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
bmOptions.inSampleSize = 1;
try
stream = getHttpConnection(url);
bitmap = BitmapFactory.decodeStream(stream, null, bmOptions);
stream.close();
catch (IOException e1)
e1.printStackTrace();
System.out.println("downloadImage"+ e1.toString());
return bitmap;
// Makes HttpURLConnection and returns InputStream
public static InputStream getHttpConnection(String urlString) throws IOException
InputStream stream = null;
URL url = new URL(urlString);
URLConnection connection = url.openConnection();
try
HttpURLConnection httpConnection = (HttpURLConnection) connection;
httpConnection.setRequestMethod("GET");
httpConnection.connect();
if (httpConnection.getResponseCode() == HttpURLConnection.HTTP_OK)
stream = httpConnection.getInputStream();
catch (Exception ex)
ex.printStackTrace();
System.out.println("downloadImage" + ex.toString());
return stream;
记住:
Android 包括两个 HTTP 客户端:HttpURLConnection 和 Apache HTTP 客户端。 对于 Gingerbread 及更高版本,HttpURLConnection 是最佳选择。
从 Android 3.x Honeycomb 或更高版本开始,您无法在 UI 线程 上执行 Network IO,这样做会引发 android.os.NetworkOnMainThreadException。您必须改用 Asynctask,如下所示
/** AsyncTAsk for Image Bitmap */
private class AsyncGettingBitmapFromUrl extends AsyncTask<String, Void, Bitmap>
@Override
protected Bitmap doInBackground(String... params)
System.out.println("doInBackground");
Bitmap bitmap = null;
bitmap = AppMethods.downloadImage(params[0]);
return bitmap;
@Override
protected void onPostExecute(Bitmap bitmap)
System.out.println("bitmap" + bitmap);
【讨论】:
如果我想加载多个位图并将它们显示为列表视图中列表项的背景,这样做的好做法是什么。我应该为每个位图调用 Asynctask 吗? 我有一个关于 AsyncTask 的问题。如何在我想将 url 转换为 Bitmap 的类中调用此方法以及如何访问该类中的 Bitmap?【参考方案7】:如果您使用Picasso 或Glide 或Universal-Image-Loader 从网址加载图片。 您可以通过
简单地获取加载的位图毕加索(当前版本2.71828
)
Java 代码
Picasso.get().load(imageUrl).into(new Target()
@Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from)
// loaded bitmap is here (bitmap)
@Override
public void onBitmapFailed(Drawable errorDrawable)
@Override
public void onPrepareLoad(Drawable placeHolderDrawable)
);
Kotlin 代码
Picasso.get().load(url).into(object : com.squareup.picasso.Target
override fun onBitmapLoaded(bitmap: Bitmap?, from: Picasso.LoadedFrom?)
// loaded bitmap is here (bitmap)
override fun onPrepareLoad(placeHolderDrawable: Drawable?)
override fun onBitmapFailed(e: Exception?, errorDrawable: Drawable?)
)
滑翔 检查How does one use glide to download an image into a bitmap?
用于通用图像加载器 Java代码
imageLoader.loadImage(imageUrl, new SimpleImageLoadingListener()
@Override
public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage)
// loaded bitmap is here (loadedImage)
);
【讨论】:
【参考方案8】:按照方法在android中获取位图的url,只需传递此图像的链接并获取位图。
public static Bitmap getBitmapFromURL(String imgUrl)
try
URL url = new URL(imgUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoInput(true);
connection.connect();
InputStream input = connection.getInputStream();
Bitmap myBitmap = BitmapFactory.decodeStream(input);
return myBitmap;
catch (IOException e)
// Log exception
return null;
【讨论】:
【参考方案9】:Glide.with(context)
.load("http://test.com/yourimage.jpg")
.asBitmap() // переводим его в нужный формат
.fitCenter()
.into(new SimpleTarget<Bitmap>(100,100)
@Override
public void onResourceReady(Bitmap bitmap, GlideAnimation<? super Bitmap> glideAnimation)
// do something with you bitmap
bitmap
);
【讨论】:
欢迎来到***。请阅读如何how to answer。【参考方案10】:public static Bitmap getImgBitmapFromUri(final String url, final Activity context, final CropImageView imageView, final File file)
final Bitmap bitmap = null;
AsyncTask.execute(new Runnable()
@Override
public void run()
try
Utils.image = Glide.with(context)
.load(url).asBitmap()
.into(100, 100).get();
catch (InterruptedException e)
e.printStackTrace();
catch (ExecutionException e)
e.printStackTrace();
context.runOnUiThread(new Runnable()
@Override
public void run()
if (imageView != null)
imageView.setImageBitmap(Utils.image);
);
);
return Utils.image;
使用 Glide 库并在发布的工作线程中运行以下代码
【讨论】:
为了其他用户的利益,请编辑以包含解释此答案的评论。【参考方案11】:请尝试以下步骤。
1) 在类或适配器中创建 AsyncTask(如果要更改列表项图像)。
public class AsyncTaskLoadImage extends AsyncTask<String, String, Bitmap>
private final static String TAG = "AsyncTaskLoadImage";
private ImageView imageView;
public AsyncTaskLoadImage(ImageView imageView)
this.imageView = imageView;
@Override
protected Bitmap doInBackground(String... params)
Bitmap bitmap = null;
try
URL url = new URL(params[0]);
bitmap = BitmapFactory.decodeStream((InputStream) url.getContent());
catch (IOException e)
e.printStackTrace();
catch (Exception e)
e.printStackTrace();
return bitmap;
@Override
protected void onPostExecute(Bitmap bitmap)
try
int width, height;
height = bitmap.getHeight();
width = bitmap.getWidth();
Bitmap bmpGrayscale = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(bmpGrayscale);
Paint paint = new Paint();
ColorMatrix cm = new ColorMatrix();
cm.setSaturation(0);
ColorMatrixColorFilter f = new ColorMatrixColorFilter(cm);
paint.setColorFilter(f);
c.drawBitmap(bitmap, 0, 0, paint);
imageView.setImageBitmap(bmpGrayscale);
catch (Exception e)
e.printStackTrace();
2) 从您的活动、片段或适配器(在 onBindViewHolder 内部)调用 AsyncTask。
2.a) 对于适配器:
String src = current.getProductImage();
new AsyncTaskLoadImage(holder.icon).execute(src);
2.b) 对于活动和片段:
**Activity:**
ImageView imagview= (ImageView) findViewById(R.Id.imageview);
String src = (your image string);
new AsyncTaskLoadImage(imagview).execute(src);
**Fragment:**
ImageView imagview= (ImageView)view.findViewById(R.Id.imageview);
String src = (your image string);
new AsyncTaskLoadImage(imagview).execute(src);
3) 请运行应用程序并检查图像。
编码愉快....:)
【讨论】:
【参考方案12】:如果不使用 AsyncTask 从位图加载 URL,请在 setContentView(R.layout.abc); 之后写两行
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
try
URL url = new URL("http://....");
Bitmap image = BitmapFactory.decodeStream(url.openConnection().getInputStream());
catch(IOException e)
System.out.println(e);
【讨论】:
【参考方案13】:如果您使用 Picasso for Images,您可以尝试以下方法!
public static Bitmap getImageBitmapFromURL(Context context, String imageUrl)
Bitmap imageBitmap = null;
try
imageBitmap = new AsyncTask<Void, Void, Bitmap>()
@Override
protected Bitmap doInBackground(Void... params)
try
int targetHeight = 200;
int targetWidth = 200;
return Picasso.with(context).load(String.valueOf(imageUrl))
//.resize(targetWidth, targetHeight)
.placeholder(R.drawable.raw_image)
.error(R.drawable.raw_error_image)
.get();
catch (IOException e)
e.printStackTrace();
return null;
.execute().get();
catch (InterruptedException e)
e.printStackTrace();
return imageBitmap;
【讨论】:
【参考方案14】:如果您使用的是 Glide 和 Kotlin,
Glide.with(this)
.asBitmap()
.load("https://...")
.addListener(object : RequestListener<Bitmap>
override fun onLoadFailed(
e: GlideException?,
model: Any?,
target: Target<Bitmap>?,
isFirstResource: Boolean
): Boolean
Toast.makeText(this@MainActivity, "failed: " + e?.printStackTrace(), Toast.LENGTH_SHORT).show()
return false
override fun onResourceReady(
resource: Bitmap?,
model: Any?,
target: Target<Bitmap>?,
dataSource: DataSource?,
isFirstResource: Boolean
): Boolean
//image is ready, you can get bitmap here
var bitmap = resource
return false
)
.into(imageView)
【讨论】:
【参考方案15】:它在 Pie OS 中的工作使用这个
@Override
protected void onCreate()
super.onCreate();
//setNotificationBadge();
if (android.os.Build.VERSION.SDK_INT >= 9)
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
BottomNavigationView bottomNavigationView = (BottomNavigationView) findViewById(R.id.navigation);
Menu menu = bottomNavigationView.getMenu();
MenuItem userImage = menu.findItem(R.id.navigation_download);
userImage.setTitle("Login");
runOnUiThread(new Runnable()
@Override
public void run()
try
URL url = new URL("https://rukminim1.flixcart.com/image/832/832/jmux18w0/mobile/b/g/n/mi-redmi-6-mzb6387in-original-imaf9z8eheryfbsu.jpeg?q=70");
Bitmap myBitmap = BitmapFactory.decodeStream(url.openConnection().getInputStream());
Log.e("keshav", "Bitmap " + myBitmap);
userImage.setIcon(new BitmapDrawable(getResources(), myBitmap));
catch (IOException e)
Log.e("keshav", "Exception " + e.getMessage());
);
【讨论】:
【参考方案16】:使用 Kotlin 协程处理线程
代码崩溃的原因是Bitmap
试图在Main Thread
上创建,这是不允许的,因为它可能会导致Android Not Responding (ANR) 错误。 p>
使用的概念
Kotlin 协程 notes. Loading, Content, Error (LCE) 模式在下面使用。如果有兴趣,您可以通过this talk and video了解更多信息。 LiveData 用于返回数据。我在these notes 中编译了我最喜欢的LiveData 资源。 在奖励代码中,toBitmap()
是一个Kotlin extension function,要求将该库添加到应用依赖项中。
实施
代码
1。在另一个线程中创建 Bitmap
,然后创建 Main Thread
。
在这个使用 Kotlin Coroutines 的示例中,函数在 Dispatchers.IO
线程中执行,该线程用于基于 CPU 的操作。该函数以 suspend
为前缀,这是一种 Coroutine 语法。
奖励 - 在创建 Bitmap
之后,它也会被压缩为 ByteArray
,因此它可以通过稍后在此 full sample 中概述的 Intent
传递。
Repository.kt
suspend fun bitmapToByteArray(url: String) = withContext(Dispatchers.IO)
MutableLiveData<Lce<ContentResult.ContentBitmap>>().apply
postValue(Lce.Loading())
postValue(Lce.Content(ContentResult.ContentBitmap(
ByteArrayOutputStream().apply
try
BitmapFactory.decodeStream(URL(url).openConnection().apply
doInput = true
connect()
.getInputStream())
catch (e: IOException)
postValue(Lce.Error(ContentResult.ContentBitmap(ByteArray(0), "bitmapToByteArray error or null - $e.localizedMessage")))
null
?.compress(CompressFormat.JPEG, BITMAP_COMPRESSION_QUALITY, this)
.toByteArray(), "")))
ViewModel.kt
//Calls bitmapToByteArray from the Repository
private fun bitmapToByteArray(url: String) = liveData
emitSource(switchMap(repository.bitmapToByteArray(url)) lce ->
when (lce)
is Lce.Loading -> liveData
is Lce.Content -> liveData
emit(Event(ContentResult.ContentBitmap(lce.packet.image, lce.packet.errorMessage)))
is Lce.Error -> liveData
Crashlytics.log(Log.WARN, LOG_TAG,
"bitmapToByteArray error or null - $lce.packet.errorMessage")
)
奖励 - 将 ByteArray
转换回 Bitmap
。
Utils.kt
fun ByteArray.byteArrayToBitmap(context: Context) =
run
BitmapFactory.decodeByteArray(this, BITMAP_OFFSET, size).run
if (this != null) this
// In case the Bitmap loaded was empty or there is an error I have a default Bitmap to return.
else AppCompatResources.getDrawable(context, ic_coinverse_48dp)?.toBitmap()
【讨论】:
【参考方案17】:fun getBitmap(url : String?) : Bitmap?
var bmp : Bitmap ? = null
Picasso.get().load(url).into(object : com.squareup.picasso.Target
override fun onBitmapLoaded(bitmap: Bitmap?, from: Picasso.LoadedFrom?)
bmp = bitmap
override fun onPrepareLoad(placeHolderDrawable: Drawable?)
override fun onBitmapFailed(e: Exception?, errorDrawable: Drawable?)
)
return bmp
用毕加索试试这个
【讨论】:
【参考方案18】: private class AsyncTaskRunner extends AsyncTask<String, String, String>
String Imageurl;
public AsyncTaskRunner(String Imageurl)
this.Imageurl = Imageurl;
@Override
protected String doInBackground(String... strings)
try
URL url = new URL(Imageurl);
thumbnail_r = BitmapFactory.decodeStream(url.openConnection().getInputStream());
catch (IOException e)
return null;
@Override
protected void onPostExecute(String s)
super.onPostExecute(s);
imgDummy.setImageBitmap(thumbnail_r);
UtilityMethods.tuchOn(relProgress);
像这样调用异步任务:
AsyncTaskRunner asyncTaskRunner = new AsyncTaskRunner(uploadsModel.getImages());
asyncTaskRunner.execute();
【讨论】:
【参考方案19】:此方法将使用 kotlin 协程来解决问题,因此它不会阻塞 UI 主线程并且将返回调整大小的圆形位图图像(如个人资料图像)
private var image: Bitmap? = null
private fun getBitmapFromURL(src: String?)
CoroutineScope(Job() + Dispatchers.IO).launch
try
val url = URL(src)
val bitMap = BitmapFactory.decodeStream(url.openConnection().getInputStream())
image = Bitmap.createScaledBitmap(bitMap, 100, 100, true)
catch (e: IOException)
// Log exception
【讨论】:
【参考方案20】:如果您更喜欢 Coil 而不是 Glide。
val imageRequest = ImageRequest.Builder(context)
.data(imageUrl)
.target drawable ->
val bitmap = drawable.toBitmap() // This is the bitmap ?
.build()
ImageLoader(context).enqueue(imageRequest)
【讨论】:
以上是关于Android 从 URL 加载到位图的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 glide 从 android 中的音频 url 获取缩略图
Android:从图库加载的位图在 ImageView 中旋转
如何将图像从 url 加载到小部件的 android 远程视图中