一、线程阻塞的概念
在android中,主线程被阻塞会导致应用无法进行刷新UI界面,应用无法响应,给用户带来不好的体验。如果,主线程阻塞的时间过长,系统会抛出ANR异常(Application Not Response).
任何耗时操作都不可以写在主线程中,下载图片属于网络交互,网络交互是一种耗时的操作,所以应该开辟一个新的子线程进行操作。
在子线程进行的操作不能刷新UI界面,UI界面运行在主线程中,要想在主线程中进行UI界面的刷新,要使用消息队列的机制。
二、消息队列的概念
当主线程创建来时,同时会创建一个Looper(轮询器)和一个Message Queue(消息队列),当消息队列中有消息时,轮询器就会把消息发送个消息处理器(handler)进行处理,因为handler运行在主线程中,所以可以直接刷新UI界面。要先在子线程中的下载的图片再对主线程进行UI刷新,只要在子线程中创建一个消息,发送到消息队列,再在handler中对主线程进行刷新。
三、缓存的机制
对于市面上软件的图片请求都带有缓存机制,将网络下面的图片下载到手机指定的缓存目录下,当下一次进行相同请求的时候直接可以从本地加载不用再去网络请求,这样大大地节省了应用效率。
四、具体代码
/**
*网络图片请求下载
*/
(一) 普通版
Handler handler = new Handler(){ //此方法在主线程中调用,可以用来刷新ui public void handleMessage(Message msg) { switch (msg.what) { case 1: //把位图对象显示至imageview(更新UI) //iv.setImageBitmap((Bitmap)msg.obj); break; case 0: //Toast.makeText(ma, "请求失败",Toast.LENGTH_SHORT).show(); break; } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } public void click(View v) { Thread thread = new Thread() { @Override public void run() { try{ String path = "";//网络图片请求地址 URL url = new URL(path);//把请求的网址封装成一个URL对象 HttpURLConnection connection = (HttpURLConnection) url.openConnection();//获取服务端与客 //户端的连接对象,此时还没有连接 connection.setRequestMethod("GET");//设置请求的方式 connection.setReadTimeout(5000);//设置读取超时 connection.setConnectTimeout(5000);//设置连接超时 connection.connect();//发送请求,与服务端进行连接 if(connection.getResponseCode()==200){//如果得到请求码为200,表示请求成功 InputStream inputStream = connection.getInputStream();//获取服务器响应头中的流,流里的数据就是客户端请求的数据 Bitmap bitmap = BitmapFactory.decodeStream(inputStream);//读出流里的数据,并把流里的数据构建成位图对象 /** * 创建一个消息机制,将消息发送给handler进行处理即进行UI刷新 */ Message msg = new Message(); //消息对象可以携带数据 msg.obj = bitmap; msg.what = 1;//标识下载成功 //把消息发送至主线程的消息队列 handler.sendMessage(msg); }else{ Message msg = handler.obtainMessage(); msg.what = 0;//表示下载失败 handler.sendMessage(msg); } }catch (Exception e){ } } }; thread.start(); } }
(二) 本地缓存机制
static MainActivity ma; //通常设置静态方法,这样其他类就可以使用同一个,别忘了设置静态后里面相应的参数也要是静态的 static Handler handler = new Handler(){ //此方法在主线程中调用,可以用来刷新ui public void handleMessage(Message msg) { switch (msg.what) { case 1: //把位图对象显示至imageview(更新UI) //iv.setImageBitmap((Bitmap)msg.obj); break; case 0: Toast.makeText(ma, "请求失败", Toast.LENGTH_SHORT).show(); break; } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ma = this; } public void click(View v) { final String path = "";//网络图片请求地址 final File file = new File(getCacheDir(), getAppName(path)); if (file.exists()) { //直接在本地更新UI }else { Thread thread = new Thread() { @Override public void run() { try { URL url = new URL(path);//把请求的网址封装成一个URL对象 HttpURLConnection connection = (HttpURLConnection) url.openConnection();//获取服务端与客 //户端的连接对象,此时还没有连接 connection.setRequestMethod("GET");//设置请求的方式 connection.setReadTimeout(5000);//设置读取超时 connection.setConnectTimeout(5000);//设置连接超时 connection.connect();//发送请求,与服务端进行连接 if (connection.getResponseCode() == 200) {//如果得到请求码为200,表示请求成功 InputStream inputStream = connection.getInputStream();//获取服务器响应头中的流,流里的数据就是客户端请求的数据 FileOutputStream outputStream = new FileOutputStream(file); Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath()); /** * 创建一个消息机制,将消息发送给handler进行处理即进行UI刷新 */ Message msg = new Message(); //消息对象可以携带数据 msg.obj = bitmap; msg.what = 1;//标识下载成功 //把消息发送至主线程的消息队列 handler.sendMessage(msg); } else { Message msg = handler.obtainMessage(); msg.what = 0;//表示下载失败 handler.sendMessage(msg); } } catch (Exception e) { } } }; thread.start(); } } private String getAppName(String path) { int i= path.lastIndexOf("/");//获取最后一个/的索引值 return path.substring(i+1);//从该索引值截取 包括 } }
谢谢大家的支持,希望您的关注,源码已经上传,编译环境为android studio,欢迎您的下载 下载地址:http://download.csdn.net/detail/qq_21813987/9442499