Hi,众猿们!昨天谈了下json的三级缓存和图片的内存缓存的代码实现,今天就聊聊如何从网络获取图片以及图片的本地缓存吧!主要有以下几个问题:
1.Android中网络访问的基本知识。
2.利用URLConnection对象访问网络图片。
3.图片的本地缓存。
废话不多说,先看第一个问题,安卓应用中访问网络资源,可以使用URLConnection及其子类HttpURLConnection对象,也可以用于Android系统提供的HttpClient、HttpGet、HttpPost对象。我们需要对Http协议有一定的了解,要知道Get请求方式和Post请求方式的基本知识。同时,像请求网络资源这种费时的操作,我们应该让其远离UI主线程(如果众猿对线程不熟悉的话,那你的Java基础需要加强呀),以避免出现用户操作卡顿的现象,因此我们会用异步任务对象AsyncTask来完成网络请求操作,最后,我们还要熟悉Java中的回调机制,因为我们还要考虑请求资源超时、失败等情况。下面是一个完成网络通信功能的基类,在实际开发中我们可以继承该类以完成特定的网络请求:
public class BaseNetConnection {
public static final int METHOD_GET = 1;
public static final int METHOD_POST = 2;
public static final String CHARSET = "utf-8";
public static final int ERROR_NET_UNAVAILABLE = 1;
public static final int ERROR_NORESULT = 2;
/**
* 用于执行请求网络资源的方法,需在清单中添加网络权限
* @param url 网络资源的接口url
* @param method 请求方式
* @param successCallback 请求成功的回调接口
* @param failCallback 请求失败的回调接口
* @param kvs 请求参数
*/
public void execute(
final String url,
final int method,
final SuccessCallback successCallback,
final FailCallback failCallback,
final String ... kvs) {
//判断网络是否已经连接,否则则调用失败接口,并返回函数
if(!isNetAvailable()){
if (failCallback != null) {
failCallback.onFail(ERROR_NET_UNAVAILABLE);
}
return;
}
//使用异步任务对象请求网络资源
new AsyncTask<Void, Void, String>() {
/**
* 执行异步任务的方式,运行在子线程中
* @param params
* @return
*/
@Override
protected String doInBackground(Void... params) {
StringBuffer paramsStr = new StringBuffer();
for (int i = 0; i < kvs.length; i+=2) {
paramsStr.append(kvs[i]).append("=").append(kvs[i+1]).append("&");
}
try {
URLConnection uc;
switch (method) {
case METHOD_POST:
uc = new URL(url).openConnection();
uc.setDoOutput(true);
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(uc.getOutputStream(), CHARSET));
bw.write(paramsStr.toString());
bw.flush();
break;
default:
uc = new URL(url+"?"+paramsStr.toString()).openConnection();
break;
}
BufferedReader br = new BufferedReader(new InputStreamReader(uc.getInputStream(), CHARSET));
String line = null;
StringBuffer result = new StringBuffer();
while((line=br.readLine())!=null){
result.append(line);
}
return result.toString();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
/**
* 任务执行完毕后处理执行结果的方法,运行在主线程中
* @param result
*/
@Override
protected void onPostExecute(String result) {
if (result!=null) {
if (successCallback!=null) {
successCallback.onSuccess(result);
}
}else{
if (failCallback!=null) {
failCallback.onFail(ERROR_NORESULT);
}
}
super.onPostExecute(result);
}
}.execute();
}
/**
* 判断网络是否连接的方法,需在清单文件中添加相关权限
* @return 若网络已连接则返回true
*/
private boolean isNetAvailable() {
ConnectivityManager manager = (ConnectivityManager) MyApplication.getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo info = manager.getActiveNetworkInfo();
if (info != null) {
return info.isAvailable();
}
return false;
}
/**
* 请求资源成功的回调接口
* @author 李明忠
*
*/
public static interface SuccessCallback{
void onSuccess(String result);
}
/**
* 请求资源失败的回调接口
* @author 李明忠
*
*/
public static interface FailCallback{
void onFail(int errorCode);
}
}
public class BitmapCacheUtil {
public static final int ERROR_NET_UNAVAILABLE = 1;
public static final int ERROR_NORESULT = 2;
public static final String LOCAL_PATH = Environment.getExternalStorageDirectory().getAbsolutePath() + "BitmapCache";
private static LruCache<String, Bitmap> mBitmapMemoryCache = new LruCache<String, Bitmap>((int) (Runtime.getRuntime().maxMemory() / 8)){
@Override
protected int sizeOf(String key, Bitmap value) {
return value.getHeight() * value.getRowBytes();
}
};
/**
* 加载url对应的图片并将其显示到ImageView控件上,若图片加载成功则将其显示到ImageView上
* 接口处理失败情况
* @param imageView 用来显示图片的控件
* @param url 图片的网络url
* @param failCallback 加载图片失败的回调接口
*/
public static void loadBitmap(
ImageView imageView,
String url,
FailCallback failCallback){
//先从内存缓存中加载图片
Bitmap bitmap = loadBitmapFromMemory(url);
if (bitmap == null) {
//若内存中不存在该图片则从本地缓存中加载
bitmap = loadBitmapFromLocal(url);
if(bitmap == null){
//若本地缓存中无图片则先判断网络是否连接
if(isNetAvailable()){
//有网络则从网络缓存中加载图片
loadBitmapFromNet(imageView, url, failCallback);
}else {
//无网络则执行请求失败回调接口
if(failCallback != null){
failCallback.onFail(ERROR_NET_UNAVAILABLE);
}
}
}else {
//若本地缓存中有该图片则使用该图片
imageView.setImageBitmap(bitmap);
}
}else {
imageView.setImageBitmap(bitmap);
}
}
/**
* 判断网络是否建立的方法
* @return 若网络已连接则返回true
*/
private static boolean isNetAvailable() {
ConnectivityManager manager = (ConnectivityManager) MyApplication.getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo info = manager.getActiveNetworkInfo();
if (info != null) {
return info.isAvailable();
}
return false;
}
/**
* 将图片放置进内存缓存
* @param url
* @param bitmap
*/
private static void putBitmapToMemory(String url, Bitmap bitmap) {
mBitmapMemoryCache.put(url, bitmap);
}
/**
* 将图片放置进本地缓存
* @param url
* @param bitmap
*/
private static void putBitmapToLocal(String url, Bitmap bitmap) {
try{
File file = new File(LOCAL_PATH, url);
File parent = file.getParentFile();
if (!parent.exists()) {
parent.mkdirs();
}
FileOutputStream stream = new FileOutputStream(file);
bitmap.compress(CompressFormat.JPEG, 100, stream);
} catch (Exception e) {}
}
/**
* 从网络上加载url对应的图片并显示在ImageView上
* @param imageView 用于显示图片的控件
* @param url
* @param failCallback 请求失败时的回调接口
*/
private static void loadBitmapFromNet(
final ImageView imageView,
final String url,
final FailCallback failCallback) {
new AsyncTask<Void, Void, Bitmap>(){
@Override
protected Bitmap doInBackground(Void... params) {
HttpURLConnection con = null;
try {
con = (HttpURLConnection) new URL(url).openConnection();
con.setConnectTimeout(5000);// 连接超时
con.setReadTimeout(5000);
con.setRequestMethod("GET");
con.connect();
int responseCode = con.getResponseCode();
if (responseCode == 200) {
InputStream inputStream = con.getInputStream();
Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
// 将图片保存在本地缓存
putBitmapToLocal(url, bitmap);
// 将图片保存在内存
putBitmapToMemory(url, bitmap);
return bitmap;
}
} catch (Exception e) {} finally {
if (con != null) {
con.disconnect();
}
}
return null;
}
@Override
protected void onPostExecute(Bitmap result) {
if (result == null) {
failCallback.onFail(ERROR_NORESULT);
}else {
imageView.setImageBitmap(result);
}
};
}.execute();
}
/**
* 从本地缓存中加载图片
* @param url
* @return
*/
private static Bitmap loadBitmapFromLocal(String url) {
File file = new File(LOCAL_PATH, url);
if (file.exists()) {
Bitmap bitmap = null;
try {
bitmap = BitmapFactory.decodeStream(new FileInputStream(file));
putBitmapToMemory(url, bitmap);
} catch (FileNotFoundException e) {}
return bitmap;
}
return null;
}
/**
* 从内存中加载url对应的图片
* @param url 该图片对应的url
* @return 若内存中不存在该图片则直接返回null
*/
private static Bitmap loadBitmapFromMemory(String url) {
return mBitmapMemoryCache.get(url);
}
public interface FailCallback{public void onFail(int errorCode);}
}