看着大神的技术各种高大上,自己怎么能落后呢?
好好加油吧,骚年。对昨天的从服务端下载图片进行复习。
主线程阻塞:
1,UI停止刷新,应用无法响应用户的操作。
2,耗时操作不应该放在主线程中。
3,ANR
application not responding
应用无响应异常
主线程阻塞时间过长,就会抛出ANR
4,主线程又称为是UI线程,因为只有在主线程,才能刷新UI
消息队列机制
这里接触到了消息队列机制:
主线程创建的时候,系统会同时创建消息队列对象(MessageQueue)和消息轮询器对象(Looper)。
消息轮询器的作用是:不停的检测消息队列中是否有消息(Message),
消息队列一旦有消息,轮询器就会把消息对象传给消息处理器(Handler),
消息处理器就会调用handlerMessage方法来处理这条消息,handlerMessage方法运行在主线程,所以可以刷新UI
总结:只要有消息队列有消息,handlerMessage方法就会调用,
子线程如果需要刷新UI,只要往队列中发送一条消息,触发handlerMessage方法即可,,子线程使用处理器对象的sendMessage方法发送消息。
实验的代码:
package com.example.xm.imageview;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
import android.widget.Toast;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
public class MainActivity extends AppCompatActivity {
ImageView iv;
Handler handler = new Handler(){
//此方法在主线程中调用,可以用来刷新UI
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case 1:
//把位图对象显示在imageview
iv.setImageBitmap((Bitmap) msg.obj);
break;
case 0:
Toast.makeText(MainActivity.this,"请求失败",Toast.LENGTH_LONG).show();
break;
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
iv = (ImageView) findViewById(R.id.iv);
}
public void click(View view){
//下载图片
/*
1,确定网站,1,确定网站,,原来模拟器默认把127.0.0.1和localhost当做本身了,
在模拟器上可以用10.0.2.2代替127.0.0.1和localhost,另外如果是在局域网环境可以用
192.168.0.x或者192.168.1.x(根据具体配置)连接本机,这样应该就不会报错了
*/
final String path = "http://10.0.2.2:8080/liu.png";
final File file = new File(getCacheDir(),getFileName(path));
//判断缓存中是否存在
if (file.exists()){
//如果缓存中存在,就从缓存中取
System.out.println("从缓存中取出");
Bitmap bm = BitmapFactory.decodeFile(file.getAbsolutePath());
iv.setImageBitmap(bm);
}else{
//如果缓存不存在,就从网上下载
System.out.println("从网上下载");
Thread t = new Thread(){
@Override
public void run() {
try {
//2,把网址封装成一个url对象
URL url = new URL(path);
//3,获取客户端和服务端的连接对象,此时ahi没有建立连接
HttpURLConnection connection =(HttpURLConnection) url.openConnection();
//4,对连接进行初始化
//设置请求方法,注意是大写
connection.setRequestMethod("GET");
//设置连接超时
connection.setConnectTimeout(5000);
//设置读取超时
connection.setReadTimeout(5000);
//5,发送请求,与服务器建立连接
connection.connect();
//如果响应码是200,说明请求成功
if (connection.getResponseCode() == 200){
//获取服务器响应头中的流,流中的数据就是客户端请求的数据
InputStream is = connection.getInputStream();
//读取服务器返回流中的数据,然后写入到本地的文件中,缓存起来
FileOutputStream fos = new FileOutputStream(file);
byte [] b = new byte[10024];
int len = 0;
while ((len = is.read(b)) != -1){
fos.write(b,0,len);
}
fos.close();
//读取出流中的数据,并构成位图
//Bitmap bm = BitmapFactory.decodeStream(is);
Bitmap bm = BitmapFactory.decodeFile(file.getAbsolutePath());
Message message = new Message();
//消息对象可以携带数据,这里把bm放在message.obj中
message.obj = bm;
//把消息发送至主线程的消息队列中
message.what =1;
handler.sendMessage(message);
}else {
Message message = handler.obtainMessage();
message.what = 0;
handler.sendMessage(message);
}
} catch (Exception e) {
e.printStackTrace();
}
}
};
t.start();
}
}