请求网络图片缓存到本地 ,还有一些现成的图片加载框架的使用 Ace网络篇(一)
现在去买年货~~~~~~ 占坑,
现在来填坑 填完睡觉,感谢这俩月的把自己往死里逼得奋斗从JAVA什么都不懂到现在,做这些也是给在自学路上的新人(我也是菜鸟)一点点我力所能及的帮助,等我水平更高了还会继续分享,分享,开源是种快乐.
这篇讲你怎样获取一张网络图片,很基础,但我还是那句话 万变不理其中,很多集成好的框架也是这个原理,框架虽易但希望你能懂得其中原理,代码再复杂,也是这种"一招一式"
现在来看请求一张照片分几步走:
获取网络图片
这里我并没有说异步线程,我直接在主线程执行这些
1 确定图片的网址
2 发送http请求
URL url = new URL(address);
//获取连接对象,并没有建立连接
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
//设置连接和读取超时
conn.setConnectTimeout(5000);
conn.setReadTimeout(5000);
//设置请求方法,注意必须大写
conn.setRequestMethod("GET");
//建立连接,发送get请求
//conn.connect();
//建立连接,然后获取响应吗,200说明请求成功
conn.getResponseCode();
* 服务器的图片是以流的形式返回给浏览器的 //拿到服务器返回的输入流
InputStream is = conn.getInputStream();
//把流里的数据读取出来,并构造成图片
Bitmap bm = BitmapFactory.decodeStream(is);
* 把图片设置为ImageView的显示内容 ImageView iv = (ImageView) findViewById(R.id.iv);
iv.setImageBitmap(bm);
3 别忘了添加权限
代码:布局就一个imageview和button 不写了 记得添加网络请求权限
public class MainActivity extends Activity { @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
} public void click(View v){
String path = "http://pic.cnblogs.com/avatar/859887/20160120170921.png";
//我酷炫吊炸天可爱卖萌的羊驼
//发送http请求
try {
//1.使用网址构造一个URL对象
URL url = new URL(path);
//2.获取连接对象
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
//3.设置一些属性
//设置请求方式,注意大写
conn.setRequestMethod("GET");
//设置请求超时
conn.setConnectTimeout(8000);
//设置读取超时
conn.setReadTimeout(8000);
//4.发送请求,建立连接
conn.connect();
//5.判断请求是否成功
if(conn.getResponseCode() == 200){
//获取服务器返回的流,流里就是客户端请求的数据
InputStream is = conn.getInputStream(); //读取流里的数据,构造出一张图片
Bitmap bm = BitmapFactory.decodeStream(is); //把下载的图片显示至imageview
ImageView iv = (ImageView) findViewById(R.id.iv);
iv.setImageBitmap(bm);
}
else{
Toast.makeText(this, "请求失败了亲~~", 0).show();
}
} catch (Exception e) {
e.printStackTrace();
}
} }
其实我不开子线程是个坑下面给我自己写个坑:
来 让主线程sleep 10秒......系统会抛出Application Not Response
因为主线程不能被阻塞:
1 在Android中,主线程被阻塞会导致应用不能刷新ui界面,不能响应用户操作,用户体验将非常差
2 主线程阻塞时间过长,系统会抛出ANR异常
3 ANR:Application Not Response;应用无响应
4 任何耗时操作都不可以写在主线程
5 因为网络交互属于耗时操作,如果网速很慢,代码会阻塞,所以网络交互的代码不能运行在主线程
那么我们需要开启子线程,开启子线程的两种方法:请看我的这个教程会再讲三个知识点:消息队列,主线程(UI线程),缓存到本地文件
一 只有主线程能刷新ui:
1 刷新ui的代码只能运行在主线程,运行在子线程是没有任何效果的
2 如果需要在子线程中刷新ui,使用消息队列机制
3 主线程也叫ui线程
二 消息队列
1 主线程创建时,系统会同时创建消息队列对象(MessageQueue)和消息轮询器对象(Looper)
2 轮询器的作用,就是不停的检测消息队列中是否有消息(Message)
3 Looper一旦发现Message Queue中有消息,就会把消息取出,然后把消息扔给Handler对象,Handler会调用自己的handleMessage方法来处理这条消息
4 handleMessage方法运行在主线程
5 主线程创建时,消息队列和轮询器对象就会被创建,但是消息处理器对象,需要使用时,自行创建
主线程创建:
//消息队列
Handler handler = new Handler(){
//主线程中有一个消息轮询器looper,不断检测消息队列中是否有新消息,如果发现有新消息,自动调用此方法,注意此方法是在主线程中运行的
public void handleMessage(android.os.Message msg) { }
};
在子线程中使用Handler对象往消息队列里发消息
//创建消息对象
Message msg = new Message();
//消息的obj属性可以赋值任何对象,通过这个属性可以携带数据
msg.obj = bm;
//what属性相当于一个标签,用于区分出不同的消息,从而运行不能的代码
msg.what = 1;
//发送消息
handler.sendMessage(msg);
通过switch语句区分不同的消息
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
//如果是1,说明属于请求成功的消息
case 1:
ImageView iv = (ImageView) findViewById(R.id.iv);
Bitmap bm = (Bitmap) msg.obj;
iv.setImageBitmap(bm);
break;
case 2:
Toast.makeText(MainActivity.this, "请求失败", 0).show();
break;
}
}
缓存图片到本地的功能:
把服务器返回的流里的数据读取出来,然后通过文件输入流写至本地文件
//1.拿到服务器返回的输入流
InputStream is = conn.getInputStream();
//2.把流里的数据读取出来,并构造成图片 FileOutputStream fos = new FileOutputStream(file);
byte[] b = new byte[1024];
int len = 0;
while((len = is.read(b)) != -1){
fos.write(b, 0, len);
}
创建bitmap对象的代码改成
Bitmap bm = BitmapFactory.decodeFile(file.getAbsolutePath());
每次发送请求前检测一下在缓存中是否存在同名图片,如果存在,则读取缓存
看代码吧
public class MainActivity extends Activity { Handler handler = new Handler(){
//只要消息队列有消息,此方法就会在主线程执行
public void handleMessage(android.os.Message msg) {
//在这里刷新ui
switch (msg.what) {
case 1:
ImageView iv = (ImageView) findViewById(R.id.iv);
iv.setImageBitmap((Bitmap)msg.obj);
break;
case 2:
Toast.makeText(MainActivity.this, "请求失败o(╯□╰)o", 0).show();
break;
} }
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
} public void click(View v){
final String path = "http://pic.cnblogs.com/avatar/859887/20160120170921.png";
final File file = new File(getCacheDir(), getNameFromPath(path));
if(file.exists()){
System.out.println("从缓存获取");
Bitmap bm = BitmapFactory.decodeFile(file.getAbsolutePath()); Message msg = new Message();
msg.obj = bm;
msg.what = 1;
handler.sendMessage(msg);
// ImageView iv = (ImageView) findViewById(R.id.iv);
// iv.setImageBitmap((Bitmap)msg.obj);
}
else{
Thread t = new Thread(){
@Override
public void run() {
System.out.println("从网络获取");
//发送http请求
try {
//1.使用网址构造一个URL对象
URL url = new URL(path);
//2.获取连接对象
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
//3.设置一些属性
//设置请求方式,注意大写
conn.setRequestMethod("GET");
//设置请求超时
conn.setConnectTimeout(8000);
//设置读取超时
conn.setReadTimeout(8000);
//4.发送请求,建立连接
// conn.connect();
//5.判断请求是否成功
if(conn.getResponseCode() == 200){
//获取服务器返回的流,流里就是客户端请求的数据
InputStream is = conn.getInputStream(); //我们自己读取流里的数据,读取1k,就把1k写到本地文件缓存起来
byte[] b = new byte[1024];
int len; FileOutputStream fos = new FileOutputStream(file);
while((len = is.read(b)) != -1){
fos.write(b, 0, len);
}
fos.close(); // 因为缓存时已经把流里数据读取完了,此时流里没有任何数据
// Bitmap bm = BitmapFactory.decodeStream(is); Bitmap bm = BitmapFactory.decodeFile(file.getAbsolutePath()); //当子线程需要刷新ui时,只需发送一条消息至消息队列
Message msg = new Message();
//消息对象本身是可以携带数据的
msg.obj = bm;
//使用what标注消息是什么类型的
msg.what = 1; handler.sendMessage(msg); }
else{
//如果消息池有消息,取出消息池第一条消息,返回,如果没有,就new一个消息返回
// Message msg = handler.obtainMessage();
// msg.what = 2;
// handler.sendMessage(msg); handler.sendEmptyMessage(2);
}
} catch (Exception e) {
e.printStackTrace();
}
}
};
t.start();
} } public String getNameFromPath(String path){
int index = path.lastIndexOf("/");
return path.substring(index + 1);
} }
更多开启线程加载图片的教程可以看我的这个教程
阿冰教你一步一步做Android新闻客户端(二)两种异步线程加载图片的方法
眼皮子打架了 我要睡了 明天讲框架 框架就太简单了 教会你用框架只要一秒 但是不懂原理你永远不会进步.
爬起来补坑 下面你自己动手:
1 github.com
2 在github搜索smart-image-view
3 下载开源项目smart-image-view
4 使用自定义组件时,标签名字要写包名(再XML文件里替换刚才我们创建的ImageView)<com.loopj.android.image.SmartImageView/>
SmartImageView的使用
SmartImageView siv = (SmartImageView) findViewById(R.id.siv);
siv.setImageUrl("http://pic.cnblogs.com/avatar/859887/20160120170921.png");//还是我们可爱的羊驼
请求网络图片缓存到本地 ,还有一些现成的图片加载框架的使用 Ace网络篇(一)的更多相关文章
- android-------非常好的图片加载框架和缓存库(Picasso)
Picasso是Square公司开源的一个Android图形缓存库, 可以实现图片加载(本地和网络)和缓存功能. 地址:http://square.github.io/picasso/ jar包下载: ...
- Android图片加载框架最全解析(三),深入探究Glide的缓存机制
在本系列的上一篇文章中,我带着大家一起阅读了一遍Glide的源码,初步了解了这个强大的图片加载框架的基本执行流程. 不过,上一篇文章只能说是比较粗略地阅读了Glide整个执行流程方面的源码,搞明白了G ...
- android--------Universal-Image-Loader图片加载框架和结合LruCache缓存图片
本博客包含包含Android-Universal-Image-Loader 网络图片加载框架实现图片加载和结合universal-image-loader与LruCache来自定义缓存图片,可以设置缓 ...
- Android图片加载与缓存开源框架:Android Glide
<Android图片加载与缓存开源框架:Android Glide> Android Glide是一个开源的图片加载和缓存处理的第三方框架.和Android的Picasso库类似,个人感觉 ...
- Volley框架之网络请求和图片加载
Volley是 Google 推出的 Android 异步网络请求框架和图片加载框架. Volley的特性 (1).封装了的异步的请求API.Volley 中大多是基于接口的设计,可配置性强.(2). ...
- Android 图片加载库Glide 实战(二),占位符,缓存,转换自签名高级实战
http://blog.csdn.net/sk719887916/article/details/40073747 请尊重原创 : skay <Android 图片加载库Glide 实战(一), ...
- android--------volley之网络请求和图片加载
Volley是 Google 推出的 Android 异步网络请求框架和图片加载框架. Volley的特性 封装了的异步的请求API.Volley 中大多是基于接口的设计,可配置性强. 一个优雅和稳健 ...
- Android批量图片加载经典系列——使用xutil框架缓存、异步加载网络图片
一.问题描述 为提高图片加载的效率,需要对图片的采用缓存和异步加载策略,编码相对比较复杂,实际上有一些优秀的框架提供了解决方案,比如近期在git上比较活跃的xutil框架 Xutil框架提供了四大模块 ...
- Android批量图片加载经典系列——采用二级缓存、异步加载网络图片
一.问题描述 Android应用中经常涉及从网络中加载大量图片,为提升加载速度和效率,减少网络流量都会采用二级缓存和异步加载机制,所谓二级缓存就是通过先从内存中获取.再从文件中获取,最后才会访问网络. ...
随机推荐
- linux select 返回值
IBM AIX上 select返回值的 man if a connect-based socket is specified in the readlist parameter and the co ...
- C#向服务器上传文件问题
最近在写服务器端web上传的接口.但一直报错,上传不上去,后来发现是在分隔符中出现的问题. 错误的写法: var boundary = "---------------" + Da ...
- vs调试的时候debug和release的区别
今天在VS项目中调式遇到一个问题,断点快速查询变量的发现变两竟然不存在 花了一个小时到处百度也查不出一个所以然,后来请教了大神才知道VS调试有debug和release两个模式, vs中的程序有deb ...
- Jquery 页面元素事件绑定
场景: 用一个Table来展示数据信息列表,通过鼠标点击Table中的Tr来获取到当前选中的数据行信息. <table class="Table" width="1 ...
- Nginx conf基本配置
#定义Nginx运行的用户和用户组 user www www; #nginx进程数,建议设置为等于CPU总核心数. worker_processes 8; #全局错误日志定义类型,[ debu ...
- OC字符串与C语言字符串之间的相互转换
1.C转OC字符串 const char *cString = "This is a C string"; // 动态方法 NSString *ocString1 = [[NSSt ...
- 预定义宏,C语言预定义的宏详解
1.预定义宏 对于预定义宏,相信大家并不陌生.为了方便处理一些有用的信息,预处理器定义了一些预处理标识符,也就是预定义宏.预定义宏的名称都是以"__"(两条下划线)开头和结尾的,如 ...
- 「BZOJ 1924」「SDOI 2010」所驼门王的宝藏「Tarjan」
题意 一个\(r\times c\)的棋盘,棋盘上有\(n\)个标记点,每个点有三种类型,类型\(1\)可以传送到本行任意标记点,类型\(2\)可以传送到本列任意标记点,类型\(3\)可以传送到周围八 ...
- kali linux之手动漏洞挖掘一
默认安装漏洞 phpmyadmin/setup默认安装 ubuntu/debian默认安装php5-cgi phpmyadmin/setup默认安装 使用?-d+allow_url_include%3 ...
- 【python】collections模块(有序字典,计数器,双向队列)
collections模块基本介绍 我们都知道,Python拥有一些内置的数据类型,比如str, int, list, tuple, dict等, collections模块在这些内置数据类型的基础上 ...