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 客户端HttpURLConnectionApache 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 远程视图中

Android - 在显示进度时将图像从 URL 加载到 ImageView(不保存图像)

如何从android中重定向url加载图像