新建项目GetPicture。并写好前台界面,就简单的输入图片地址,在下面显示的就可以了,布局如下:
MainActivity中代码:
package com.example.dy.getpictrue;
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.text.TextUtils;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
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 MainActivity extends AppCompatActivity implements View.OnClickListener {
private static final int ERROR = 2;
private static final int SUCCESS =1;
private static final int EXCEPTION = 3;
private EditText editText;
private Button btn;
private ImageView imageView;
private Handler handler=new Handler(){
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case SUCCESS:
Bitmap bitmap= (Bitmap) msg.obj;
imageView.setImageBitmap(bitmap);
break;
case ERROR:
Toast.makeText(MainActivity.this, "图片获取失败", Toast.LENGTH_SHORT).show();
break;
case EXCEPTION:
Toast.makeText(MainActivity.this, "网路连接异常", Toast.LENGTH_SHORT).show();
break;
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
editText= (EditText) findViewById(R.id.et_pic_url);
btn= (Button) findViewById(R.id.btn_pic_click);
imageView= (ImageView) findViewById(R.id.img_pic);
btn.setOnClickListener(this);
}
@Override
public void onClick(View v) {
final String str=editText.getText().toString().trim();
if(TextUtils.isEmpty(str)){
Toast.makeText(MainActivity.this, "输入的图片网址不能为空", Toast.LENGTH_SHORT).show();
return;
}
new Thread(){
@Override
public void run() {
try {
URL url=new URL(str);
HttpURLConnection conn= (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setReadTimeout(5000);
if (conn.getResponseCode()==200){
InputStream inputStream = conn.getInputStream();
Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
Message msg=Message.obtain();
msg.what=SUCCESS;
msg.obj=bitmap;
handler.sendMessage(msg);
}else{
Message msg=Message.obtain();
msg.what=ERROR;
handler.sendMessage(msg);
}
}catch (IOException e) {
Message msg=Message.obtain();
msg.what=EXCEPTION;
handler.sendMessage(msg);
}
}
}.start();
}
}
具体源代码可以在https://github.com/loopj/android-smart-image-view获取,只需要通过一句话就可以搞定:
smartImageView.setImageUrl(str);
SmartImageView是图片异步下载的开源项目,可以下载指定路径的图片,加入了缓存机制,可以自动清除缓存,清除的缓存按缓存文件创建时间最久未使用的原则进行清除。
下面会重点分析它的缓存机制,在这之前先看下它的网络下载的方法:
private Bitmap getBitmapFromUrl(String url) {
Bitmap bitmap = null;
try {
URLConnection conn = new URL(url).openConnection();
conn.setConnectTimeout(CONNECT_TIMEOUT);
conn.setReadTimeout(READ_TIMEOUT);
bitmap = BitmapFactory.decodeStream((InputStream) conn.getContent());
} catch(Exception e) {
e.printStackTrace();
}
return bitmap;
}
可以看出和我们自己用原生的写法差不多,共同的确定是没有考虑到内存溢出的情况,关于避免图片内存溢出的办法可以参考我的另外一篇博客: http://blog.csdn.net/qq_33748378/article/details/51182397。
当图片下载完成之后也是通过Handler将下载到的图片传递到主线程去更新界面的:
public static class OnCompleteHandler extends Handler {
@Override
public void handleMessage(Message msg) {
Bitmap bitmap = (Bitmap)msg.obj;
onComplete(bitmap);
}
public void onComplete(Bitmap bitmap){};
}
缓存机制分析:
public Bitmap getBitmap(Context var1) {
if(webImageCache == null) {
webImageCache = new WebImageCache(var1);
}
Bitmap var2 = null;
if(this.url != null) {
var2 = webImageCache.get(this.url);
if(var2 == null) {
var2 = this.getBitmapFromUrl(this.url);
if(var2 != null) {
webImageCache.put(this.url, var2);
}
}
}
return var2;
}
通过以上大致可以看出,当输入的url地址不为空的时候首先访问webImageCatch(),如果webImageCatch中不包含所要访问的资源那么久访问网络下载资源,如果在网络下载到该图片资源则将该资源存入到webImageCatch,并返回下载的bitmap对象。那么下次再访问该资源的时候就可以直接在webImageView中获取该图片资源而不必再去访问网络。
public Bitmap get(String var1) {
Bitmap var2 = null;
var2 = this.getBitmapFromMemory(var1);
if(var2 == null) {
var2 = this.getBitmapFromDisk(var1);
if(var2 != null) {
this.cacheBitmapToMemory(var1, var2);
}
}
return var2;
}
public void put(String var1, Bitmap var2) {
this.cacheBitmapToMemory(var1, var2);
this.cacheBitmapToDisk(var1, var2);
}
从上面的源码可以看出, webImageCache.get()方法和webImageCache.put()方法是先到内存中取再到磁盘中取(或者先存到内存中,再存到磁盘中),即为二级缓存。
private void cacheBitmapToMemory(String var1, Bitmap var2) {
this.memoryCache.put(this.getCacheKey(var1), new SoftReference(var2));
}
private void cacheBitmapToDisk(final String var1, final Bitmap var2) {
this.writeThread.execute(new Runnable() {
public void run() {
if(WebImageCache.this.diskCacheEnabled) {
BufferedOutputStream var1x = null;
try {
var1x = new BufferedOutputStream(new FileOutputStream(new File(WebImageCache.this.diskCachePath, WebImageCache.this.getCacheKey(var1))), 2048);
var2.compress(CompressFormat.PNG, 100, var1x);
} catch (FileNotFoundException var11) {
var11.printStackTrace();
} finally {
try {
if(var1x != null) {
var1x.flush();
var1x.close();
}
} catch (IOException var10) {
;
}
}
}
}
});
}
上面的源码是将图片缓存到内存中和磁盘中。
private Bitmap getBitmapFromMemory(String var1) {
Bitmap var2 = null;
SoftReference var3 = (SoftReference)this.memoryCache.get(this.getCacheKey(var1));
if(var3 != null) {
var2 = (Bitmap)var3.get();
}
return var2;
}
private Bitmap getBitmapFromDisk(String var1) {
Bitmap var2 = null;
if(this.diskCacheEnabled) {
String var3 = this.getFilePath(var1);
File var4 = new File(var3);
if(var4.exists()) {
var2 = BitmapFactory.decodeFile(var3);
}
}
return var2;
}
上面的源码是获取内存和磁盘中的图片。
参考资料:
Android SmartImageView源码分析:http://blog.csdn.net/xuehuayous/article/details/42101385?locationNum=4