为了防止老年痴呆,基础的东西也要记一记。
其实图片加载用的框架很多。但是简单的加载个图片还是直接用系统的api处理一下比较节约了。
ImageView的setImageBitmap方法和异步加载就不说了。就来看一下bitmap的获取。
最基本的方法如下:
public static Bitmap returnBitMap(String url,int _w,int _h) {
URL myFileUrl = null;
Bitmap bitmap = null;
try {
myFileUrl = new URL(url);
HttpURLConnection conn = (HttpURLConnection) myFileUrl.openConnection();
conn.setDoInput(true);
conn.connect();
InputStream is = conn.getInputStream();
bitmap = BitmapFactory.decodeStream(is);
return bitmap;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
很简单吧,然而实际使用中如果只是这样的话,分分钟OOM给你看哦。
那么,OOM错误的原因就是图片如果很多或者很大,内存就溢出了。万幸我们可以选择输出多大的尺寸的Bitmap,而通常,一个App中的大部分图片其实是很小的。(如果都很大那就要涉及回收的问题了,这里不展开)
所以我们要控制一下获取的Bitmap的大小。
先上代码:
public static Bitmap returnBitMap(String url,int _w,int _h) {
URL myFileUrl = null;
Bitmap bitmap = null;
try {
myFileUrl = new URL(url);
//获得缩放比例
HttpURLConnection conn = (HttpURLConnection) myFileUrl.openConnection();
// conn.setConnectTimeout(3000);
conn.setDoInput(true);
conn.connect();
InputStream is = conn.getInputStream();
BitmapFactory.Options _options = new BitmapFactory.Options();
//设成true就只返回宽高
_options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(is,null,_options);
int scaleSize=1;
if(_w>0 && _h>0){
//缩略图的比例
scaleSize=calculateInSampleSize(_options,_w,_h);
if(scaleSize<1){
scaleSize=1;
}
}
conn.disconnect();
is.close();
//获得实际的图片数据
BitmapFactory.Options options = new BitmapFactory.Options();
//不涉及透明度可使用RGB_565
options.inPreferredConfig = Bitmap.Config.RGB_565;
options.inJustDecodeBounds = false;
options.inSampleSize=scaleSize;
conn = (HttpURLConnection) myFileUrl.openConnection();
//conn.setConnectTimeout(3000);
conn.setDoInput(true);
conn.connect();
is = conn.getInputStream();
bitmap = BitmapFactory.decodeStream(is,null,options);
//对位图的宽度进行缩放
try{
int width = bitmap.getWidth();
int height = bitmap.getHeight();
Bitmap newBitmap;
if(width>0 && height>0 && _w>0 && _h>0) {
float scaleWidth = ((float) bitmap.getHeight() * _w / _h) / bitmap.getWidth();
Matrix matrix = new Matrix();
matrix.postScale(scaleWidth, 1);
newBitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);
is.close();
return newBitmap;
}
}catch (Exception e){
}
is.close();
return bitmap;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
/**
* 计算缩放量
*/
public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight){
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
while ((halfHeight / inSampleSize) > reqHeight && (halfWidth / inSampleSize) > reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
主要就在BitmapFactory.Options部分。通过BitmapFactory.Options类可以获取原始图片的尺寸。然后与设备上实际的尺寸进行比较就可以得到需要的缩放比例。
先将inJustDecodeBounds
属性设置成true
,然后获取图片的bitmap,此时并不加载实际的图片内容,也就不占用内存,只是返回图片的原始尺寸。
然后根据图片在设备上显示的实际尺寸计算出缩放比例。
就是这里的calculateInSampleSize方法:
public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight){
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
while ((halfHeight / inSampleSize) > reqHeight && (halfWidth / inSampleSize) > reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
获取比例后将options.inJustDecodeBounds
属性设置为false
再次加载图片,并将缩放比例设置给options.inSampleSize
属性就可以获得符合实际显示需要的尺寸,这就没有什么资源上的浪费了。
至于options.inPreferredConfig = Bitmap.Config.RGB_565;
什么的就看具体需要了。
好,图片加载完了,再来个缓存吧。
毕竟每次显示都去请求一遍图片,想想就很闹心啊。
来,先来一个MemoryCache
类保存图片
import android.graphics.Bitmap;
import java.lang.ref.SoftReference;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/**
* 图片缓存(其中的id是判断是否同一个图片的标识)
*/
public class MemoryCache {
private Map<String, SoftReference<Bitmap>> cache= Collections.synchronizedMap(new HashMap<String, SoftReference<Bitmap>>());//软引用
public Bitmap get(String id){
if(!cache.containsKey(id))
return null;
SoftReference<Bitmap> ref=cache.get(id);
return ref.get();
}
public void put(String id, Bitmap bitmap){
cache.put(id, new SoftReference<>(bitmap));
}
public void remove(String id){
cache.remove(id);
}
public void clear() {
cache.clear();
}
}
然后获取图片的时候判断一下,缓存里有就直接取缓存的,没有就还是老样子。
Bitmap bitmapCache = imgCache.get(url);//这里是以图片地址作为标识,当然也可以设别的ID
if (bitmapCache != null && iscui) {
int width = bitmapCache.getWidth();
int height = bitmapCache.getHeight();
Bitmap cache2NewBitmap;
if(width>0 && height>0 && _w>0 && _h>0) {
float scaleWidth = ((float) bitmapCache.getHeight() * _w / _h) / bitmapCache.getWidth();
Matrix matrix = new Matrix();
matrix.postScale(scaleWidth, 1);
cache2NewBitmap = Bitmap.createBitmap(bitmapCache, 0, 0, width, height, matrix, true);
return cache2NewBitmap;
}
}
图片获取完要存到cache里:
if(imagekeyList.size()>cacheMaxSize) {//超出数量就从最开头起删除
imgCache.remove(imagekeyList.get(0));
imagekeyList.remove(0);
}
imagekeyList.add(url);
imgCache.put(url, bitmap);
这里头的imagekeyList
和cacheMaxSize
用来控制缓存数量
private static List<String> imagekeyList=new ArrayList<String>();
private static final int cacheMaxSize=100;
来,完整代码再来一遍:
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
/**
* 图片加载类
*/
public class imageLoader {
private static MemoryCache imgCache = new MemoryCache();
private static List<String> imagekeyList=new ArrayList<String>();
private static final int cacheMaxSize=100;
public static Boolean iscui=true;//是否加载缓存
public static Bitmap returnBitMap(String url, int _w, int _h) {
//检测是否已在内存
Bitmap bitmapCache = imgCache.get(url);
if (bitmapCache != null && iscui) {
int width = bitmapCache.getWidth();
int height = bitmapCache.getHeight();
Bitmap cache2NewBitmap;
// Log.d("LOGCAT","scale:"+width+"-"+height+"-"+_w+"-"+_h);
if(width>0 && height>0 && _w>0 && _h>0) {
float scaleWidth = ((float) bitmapCache.getHeight() * _w / _h) / bitmapCache.getWidth();
Matrix matrix = new Matrix();
matrix.postScale(scaleWidth, 1);
cache2NewBitmap = Bitmap.createBitmap(bitmapCache, 0, 0, width, height, matrix, true);
return cache2NewBitmap;
}
}
URL myFileUrl = null;
Bitmap bitmap = null;
try {
myFileUrl = new URL(url);
//获得缩放比例
HttpURLConnection conn = (HttpURLConnection) myFileUrl.openConnection();
// conn.setConnectTimeout(3000);
conn.setDoInput(true);
conn.connect();
InputStream is = conn.getInputStream();
BitmapFactory.Options _options = new BitmapFactory.Options();
//设成true就只返回宽高
_options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(is,null,_options);
// Log.d("LOGCAT","picSize:"+options.outWidth+"-"+options.outHeight+"-"+_w+"-"+_h);
int scaleSize=1;
if(_w>0 && _h>0){
//缩略图的比例
scaleSize=calculateInSampleSize(_options,_w,_h);
if(scaleSize<1){
scaleSize=1;
}
}
conn.disconnect();
is.close();
//获得实际的图片数据
BitmapFactory.Options options = new BitmapFactory.Options();
//不涉及透明度可使用RGB_565
options.inPreferredConfig = Bitmap.Config.RGB_565;
//设置成内存不足时可回收
options.inPurgeable = true;
//设施是否深拷贝inPurgeable=false时无效
options.inInputShareable = true;
options.inJustDecodeBounds = false;
options.inSampleSize=scaleSize;
conn = (HttpURLConnection) myFileUrl.openConnection();
//conn.setConnectTimeout(3000);
conn.setDoInput(true);
conn.connect();
is = conn.getInputStream();
bitmap = BitmapFactory.decodeStream(is,null,options);
//对位图的宽度进行缩放
try{
int width = bitmap.getWidth();
int height = bitmap.getHeight();
Bitmap newBitmap;
// Log.d("LOGCAT","scale:"+width+"-"+height+"-"+_w+"-"+_h);
if(width>0 && height>0 && _w>0 && _h>0) {
float scaleWidth = ((float) bitmap.getHeight() * _w / _h) / bitmap.getWidth();
Matrix matrix = new Matrix();
matrix.postScale(scaleWidth, 1);
newBitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);
is.close();
if(imagekeyList.size()>cacheMaxSize) {
imgCache.remove(imagekeyList.get(0));
imagekeyList.remove(0);
}
imagekeyList.add(url);
imgCache.put(url, bitmap);
return newBitmap;
}
}catch (Exception e){
}
is.close();
if(imagekeyList.size()>cacheMaxSize) {
imgCache.remove(imagekeyList.get(0));
imagekeyList.remove(0);
}
imagekeyList.add(url);
imgCache.put(url, bitmap);
return bitmap;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
//计算缩放量
public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight){
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
while ((halfHeight / inSampleSize) > reqHeight && (halfWidth / inSampleSize) > reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
/**
* 清除图片cache
*/
public static void clearCache(){
imgCache.clear();
}
}
网友评论