-
Android在ImageView上直接显示网络图片
2017-08-16 18:33:19在原生的ImageView中,没有一个方法是可以直接显示网络的图片的,当我们经常需要显示网络图片时,每次都有一大堆的操作,这会很麻烦,今天就教大家在ImageView上轻松显示网络图片。 自定义ImageView方法 写一个类让...原文博客:Doi技术团队
链接地址:https://blog.doiduoyi.com/authors/1584446358138
初心:记录优秀的Doi技术团队学习经历在原生的ImageView中,没有一个方法是可以直接显示网络的图片的,当我们经常需要显示网络图片时,每次都有一大堆的操作,这会很麻烦,今天就教大家在ImageView上轻松显示网络图片。
自定义ImageView方法
写一个类让它继承ImageView,并增加一个setImageURL(path)方法
import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Handler; import android.os.Message; import android.util.AttributeSet; import android.widget.ImageView; import android.widget.Toast; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; public class MyImageView extends ImageView { public static final int GET_DATA_SUCCESS = 1; public static final int NETWORK_ERROR = 2; public static final int SERVER_ERROR = 3; //子线程不能操作UI,通过Handler设置图片 private Handler handler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what){ case GET_DATA_SUCCESS: Bitmap bitmap = (Bitmap) msg.obj; setImageBitmap(bitmap); break; case NETWORK_ERROR: Toast.makeText(getContext(),"网络连接失败",Toast.LENGTH_SHORT).show(); break; case SERVER_ERROR: Toast.makeText(getContext(),"服务器发生错误",Toast.LENGTH_SHORT).show(); break; } } }; public MyImageView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } public MyImageView(Context context) { super(context); } public MyImageView(Context context, AttributeSet attrs) { super(context, attrs); } //设置网络图片 public void setImageURL(final String path) { //开启一个线程用于联网 new Thread() { @Override public void run() { try { //把传过来的路径转成URL URL url = new URL(path); //获取连接 HttpURLConnection connection = (HttpURLConnection) url.openConnection(); //使用GET方法访问网络 connection.setRequestMethod("GET"); //超时时间为10秒 connection.setConnectTimeout(10000); //获取返回码 int code = connection.getResponseCode(); if (code == 200) { InputStream inputStream = connection.getInputStream(); //使用工厂把网络的输入流生产Bitmap Bitmap bitmap = BitmapFactory.decodeStream(inputStream); //利用Message把图片发给Handler Message msg = Message.obtain(); msg.obj = bitmap; msg.what = GET_DATA_SUCCESS; handler.sendMessage(msg); inputStream.close(); }else { //服务启发生错误 handler.sendEmptyMessage(SERVER_ERROR); } } catch (IOException e) { e.printStackTrace(); //网络连接错误 handler.sendEmptyMessage(NETWORK_ERROR); } } }.start(); } }
在布局上不能使用ImageView,要使用MyImageView,要把刚才重写的一个MyImageView的全路径写上
<Button android:text="加载网络图片" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/button" /> <com.example.dell.myapplication.MyImageView android:id="@+id/image_view" android:layout_width="match_parent" android:layout_height="match_parent" />
在MainActivity上,只要调用setImageURL(),直接把网络的图片路径写上就可以显示网络的图片了
final MyImageView myImageView = (MyImageView) findViewById(R.id.image_view); Button button = (Button) findViewById(R.id.button); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //直接把网络的图片路径写上就可以显示网络的图片了 myImageView.setImageURL("https://pic.cnblogs.com/avatar/1142647/20170416093225.png"); } });
最后别忘了添加访问网络的权限
<uses-permission android:name="android.permission.INTERNET"/>
效果图
压缩
这是比较简单的从网络获取照片,直接在ImageView上显示,但是你有没有考虑过如果网络的图片很大,已经超出了手机屏幕的大小,如果还是加载原图的话无疑是浪费内存,还有可能造成内存溢出,所以我们有必要对网络的图片进行压缩,下面就开始讲网络图片的压缩。
首先获取ImageView要显示的宽度和高度
/** * 获取ImageView实际的宽度 * @return 返回ImageView实际的宽度 */ public int realImageViewWith() { DisplayMetrics displayMetrics = getContext().getResources().getDisplayMetrics(); ViewGroup.LayoutParams layoutParams = getLayoutParams(); //如果ImageView设置了宽度就可以获取实在宽带 int width = getWidth(); if (width <= 0) { //如果ImageView没有设置宽度,就获取父级容器的宽度 width = layoutParams.width; } if (width <= 0) { //获取ImageView宽度的最大值 width = getMaxWidth(); } if (width <= 0) { //获取屏幕的宽度 width = displayMetrics.widthPixels; } Log.e("ImageView实际的宽度", String.valueOf(width)); return width; } /** * 获取ImageView实际的高度 * @return 返回ImageView实际的高度 */ public int realImageViewHeight() { DisplayMetrics displayMetrics = getContext().getResources().getDisplayMetrics(); ViewGroup.LayoutParams layoutParams = getLayoutParams(); //如果ImageView设置了高度就可以获取实在宽度 int height = getHeight(); if (height <= 0) { //如果ImageView没有设置高度,就获取父级容器的高度 height = layoutParams.height; } if (height <= 0) { //获取ImageView高度的最大值 height = getMaxHeight(); } if (height <= 0) { //获取ImageView高度的最大值 height = displayMetrics.heightPixels; } Log.e("ImageView实际的高度", String.valueOf(height)); return height; }
然后是通过网络图片的大小计算要压缩的比率
/** * 获得需要压缩的比率 * * @param options 需要传入已经BitmapFactory.decodeStream(is, null, options); * @return 返回压缩的比率,最小为1 */ public int getInSampleSize(BitmapFactory.Options options) { int inSampleSize = 1; int realWith = realImageViewWith(); int realHeight = realImageViewHeight(); int outWidth = options.outWidth; Log.e("网络图片实际的宽度", String.valueOf(outWidth)); int outHeight = options.outHeight; Log.e("网络图片实际的高度", String.valueOf(outHeight)); //获取比率最大的那个 if (outWidth > realWith || outHeight > realHeight) { int withRadio = Math.round(outWidth / realWith); int heightRadio = Math.round(outHeight / realHeight); inSampleSize = withRadio > heightRadio ? withRadio : heightRadio; } Log.e("压缩比率", String.valueOf(inSampleSize)); return inSampleSize; }
获得压缩比率后,就可以进行压缩了
/** * 根据输入流返回一个压缩的图片 * @param input 图片的输入流 * @return 压缩的图片 */ public Bitmap getCompressBitmap(InputStream input) { //因为InputStream要使用两次,但是使用一次就无效了,所以需要复制两个 ByteArrayOutputStream baos = new ByteArrayOutputStream(); try { byte[] buffer = new byte[1024]; int len; while ((len = input.read(buffer)) > -1 ) { baos.write(buffer, 0, len); } baos.flush(); } catch (IOException e) { e.printStackTrace(); } //复制新的输入流 InputStream is = new ByteArrayInputStream(baos.toByteArray()); InputStream is2 = new ByteArrayInputStream(baos.toByteArray()); //只是获取网络图片的大小,并没有真正获取图片 BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeStream(is, null, options); //获取图片并进行压缩 options.inSampleSize = getInSampleSize(options); options.inJustDecodeBounds = false; return BitmapFactory.decodeStream(is2, null, options); }
最后就是在setImageURL()的方法中把 Bitmap bitmap = BitmapFactory.decodeStream(inputStream); 改成下面的方法
Bitmap bitmap = getCompressBitmap(inputStream);
缓存
有时候提高运行效率和节省流量,经常会使用的缓存,数据缓存后就算没有网络都可以使用,下面就开始学习缓存吧,我这种缓存不是正规的缓存技术。
将setImageURL()方法改成如下,并增加两全局变量imagePath、isUseCache;
//是否启用缓存 public boolean isUseCache = false; private String imagePath; //设置网络图片 public void setImageURL(String path) { imagePath = path; if (isUseCache){ useCacheImage(); }else { useNetWorkImage(); } }
把之前setImageURL()的大部分功能放到useNetWorkImage()方法中,增加一个判断:是否缓存图片
//使用网络图片显示 public void useNetWorkImage(){ //开启一个线程用于联网 new Thread() { @Override public void run() { try { //把传过来的路径转成URL URL url = new URL(imagePath); //获取连接 HttpURLConnection connection = (HttpURLConnection) url.openConnection(); //使用GET方法访问网络 connection.setRequestMethod("GET"); //超时时间为10秒 connection.setConnectTimeout(10000); //获取返回码 int code = connection.getResponseCode(); if (code == 200) { Bitmap bitmap; //获取网络输入流 InputStream inputStream = connection.getInputStream(); //判断是否使用缓存图片 if (isUseCache){ //因为InputStream要使用两次,但是使用一次就无效了,所以需要复制两个 ByteArrayOutputStream baos = new ByteArrayOutputStream(); try { byte[] buffer = new byte[1024]; int len; while ((len = inputStream.read(buffer)) > -1) { baos.write(buffer, 0, len); } baos.flush(); } catch (IOException e) { e.printStackTrace(); } //复制新的输入流 InputStream is = new ByteArrayInputStream(baos.toByteArray()); InputStream is2 = new ByteArrayInputStream(baos.toByteArray()); //调用压缩方法显示图片 bitmap = getCompressBitmap(is); //调用缓存图片方法 cacheImage(is2); }else { //调用压缩方法 bitmap = getCompressBitmap(inputStream); } //利用Message把图片发给Handler Message msg = Message.obtain(); msg.obj = bitmap; msg.what = GET_DATA_SUCCESS; handler.sendMessage(msg); inputStream.close(); } else { //服务启发生错误 handler.sendEmptyMessage(SERVER_ERROR); } } catch (IOException e) { e.printStackTrace(); //网络连接错误 handler.sendEmptyMessage(NETWORK_ERROR); } } }.start(); }
创建一个方法用于根据传了的网址生成一个独一无二文件,之后会根据这个路径生成图片和查找是否有缓存图片
/** * 根据网址生成一个文件名 * @return 文件名 */ public String getURLPath() { StringBuilder urlStr2 = new StringBuilder(); String[] strings = imagePath.split("\\/"); for (String string : strings) { urlStr2.append(string); } Log.e("MyImageView","文件名:"+urlStr2.toString()); return urlStr2.toString(); }
根据生成的路径缓存图片
/** * 缓存网络的图片 * @param inputStream 网络的输入流 */ public void cacheImage(InputStream inputStream) { try { File file = new File(getContext().getCacheDir(), getURLPath()); FileOutputStream fos = new FileOutputStream(file); int len; byte[] buffer = new byte[1024]; while ((len = inputStream.read(buffer)) != -1) { fos.write(buffer, 0, len); } fos.close(); Log.e("MyImageView","缓存成功"); } catch (IOException e) { e.printStackTrace(); Log.e("MyImageView","缓存失败"); } }
最后就可以直接使用缓存图片了
//使用缓存图片 public void useCacheImage() { //创建路径一样的文件 File file = new File(getContext().getCacheDir(), getURLPath()); //判断文件是否存在 if (file != null && file.length() > 0) { //使用本地图片 try { InputStream inputStream = new FileInputStream(file); //调用压缩方法显示图片 Bitmap bitmap = getCompressBitmap(inputStream); //利用Message把图片发给Handler Message msg = Message.obtain(); msg.obj = bitmap; msg.what = GET_DATA_SUCCESS; handler.sendMessage(msg); Log.e("MyImageView","使用缓存图片"); } catch (FileNotFoundException e) { e.printStackTrace(); } }else { //使用网络图片 useNetWorkImage(); Log.e("MyImageView","使用网络图片"); } }
现在就可以使用缓存了,记得要吧isUseCache设置成true
//直接把网络的图片路径写上就可以显示网络的图片了 String url = "https://pic.cnblogs.com/avatar/1142647/20170416093225.png"; //设置成true才会启动缓存,默认是false myImageView.isUseCache = true; myImageView.setImageURL(url);
整篇MyImageView.java的代码
import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Handler; import android.os.Message; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.Log; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.Toast; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; public class MyImageView extends ImageView { private String imagePath; //是否启用缓存 public boolean isUseCache = false; public static final int GET_DATA_SUCCESS = 1; public static final int NETWORK_ERROR = 2; public static final int SERVER_ERROR = 3; //子线程不能操作UI,通过Handler设置图片 private Handler handler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case GET_DATA_SUCCESS: Bitmap bitmap = (Bitmap) msg.obj; setImageBitmap(bitmap); break; case NETWORK_ERROR: Toast.makeText(getContext(), "网络连接失败", Toast.LENGTH_SHORT).show(); break; case SERVER_ERROR: Toast.makeText(getContext(), "服务器发生错误", Toast.LENGTH_SHORT).show(); break; } } }; public MyImageView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } public MyImageView(Context context) { super(context); } public MyImageView(Context context, AttributeSet attrs) { super(context, attrs); } //设置网络图片 public void setImageURL(String path) { imagePath = path; if (isUseCache){ useCacheImage(); }else { useNetWorkImage(); } } //使用网络图片显示 public void useNetWorkImage(){ //开启一个线程用于联网 new Thread() { @Override public void run() { try { //把传过来的路径转成URL URL url = new URL(imagePath); //获取连接 HttpURLConnection connection = (HttpURLConnection) url.openConnection(); //使用GET方法访问网络 connection.setRequestMethod("GET"); //超时时间为10秒 connection.setConnectTimeout(10000); //获取返回码 int code = connection.getResponseCode(); if (code == 200) { Bitmap bitmap; //获取网络输入流 InputStream inputStream = connection.getInputStream(); //判断是否使用缓存图片 if (isUseCache){ //因为InputStream要使用两次,但是使用一次就无效了,所以需要复制两个 ByteArrayOutputStream baos = new ByteArrayOutputStream(); try { byte[] buffer = new byte[1024]; int len; while ((len = inputStream.read(buffer)) > -1) { baos.write(buffer, 0, len); } baos.flush(); } catch (IOException e) { e.printStackTrace(); } //复制新的输入流 InputStream is = new ByteArrayInputStream(baos.toByteArray()); InputStream is2 = new ByteArrayInputStream(baos.toByteArray()); //调用压缩方法显示图片 bitmap = getCompressBitmap(is); //调用缓存图片方法 cacheImage(is2); }else { //调用压缩方法 bitmap = getCompressBitmap(inputStream); } //利用Message把图片发给Handler Message msg = Message.obtain(); msg.obj = bitmap; msg.what = GET_DATA_SUCCESS; handler.sendMessage(msg); inputStream.close(); } else { //服务启发生错误 handler.sendEmptyMessage(SERVER_ERROR); } } catch (IOException e) { e.printStackTrace(); //网络连接错误 handler.sendEmptyMessage(NETWORK_ERROR); } } }.start(); } //使用缓存图片 public void useCacheImage() { //创建路径一样的文件 File file = new File(getContext().getCacheDir(), getURLPath()); //判断文件是否存在 if (file != null && file.length() > 0) { //使用本地图片 try { InputStream inputStream = new FileInputStream(file); //调用压缩方法显示图片 Bitmap bitmap = getCompressBitmap(inputStream); //利用Message把图片发给Handler Message msg = Message.obtain(); msg.obj = bitmap; msg.what = GET_DATA_SUCCESS; handler.sendMessage(msg); Log.e("MyImageView","使用缓存图片"); } catch (FileNotFoundException e) { e.printStackTrace(); } }else { //使用网络图片 useNetWorkImage(); Log.e("MyImageView","使用网络图片"); } } /** * 缓存网络的图片 * @param inputStream 网络的输入流 */ public void cacheImage(InputStream inputStream) { try { File file = new File(getContext().getCacheDir(), getURLPath()); FileOutputStream fos = new FileOutputStream(file); int len; byte[] buffer = new byte[1024]; while ((len = inputStream.read(buffer)) != -1) { fos.write(buffer, 0, len); } fos.close(); Log.e("MyImageView","缓存成功"); } catch (IOException e) { e.printStackTrace(); Log.e("MyImageView","缓存失败"); } } /** * 根据网址生成一个文件名 * @return 文件名 */ public String getURLPath() { StringBuilder urlStr2 = new StringBuilder(); String[] strings = imagePath.split("\\/"); for (String string : strings) { urlStr2.append(string); } Log.e("MyImageView","文件名:"+urlStr2.toString()); return urlStr2.toString(); } /** * 根据输入流返回一个压缩的图片 * * @param input 图片的输入流 * @return 压缩的图片 */ public Bitmap getCompressBitmap(InputStream input) { //因为InputStream要使用两次,但是使用一次就无效了,所以需要复制两个 ByteArrayOutputStream baos = new ByteArrayOutputStream(); try { byte[] buffer = new byte[1024]; int len; while ((len = input.read(buffer)) > -1) { baos.write(buffer, 0, len); } baos.flush(); } catch (IOException e) { e.printStackTrace(); } //复制新的输入流 InputStream is = new ByteArrayInputStream(baos.toByteArray()); InputStream is2 = new ByteArrayInputStream(baos.toByteArray()); //只是获取网络图片的大小,并没有真正获取图片 BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeStream(is, null, options); //获取图片并进行压缩 options.inSampleSize = getInSampleSize(options); options.inJustDecodeBounds = false; return BitmapFactory.decodeStream(is2, null, options); } /** * 获得需要压缩的比率 * * @param options 需要传入已经BitmapFactory.decodeStream(is, null, options); * @return 返回压缩的比率,最小为1 */ public int getInSampleSize(BitmapFactory.Options options) { int inSampleSize = 1; int realWith = realImageViewWith(); int realHeight = realImageViewHeight(); int outWidth = options.outWidth; Log.e("网络图片实际的宽度", String.valueOf(outWidth)); int outHeight = options.outHeight; Log.e("网络图片实际的高度", String.valueOf(outHeight)); //获取比率最大的那个 if (outWidth > realWith || outHeight > realHeight) { int withRadio = Math.round(outWidth / realWith); int heightRadio = Math.round(outHeight / realHeight); inSampleSize = withRadio > heightRadio ? withRadio : heightRadio; } Log.e("压缩比率", String.valueOf(inSampleSize)); return inSampleSize; } /** * 获取ImageView实际的宽度 * * @return 返回ImageView实际的宽度 */ public int realImageViewWith() { DisplayMetrics displayMetrics = getContext().getResources().getDisplayMetrics(); ViewGroup.LayoutParams layoutParams = getLayoutParams(); //如果ImageView设置了宽度就可以获取实在宽带 int width = getWidth(); if (width <= 0) { //如果ImageView没有设置宽度,就获取父级容器的宽度 width = layoutParams.width; } if (width <= 0) { //获取ImageView宽度的最大值 width = getMaxWidth(); } if (width <= 0) { //获取屏幕的宽度 width = displayMetrics.widthPixels; } Log.e("ImageView实际的宽度", String.valueOf(width)); return width; } /** * 获取ImageView实际的高度 * * @return 返回ImageView实际的高度 */ public int realImageViewHeight() { DisplayMetrics displayMetrics = getContext().getResources().getDisplayMetrics(); ViewGroup.LayoutParams layoutParams = getLayoutParams(); //如果ImageView设置了高度就可以获取实在宽度 int height = getHeight(); if (height <= 0) { //如果ImageView没有设置高度,就获取父级容器的高度 height = layoutParams.height; } if (height <= 0) { //获取ImageView高度的最大值 height = getMaxHeight(); } if (height <= 0) { //获取ImageView高度的最大值 height = displayMetrics.heightPixels; } Log.e("ImageView实际的高度", String.valueOf(height)); return height; } }
使用网络图片的效果图使用缓存图片的效果图
使用图片加载框架Glide
在这开源非常发达的时代,肯定会有大牛为我们做了个种各样的开源框架,根本不需要我们做这么复杂的工作,下面就简单使用图片加载框架Glide
在使用前要添加Glide的依赖库
compile 'com.github.bumptech.glide:glide:4.0.0'
刚才的条件不变,把点击事件的操作换成下面两行代码
String url = "https://pic.cnblogs.com/avatar/1142647/20170416093225.png"; Glide.with(MainActivity.this).load(url).into(myImageView);
是不是非常简单,有了这个开源库,你还愿意写那一大堆的代码吗,我想不会,更强大的是它已经有缓存功能,这一切它都帮你做好了。
加载网络图片的效果图
使用缓存的效果图
既然那么强大的开源库,我们就简单地了解它是如何使用的,先看看with()方法的源码,它可以接收6中参数,所以在各种情况下都能使用
public static RequestManager with(Context context) { return getRetriever(context).get(context); } public static RequestManager with(Activity activity) { return getRetriever(activity).get(activity); } public static RequestManager with(FragmentActivity activity) { return getRetriever(activity).get(activity); } public static RequestManager with(android.app.Fragment fragment) { return getRetriever(fragment.getActivity()).get(fragment); } public static RequestManager with(Fragment fragment) { return getRetriever(fragment.getActivity()).get(fragment); } public static RequestManager with(View view) { return getRetriever(view.getContext()).get(view); }
然后是load()方法,虽然只有一个方法,但是所能做的事情却不少,比如我刚才只是传了一个String类型的,它就可以帮我加载了网络的图片,它还支持File(加载本地图片)、int(加载应用文件的源)、byte[](字节流)、Uri
public RequestBuilder<Drawable> load(@Nullable Object model) { return asDrawable().load(model); }
我们就试试加载应用的图片
Glide.with(MainActivity.this).load(R.mipmap.ic_launcher).into(myImageView);
效果图
最后是into()方法,就是把我们要显示的ImageView加载进去,那就大功告成了。
重复使用过程Glide-->with()-->load()-->into()
项目源代码:https://resource.doiduoyi.com/#2o4csq2
-
Android Volley完全解析(二),使用Volley加载网络图片
2014-04-17 09:23:22在上一篇文章中,我们了解了Volley到底是什么,以及它的基本用法。本篇文章中我们即将学习关于Volley更加高级...我们都知道,Universal-Image-Loader具备非常强大的加载网络图片的功能,而使用Volley,我们也可以实现基转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/17482165
在上一篇文章中,我们了解了Volley到底是什么,以及它的基本用法。本篇文章中我们即将学习关于Volley更加高级的用法,如何你还没有看过我的上一篇文章的话,建议先去阅读Android Volley完全解析(一),初识Volley的基本用法。
在上篇文章中有提到过,Volley是将AsyncHttpClient和Universal-Image-Loader的优点集成于一身的一个框架。我们都知道,Universal-Image-Loader具备非常强大的加载网络图片的功能,而使用Volley,我们也可以实现基本类似的效果,并且在性能上也豪不逊色于Universal-Image-Loader,下面我们就来具体学习一下吧。
1. ImageRequest的用法
前面我们已经学习过了StringRequest和JsonRequest的用法,并且总结出了它们的用法都是非常类似的,基本就是进行以下三步操作即可:
1. 创建一个RequestQueue对象。
2. 创建一个Request对象。
3. 将Request对象添加到RequestQueue里面。
其中,StringRequest和JsonRequest都是继承自Request的,所以它们的用法才会如此类似。那么不用多说,今天我们要学习的ImageRequest,相信你从名字上就已经猜出来了,它也是继承自Request的,因此它的用法也是基本相同的,首先需要获取到一个RequestQueue对象,可以调用如下方法获取到:
接下来自然要去new出一个ImageRequest对象了,代码如下所示:RequestQueue mQueue = Volley.newRequestQueue(context);
ImageRequest imageRequest = new ImageRequest( "http://developer.android.com/images/home/aw_dac.png", new Response.Listener<Bitmap>() { @Override public void onResponse(Bitmap response) { imageView.setImageBitmap(response); } }, 0, 0, Config.RGB_565, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { imageView.setImageResource(R.drawable.default_image); } });
可以看到,ImageRequest的构造函数接收六个参数,第一个参数就是图片的URL地址,这个没什么需要解释的。第二个参数是图片请求成功的回调,这里我们把返回的Bitmap参数设置到ImageView中。第三第四个参数分别用于指定允许图片最大的宽度和高度,如果指定的网络图片的宽度或高度大于这里的最大值,则会对图片进行压缩,指定成0的话就表示不管图片有多大,都不会进行压缩。第五个参数用于指定图片的颜色属性,Bitmap.Config下的几个常量都可以在这里使用,其中ARGB_8888可以展示最好的颜色属性,每个图片像素占据4个字节的大小,而RGB_565则表示每个图片像素占据2个字节大小。第六个参数是图片请求失败的回调,这里我们当请求失败时在ImageView中显示一张默认图片。
最后将这个ImageRequest对象添加到RequestQueue里就可以了,如下所示:
mQueue.add(imageRequest);
现在如果运行一下程序,并尝试发出这样一条网络请求,很快就能看到网络上的图片在ImageView中显示出来了,如下图所示:
2. ImageLoader的用法
如果你觉得ImageRequest已经非常好用了,那我只能说你太容易满足了 ^_^。实际上,Volley在请求网络图片方面可以做到的还远远不止这些,而ImageLoader就是一个很好的例子。ImageLoader也可以用于加载网络上的图片,并且它的内部也是使用ImageRequest来实现的,不过ImageLoader明显要比ImageRequest更加高效,因为它不仅可以帮我们对图片进行缓存,还可以过滤掉重复的链接,避免重复发送请求。
由于ImageLoader已经不是继承自Request的了,所以它的用法也和我们之前学到的内容有所不同,总结起来大致可以分为以下四步:
1. 创建一个RequestQueue对象。
2. 创建一个ImageLoader对象。
3. 获取一个ImageListener对象。
4. 调用ImageLoader的get()方法加载网络上的图片。
下面我们就来按照这个步骤,学习一下ImageLoader的用法吧。首先第一步的创建RequestQueue对象我们已经写过很多遍了,相信已经不用再重复介绍了,那么就从第二步开始学习吧,新建一个ImageLoader对象,代码如下所示:
ImageLoader imageLoader = new ImageLoader(mQueue, new ImageCache() { @Override public void putBitmap(String url, Bitmap bitmap) { } @Override public Bitmap getBitmap(String url) { return null; } });
可以看到,ImageLoader的构造函数接收两个参数,第一个参数就是RequestQueue对象,第二个参数是一个ImageCache对象,这里我们先new出一个空的ImageCache的实现即可。
接下来需要获取一个ImageListener对象,代码如下所示:
ImageListener listener = ImageLoader.getImageListener(imageView, R.drawable.default_image, R.drawable.failed_image);
我们通过调用ImageLoader的getImageListener()方法能够获取到一个ImageListener对象,getImageListener()方法接收三个参数,第一个参数指定用于显示图片的ImageView控件,第二个参数指定加载图片的过程中显示的图片,第三个参数指定加载图片失败的情况下显示的图片。
最后,调用ImageLoader的get()方法来加载图片,代码如下所示:
imageLoader.get("https://img-my.csdn.net/uploads/201404/13/1397393290_5765.jpeg", listener);
get()方法接收两个参数,第一个参数就是图片的URL地址,第二个参数则是刚刚获取到的ImageListener对象。当然,如果你想对图片的大小进行限制,也可以使用get()方法的重载,指定图片允许的最大宽度和高度,如下所示:
imageLoader.get("https://img-my.csdn.net/uploads/201404/13/1397393290_5765.jpeg", listener, 200, 200);
现在运行一下程序并开始加载图片,你将看到ImageView中会先显示一张默认的图片,等到网络上的图片加载完成后,ImageView则会自动显示该图,效果如下图所示。
虽然现在我们已经掌握了ImageLoader的用法,但是刚才介绍的ImageLoader的优点却还没有使用到。为什么呢?因为这里创建的ImageCache对象是一个空的实现,完全没能起到图片缓存的作用。其实写一个ImageCache也非常简单,但是如果想要写一个性能非常好的ImageCache,最好就要借助Android提供的LruCache功能了,如果你对LruCache还不了解,可以参考我之前的一篇博客Android高效加载大图、多图解决方案,有效避免程序OOM。
这里我们新建一个BitmapCache并实现了ImageCache接口,如下所示:
可以看到,这里我们将缓存图片的大小设置为10M。接着修改创建ImageLoader实例的代码,第二个参数传入BitmapCache的实例,如下所示:public class BitmapCache implements ImageCache { private LruCache<String, Bitmap> mCache; public BitmapCache() { int maxSize = 10 * 1024 * 1024; mCache = new LruCache<String, Bitmap>(maxSize) { @Override protected int sizeOf(String key, Bitmap bitmap) { return bitmap.getRowBytes() * bitmap.getHeight(); } }; } @Override public Bitmap getBitmap(String url) { return mCache.get(url); } @Override public void putBitmap(String url, Bitmap bitmap) { mCache.put(url, bitmap); } }
ImageLoader imageLoader = new ImageLoader(mQueue, new BitmapCache());
这样我们就把ImageLoader的功能优势充分利用起来了。
3. NetworkImageView的用法
除了以上两种方式之外,Volley还提供了第三种方式来加载网络图片,即使用NetworkImageView。不同于以上两种方式,NetworkImageView是一个自定义控制,它是继承自ImageView的,具备ImageView控件的所有功能,并且在原生的基础之上加入了加载网络图片的功能。NetworkImageView控件的用法要比前两种方式更加简单,大致可以分为以下五步:
1. 创建一个RequestQueue对象。
2. 创建一个ImageLoader对象。
3. 在布局文件中添加一个NetworkImageView控件。4. 在代码中获取该控件的实例。
5. 设置要加载的图片地址。
其中,第一第二步和ImageLoader的用法是完全一样的,因此这里我们就从第三步开始学习了。首先修改布局文件中的代码,在里面加入NetworkImageView控件,如下所示:
接着在Activity获取到这个控件的实例,这就非常简单了,代码如下所示:<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Send Request" /> <com.android.volley.toolbox.NetworkImageView android:id="@+id/network_image_view" android:layout_width="200dp" android:layout_height="200dp" android:layout_gravity="center_horizontal" /> </LinearLayout>
得到了NetworkImageView控件的实例之后,我们可以调用它的setDefaultImageResId()方法、setErrorImageResId()方法和setImageUrl()方法来分别设置加载中显示的图片,加载失败时显示的图片,以及目标图片的URL地址,如下所示:networkImageView = (NetworkImageView) findViewById(R.id.network_image_view);
其中,setImageUrl()方法接收两个参数,第一个参数用于指定图片的URL地址,第二个参数则是前面创建好的ImageLoader对象。networkImageView.setDefaultImageResId(R.drawable.default_image); networkImageView.setErrorImageResId(R.drawable.failed_image); networkImageView.setImageUrl("https://img-my.csdn.net/uploads/201404/13/1397393290_5765.jpeg", imageLoader);
好了,就是这么简单,现在重新运行一下程序,你将看到和使用ImageLoader来加载图片一模一样的效果,这里我就不再截图了。
这时有的朋友可能就会问了,使用ImageRequest和ImageLoader这两种方式来加载网络图片,都可以传入一个最大宽度和高度的参数来对图片进行压缩,而NetworkImageView中则完全没有提供设置最大宽度和高度的方法,那么是不是使用NetworkImageView来加载的图片都不会进行压缩呢?
其实并不是这样的,NetworkImageView并不需要提供任何设置最大宽高的方法也能够对加载的图片进行压缩。这是由于NetworkImageView是一个控件,在加载图片的时候它会自动获取自身的宽高,然后对比网络图片的宽度,再决定是否需要对图片进行压缩。也就是说,压缩过程是在内部完全自动化的,并不需要我们关心,NetworkImageView会始终呈现给我们一张大小刚刚好的网络图片,不会多占用任何一点内存,这也是NetworkImageView最简单好用的一点吧。
当然了,如果你不想对图片进行压缩的话,其实也很简单,只需要在布局文件中把NetworkImageView的layout_width和layout_height都设置成wrap_content就可以了,这样NetworkImageView就会将该图片的原始大小展示出来,不会进行任何压缩。
这样我们就把使用Volley来加载网络图片的用法都学习完了,今天的讲解也就到此为止,下一篇文章中我会带大家继续探究Volley的更多功能。感兴趣的朋友请继续阅读Android Volley完全解析(三),定制自己的Request。
关注我的技术公众号,每天都有优质技术文章推送。关注我的娱乐公众号,工作、学习累了的时候放松一下自己。
微信扫一扫下方二维码即可关注:
-
OC - 网络图片压缩,获取网络图片尺寸
2016-09-12 11:19:14在项目开发中,我们很多时候,需要在原有图片的基础上,将图片进行压缩。而大多数时候,我们都是在接口方直接获取的图片链接。而此篇,就是为了解决,将压缩网络图片,进而展示在UI上在项目开发中,我们很多时候,需要在原有图片的基础上,将图片进行压缩。而大多数时候,我们都是在接口方直接获取的图片链接。而此篇,就是为了解决,将压缩网络图片,进而展示在UI上
首先,将接口获取的图片,转成NSData :
NSData *data = [NSDatadataWithContentsOfURL:[NSURLURLWithString:@"网络图片地址"]];
将data抓成UIImage:
UIImage *image = [UIImageimageWithData:data];
压缩图片操作:
参数image 当前需要压缩的图片
参数 size 需要压缩到的尺寸
- (UIImage *)thumbnailWithImageWithoutScale:(UIImage *)image size:(CGSize)asize { UIImage *newimage; if (nil == image) { newimage = nil; } else { CGSize oldsize = image.size; CGRect rect; if (asize.width/asize.height > oldsize.width/oldsize.height) { rect.size.width = size.height* oldsize.width/ oldsize.height; rect.size.height = asize.height; rect.origin.x = (asize.width - rect.size.width) / 2; rect.origin.y =0; } else { rect.size.width = asize.width; rect.size.height = size.width* oldsize.height/ oldsize.width; rect.origin.x =0; rect.origin.y = (asize.height - rect.size.height) / 2; } UIGraphicsBeginImageContext(asize); CGContextRef context =UIGraphicsGetCurrentContext(); CGContextSetFillColorWithColor(context, [[UIColorclearColor]CGColor]); UIRectFill(CGRectMake(0,0, asize.width, asize.height)); [image drawInRect:rect]; newimage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); } return newimage; }
调用压缩图片:UIImage *compress = [self thumbnailWithImageWithoutScale:image size:CGSizeMake(200,200)];
到此为止,压缩网络图片操作完成。 注意:上述操作,要在子线程中进行,否则会卡主线程 -
Python实现网络图片抓取
2019-05-08 01:00:06Python在网络爬虫方面功能很强大,程序语言简单高效,下面编程实现一下如何抓取网络图片。本案例分为:单独图片抓取、全网图片抓取。分别给出实现代码,作为学习和技术交流。 Python基础环境准备 参见:...案例分析
概述
Python在网络爬虫方面功能很强大,程序语言简单高效,下面编程实现一下如何抓取网络图片。本案例分为:单独图片抓取、全网图片抓取。分别给出实现代码,作为学习和技术交流。
Python基础环境准备
案例实现
单独图片抓取
import requests url='http://724.169pp.net/169mm/201904/141.2.jppg' resp = requests.get(url).content #print(resp) #下载图片 with open('my.jpg','wb') as f: f.write(resp)
全网图片抓取
import requests import os from pyquery import PyQuery as pq url='https://www.169tp.com/guoneimeinv/' headers={'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3514.0 Safari/537.36guoneimeinv/ tz.js logo.gif 1_061G54TJ0P.jpg 1_061515062KO6.jpg 1_06141601425K5.jpg 1_0613152F01P5.jpg 1_050G4194Y5a.jpg 1_05061336131V3.jpg 1_0506133354E04.jpg 1_05041232432964.jpg 1_05041230246021.jpg 1_0502143440W33.jpg 1_05021432411914.jpg'} # resp=requests.get(url,headers=headers).content.decode('utf-8') # 报错:UnicodeDecodeError: 'utf-8' codec can't decode byte 0xb9 in position 423: invalid start byte # 突破反扒,返回响应 # print(resp) # 方法-下载图片 def download_images(a_url,a_filename): ''' 详情页面的图片请求,并保存在本地''' resp_dtl = requests.get(a_url, headers=headers).content.decode('gbk') doc = pq(resp_dtl) bigImgs = doc('.big_img p img').items() count=1 # print(bigImgs) for bigImg in bigImgs: bigImgSrc=bigImg.attr("src") imgs_data=requests.get(bigImgSrc,headers=headers) file_name="图片/"+a_filename save_name=str(file_name) # 若图片目录文件不存在,则重建 if not os.path.exists(save_name): os.makedirs(file_name) else: with open(save_name+'/{}.jpg'.format(count),'wb') as f: f.write(imgs_data.content) count+=1 # 方法-取得图片并下载数据 def getPics(a_url): resp_data = requests.get(a_url, headers=headers).content.decode('gbk') doc = pq(resp_data) # 通过类选择器获取数据 picObj =doc(".pic").items() # print(pic) for pic in picObj: # 通过属性获取内容 picUrl=pic.attr("href") picName = pic.text() # print(picUrl) download_images(picUrl,picName) # 主入口方法,调用抓取图片 getPics(url)
实现效果,抓取图片文件如下
-
GridView加载网络图片
2015-06-15 15:23:03GridView加载本地图片可以直接用Drawable获取图片资源,但是如果想要加载网络图片的话,就得用异步任务,获取图片资源,然后再加载到GridView中。 首先先写一个类,声明Item里面的内容控件,这 -
Glide使用 加载网络图片 圆形图片 圆角图片
2017-03-06 15:27:42在项目中总结的Glide用法(工具类)。public class Glides { public static Glides instance = new Glides(); public Glides() { } public static Glides getInstance() { return instance;... } // 加载网络图片 -
ImageView加载网络图片
2019-04-19 22:13:45使用第三方的库Glide加载网络图片 首先去下载一个glide的包 下载地址:https://github.com/bumptech/glide/releases/download/v4.7.0/glide-full-4.7.0.jar 我这里用的是glide-full-4.7.0 下载好之后直接复制到... -
PHPExcel导出网络图片
2019-01-10 15:10:35PHPExcel导出网络图片 在使用PHPExcel中发现,本地的图片特别方便导出,但是网上的不好导出。我们的图片存储在oss上,所以导出数据时,在这费了不少时间 新的改变 我们对Markdown编辑器进行了一些功能拓展与语法支持... -
Weex Android加载本地图片及网络图片
2016-09-30 16:57:32Weex Android加载本地图片及网络图片前言本篇本地图片加载目前仅适用于ImageLoader,如若是其他图片框架,则需要自己写适配规则。当然如果要适配Fresco,则需去研究一下WXImage的源代码,相信大家都有收获的。一、... -
Qt 之显示网络图片
2016-03-01 16:07:03简述Qt中包含了网络模块-network,我们可以很容易的进行各种网络编程和数据传输,关于...下面我们先看一个简单地示例:Qt显示一个网络图片。简述 效果 源码 处理方式效果源码创建按钮及显示图像的标签,连接信号槽。 -
QT加载网络图片
2016-01-30 14:15:211.网络图片这里指的是,服务器上面保存的图片,给你一个链接,你可以在浏览器里面打开的图片。 2.网络图片的显示跟网络音频,视频不太一样,要比它们麻烦。 因为QT 的QMediaPlayer 类中,有设置URL地址的接口... -
Java携带HTTP头信息下载网络图片
2019-03-12 10:48:27网络图片下载校验一般分两种情况: 1、校验Reffer头信息,即只有指定的网站的才能访问图片 2、校验Cookie头信息,即只有登录状态才能访问图片 如下图直接通过url访问返回:{"code":"40310014","msg":"invalid ... -
网络图片转成base64操作,解决图片跨域问题
2019-10-16 16:28:56网络图片转成base64操作,解决canvas不支持绘制网络图片问题 // 直接调用 var url = '网络图片地址' getBase64(url).then(base64 =>{ console.log(base64) }); // oss图片转成base64操作,解决canvas不支持绘制... -
基于Volley网络库实现加载多种网络图片(包括GIF动态图片、圆形图片、普通图片)...
2016-05-17 13:10:08基于Volley网络库实现加载多种网络图片(包括GIF动态图片、圆形图片、普通图片) 本案例是基于Volley网络库实现的加载多种网络图片,目前包括GIF动态图片、圆形图片、普通图片,还有待完善,欢迎提意见,或者一起... -
Cocos Creator加载网络图片
2019-07-12 17:57:36//设置显示图片 function setImg(imgNode, spriteFrame) { imgNode.getComponent(cc.Sprite).spriteFrame = sprite...//加载网络图片 function loadImgByUrl(imgNode, remoteUrl, imageType) { if (!imageType) { ... -
ImageLoder如何加载本地图片 sd卡图片 网络图片 assets文件夹下的图片 contentprovider图片
2016-06-07 18:12:32只需要将url设置成以下格式即可 ... // 网络图片 String imageUri = "file:///mnt/sdcard/image.png"; // sd卡图片 String imageUri = "content://media/external/audio/albumart -
Unity 加载网络图片
2016-03-17 17:22:41IOS工程师都应该用过...原理就是先用一张placeholder来显示图片,等待图片加载,等加载完了之后替换placeholder,第二次加载网络图片时,先判断本地时候已经加载过图片,如果加载过就从本地获取图片,如果没有就去 -
Android 如何根据网络地址获取网络图片方法
2015-11-08 21:10:29Android 如何根据网络地址获取网络图片方法 -
微信小程序 本地资源图片无法通过 WXSS 获取,可以使用网络图片,或者 base64,或者使用image标签。
2018-06-27 16:26:39pages/index/index.wxss 中的本地资源图片无法通过 WXSS 获取,可以使用网络图片,或者 base64,或者使用&lt;image/&gt;标签。 报错位置 background-image: .user-container { display: flex; ... -
Android中ImageView显示网络图片
2018-07-25 14:38:10* 加载网络图片,获取网络图片的bitmap * @param url:网络图片的地址 * @return */ //加载图片 public static Bitmap getURLimage(String url) { Bitmap bmp = null; try { URL myurl = new URL(url); // ... -
node.js抓取网络图片保存到本地,node.js抓取防盗链网络图片保存到本地
2018-01-25 10:17:03node.js抓取网络图片保存到本地,node.js抓取防盗链网络图片保存到本地 -
canvas绘制多张网络图片
2018-08-31 11:48:321、最近在做小程序的分享图的时候,后台返回的背景图和小程序码网络图片。canvas不能绘制网络的图片和base64形式的图片。 2、现在的做法是先把图片下载到本地。就是 wx.downloadFile( )。 3、先绘制多张网络的图片... -
Flutter中网络图片加载和缓存
2019-03-30 16:45:24前言 ...Flutter本身提供的Image Widget已经实现了加载网络图片的功能,且具备内存缓存的机制,接下来一起看一下Image的网络图片加载的实现。 重温小部件Image 常用小部件Image中实现了几种构造函数... -
AndroidStudio——加载网络图片
2016-08-14 20:55:35加载网络图片 -
PHP 获取网络图片资源并保存
2018-09-29 10:56:22在进行后台图片资源整合时,我发现有需要获取网络图片的需要,简单的要求就是,先获取某个资源图片,然后由代 PHP 代码实现剪切水印等操作,最后进行上传服务器… ☺.框架 : ThinkPHP3.2.3 (越来越不想玩这个低... -
Android加载大量网络图片
2015-09-21 02:05:49我获取大量网络图片显示在我的列表里边,就类似淘宝那种,我的方法是一下子把图片全取过来了,而且没有缓存,这样经常有内存溢出的错误,而且用户体验不好!我想请教一下,类似淘宝那样,屏幕划到哪儿,就消失图片到... -
小程序中canvas绘制网络图片
2018-03-20 13:29:02小程序中,canvas绘制图片,可使用drawImage方法,但是绘制网络图片时,在手机端不会显示,需要先将网络图片下载到本地,然后用图片的本地路径绘制。如下伪代码:function downLoadImg(netUrl, storageKeyUrl) { wx... -
向excel里面插入网络图片
2018-08-06 21:03:34今天研究的是向excel里面插入网络图片。不是将网络图片保存到本地,再完成插入操作。这里直接是通过网络图片的数据流转化为可以操作的image对象,直接插入到Excel表的A1单元格里面,并且调整单元格A1的行高和列宽以...
-
uploadifive上传图片源码附教程文档.zip
-
excel_test.zip
-
NFS 网络文件系统
-
2021-02-27
-
LeetCode | 0655. 输出二叉树【Python】
-
PrefixHashTree.pdf
-
小粥重学mysql(6)之多表查询----练习
-
朱老师c++课程第3部分-3.5STL的其他容器讲解
-
尴尬!因软件 Bug ,美国数百名囚犯释放后无法出狱
-
【开发工具】eclipse更改字体样式及大小
-
error:please select a valid Python interpreter
-
正则表达式^
-
电视直播新选择 黑鸟播放器 BlackBird Player 1.8.12 单文件便携化版_by dfhwqc.exe
-
程序员必修基础套餐课
-
高级人工智能期末复习整理.pdf
-
spider数据挖掘-----11、分布式爬虫(一)
-
MySQL 性能优化(思路拓展及实操)
-
模块2Python语言基础.pptx
-
Android第十章
-
vb读文件属性.rar