您的位置:首页 > 理论基础 > 计算机网络

android 网络加载图片,对图片资源进行优化,并且实现内存双缓存 + 磁盘缓存

2016-05-11 10:47 896 查看
经常会用到 网络文件 比如查看大图片数据 资源优化的问题,当然用开源的项目 Android-Universal-Image-Loader 或者 ignition 都是个很好的选择。

在这里把原来 写过的优化的代码直接拿出来,经过测试千张图片效果还是不错的。

免费培训课:http://www.jinhusns.com/Products/Curriculum/?type=xcj



工程目录



至于 Activity 就是加载了 1个网格布局

01.
/**

02.
*实现 异步加载 和   2级缓存

03.
*/

04.
public
class
ImagedownActivity
extends
Activity {

05.

06.
public
static
String filepath;

07.
@Override

08.
public
void
onCreate(Bundle savedInstanceState) {

09.
super
.onCreate(savedInstanceState);

10.
setContentView(R.layout.main);

11.
filepath =
this
.getCacheDir().getAbsolutePath();

12.
GridView gv=(GridView)findViewById(R.id.gridview01);

13.
//设置列数

14.
gv.setNumColumns(
3
);

15.
//配置适配器

16.
gv.setAdapter(
new
Myadapter(
this
));

17.
}

18.

19.
@Override

20.
protected
void
onDestroy() {

21.
//TODO Auto-generated method stub

22.
//activity 销毁时,清除缓存

23.
MyImageLoader.removeCache(filepath);

24.
super
.onDestroy();

25.
}

26.

27.
}


接下来 Myadapter.java(给网格每个item塞入图片 )在生成每个 item 异步请求网络获取image

01.
public
class
Myadapter
extends
BaseAdapter {

02.
private
Context context;

03.
private
String  root =
"http://192.168.0.100:8080/Android_list/"
;

04.
private
String[] URLS;

05.
private
final
MyImageLoader  myImageLoader =
new
MyImageLoader(context);;

06.

07.
/**

08.
*adapter 初始化的时候早一堆数据

09.
*这里我请求的是自己搭的服务器

10.
*@param context

11.
*/

12.
public
Myadapter(Context context){

13.
this
.context =context;

14.
URLS =
new
String[
999
];

15.
for
(
int
i =
0
; i <
999
; i++) {

16.
URLS[i] = root + (i+
1
)+
".jpg"
;

17.
}

18.
}

19.

20.

21.
@Override

22.
public
int
getCount() {

23.
return
URLS.length;

24.
}

25.

26.
@Override

27.
public
Object getItem(
int
position) {

28.
return
URLS[position];

29.
}

30.

31.
@Override

32.
public
long
getItemId(
int
position) {

33.
return
URLS[position].hashCode();

34.
}

35.

36.

37.

38.
@Override

39.
public
View getView(
int
position,View view,ViewGroup parent) {

40.
ImageView imageView;

41.
if
(view==
null
){

42.
imageView=
new
ImageView(context);

43.
imageView.setLayoutParams(
new
GridView.LayoutParams(
200
,
190
));

44.
imageView.setAdjustViewBounds(
false
);

45.
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);

46.
imageView.setPadding(
5
,
5
,
5
,
5
);

47.
}
else
{

48.
imageView=(ImageView)view;

49.
}

50.
myImageLoader.downLoad(URLS[position],(ImageView)imageView ,context);

51.
return
imageView;

52.
}

53.
}


MyImageLoader.java

001.
public
class
MyImageLoader {

002.

003.
//最大内存

004.
final
static
int
memClass = (
int
) Runtime.getRuntime().maxMemory();

005.
private
Context context;

006.

007.
//是否缓存到硬盘

008.
private
boolean
diskcache =
true
;

009.

010.
//定义一级 缓存的图片数

011.
private
static
final
int
catch_num =
10
;

012.

013.
//定义二级缓存 容器  软引用

014.
private
static
ConcurrentHashMap<String,SoftReference<Bitmap>> current_hashmap = 
new
ConcurrentHashMap<String,SoftReference<Bitmap>>();

015.

016.
//定义一级缓存容器  强引用       (catch_num ,0.75f,true) 默认参 数                                                                                                                        2.加载因子默认        3.排序模式 true

017.
private
static
LinkedHashMap<String,Bitmap> link_hashmap = 
new
LinkedHashMap<String,Bitmap>(catch_num ,
0
.75f,
true
) {

018.

019.
//必须实现的方法

020.
protected
boolean
removeEldestEntry(java.util.Map.Entry<String,Bitmap> eldest) {

021.
/**当一级缓存中 图片数量大于 定义的数量 放入二级缓存中

022.
*/

023.
if
(
this
.size() > catch_num) {

024.
//软连接的方法 存进二级缓存中

025.
current_hashmap.put(eldest.getKey(),
new
SoftReference<Bitmap>(

026.
eldest.getValue()));

027.
//缓存到本地

028.
cancheToDisk(eldest.getKey(),eldest.getValue() );

029.

030.
return
true
;

031.
}

032.
return
false
;

033.
};

034.
};

035.

036.
public
MyImageLoader(Context context) {

037.

038.
}

039.

040.

041.
/**

042.
*外部调用此方法   进行下载图片

043.
*/

044.
public
void
downLoad(String key ,ImageView imageView,Context context){

045.
//先从缓存中找   。

046.
context =
this
.context;

047.

048.
Bitmap bitmap =getBitmapFromCache(key);

049.
if
(
null
!= bitmap){

050.
imageView.setImageBitmap(bitmap);

051.
cancleDownload(key,imageView); 
//取消下载

052.
return
;

053.
}

054.

055.
//缓存中 没有  把当前的 imageView 给他 得到 task

056.
if
(cancleDownload(key,imageView)){ 
//没有任务进行。,。。开始下载

057.
ImageDownloadTasktask =
new
ImageDownloadTask(imageView);

058.
Zhanwei_Image zhanwei_image =
new
Zhanwei_Image(task);

059.
//先把占位的图片放进去

060.
imageView.setImageDrawable(zhanwei_image);

061.
//task执行任务

062.
task.execute(key); 

063.
}

064.
}

065.

066.

067.
/**此方法 用于优化  : 用户直接 翻到 哪个 就先加载 哪个、

068.
*@param key               - URL

069.
*@param imageView          - imageView

070.
*core: 给当前的 imageView 得到给他下载的 task

071.
*/

072.

073.
private
boolean
cancleDownload(String key,ImageView imageView){

074.
//给当前的 imageView 得到给他下载的 task

075.
ImageDownloadTasktask =getImageDownloadTask(imageView);

076.
if
(
null
!= task){

077.
String down_key = task.key;

078.
if
(
null
== down_key || !down_key.equals(key)){

079.
task.cancel(
true
);
//imageview 和 url 的key不一样       取消下载

080.
}
else
{

081.
return
false
;
//正在下载:

082.
}

083.
}

084.
return
true
;
//没有正在下载

085.
}

086.

087.

088.

089.
// public void getThisProcessMemeryInfo() {

090.
//       int pid = android.os.Process.myPid();

091.
//       android.os.Debug.MemoryInfo[] memoryInfoArray = activityManager.getProcessMemoryInfo(new int[] {pid});

092.
//       System.out.println("本应用当前使用了" + (float)memoryInfoArray[0].getTotalPrivateDirty() / 1024 + "mb的内存");

093.
//   }

094.

095.

096.

097.
/**

098.
*从缓存中得到 图片的方法 1.先从一级 缓存找 linkhashmap 不是线程安全的 必须要加同步

099.
*/

100.
public
Bitmap getBitmapFromCache(String key) {

101.
//1.先在一级缓存中找

102.
synchronized
(link_hashmap) {

103.
Bitmap bitmap =link_hashmap.get(key);

104.
if
(
null
!= bitmap) {

105.
link_hashmap.remove(key);

106.
//按照 LRU是Least Recently Used 近期最少使用算法 内存算法 就近 就 原则 放到首位

107.
link_hashmap.put(key,bitmap);

108.
System.out.println(
" 在缓存1中找图片了 ="
+key);

109.
return
bitmap;

110.
}

111.
}

112.

113.
//2. 到二级 缓存找

114.
SoftReference<Bitmap> soft = current_hashmap.get(key);

115.
if
(soft !=
null
) {

116.
//得到 软连接 中的图片

117.
Bitmap soft_bitmap =soft.get();

118.
if
(
null
!= soft_bitmap) {

119.
System.out.println(
" 在缓存2中找图片了 ="
+key);

120.
return
soft_bitmap;

121.
}

122.
}
else
{

123.
//没有图片的话 把这个key删除

124.
current_hashmap.remove(key);

125.
}

126.

127.

128.
//3.都没有的话去从外部缓存文件读取

129.
if
(diskcache){

130.
Bitmap bitmap =getBitmapFromFile(key);

131.
if
(bitmap!=
null
){

132.
link_hashmap.put(key,bitmap); 
//将图片放到一级缓存首位

133.
return
bitmap;

134.
}

135.
}

136.

137.
return
null
;

138.
}

139.

140.

141.
/**

142.
*缓存到本地文件

143.
*@param key

144.
*@param bitmap

145.
*/

146.
public
static
void
cancheToDisk(String key ,Bitmap bitmap ){

147.
//2.缓存bitmap至/data/data/packageName/cache/文件夹中

148.
try
{

149.
String fileName = getMD5Str(key);

150.
String filePath = ImagedownActivity.filepath +
"/"
+ fileName;

151.
System.out.println(
"缓存到本地==="
+ filePath);

152.
FileOutputStream fos =
new
FileOutputStream(filePath);

153.
bitmap.compress(Bitmap.CompressFormat.JPEG,
100
,fos);

154.

155.
}
catch
(Exception e) {

156.

157.
}

158.
}

159.

160.

161.
/**

162.
*从外部文件缓存中获取bitmap

163.
*@param url

164.
*@return

165.
*/

166.
private
Bitmap getBitmapFromFile(String url){

167.
Bitmap bitmap =
null
;

168.
String fileName = getMD5Str(url);

169.
if
(fileName ==
null
){

170.
return
null
;

171.
}

172.
String filePath = ImagedownActivity.filepath +
"/"
+ fileName;

173.
try
{

174.
FileInputStream fis =
new
FileInputStream(filePath);

175.
bitmap =BitmapFactory.decodeStream(fis);

176.
System.out.println(
"在本地缓存中找到图片==="
+ filePath);

177.
}
catch
(FileNotFoundException e) {

178.
System.out.println(
"getBitmapFromFile==="
+ e.toString());

179.
e.printStackTrace();

180.
bitmap =
null
;

181.
}

182.
return
bitmap;

183.
}

184.

185.

186.

187.
/**

188.
*清理文件缓存

189.
*@param dirPath

190.
*@return

191.
*/

192.
public
static
boolean
removeCache(String dirPath) {

193.
File dir =
new
File(dirPath);

194.
File[] files = dir.listFiles();

195.
if
(files ==
null
|| files.length ==
0
) {

196.
return
true
;

197.
}

198.
int
dirSize =
0
;

199.
//这里删除所有的缓存

200.
int
all_ = (
int
) (
1
*files.length +
1
);

201.
//对files 进行排序

202.
Arrays.sort(files,
new
FileLastModifiedSort());

203.
for
(
int
i =
0
; i <all_ ; i++) {

204.
files[i].delete();

205.
}

206.
return
true
;

207.
}

208.

209.

210.
/**

211.
*根据文件最后修改时间进行排序

212.
*/

213.
private
static
class
FileLastModifiedSort
implements
Comparator<File> {

214.
@Override

215.
public
int
compare(File lhs,File rhs) {

216.
if
(lhs.lastModified() > rhs.lastModified()) {

217.
return
1
;

218.
}
else
if
(lhs.lastModified() == rhs.lastModified()) {

219.
return
0
;

220.
}
else
{

221.
return
-
1
;

222.
}

223.
}

224.
}

225.

226.

227.
/**

228.
*MD5 加密

229.
*/

230.
private
static
String getMD5Str(String str) { 

231.
MessageDigest messageDigest =
null
; 

232.
try
{ 

233.
messageDigest = MessageDigest.getInstance(
"MD5"
); 

234.
messageDigest.reset(); 

235.
messageDigest.update(str.getBytes(
"UTF-8"
)); 

236.
}
catch
(NoSuchAlgorithmException e) { 

237.
System.out.println(
"NoSuchAlgorithmException caught!"
); 

238.
return
null
;

239.
}
catch
(UnsupportedEncodingException e) { 

240.
e.printStackTrace();

241.
return
null
;

242.
}

243.

244.
byte
[] byteArray = messageDigest.digest(); 

245.
StringBuffer md5StrBuff =
new
StringBuffer(); 

246.
for
(
int
i =
0
; i <byteArray.length; i++) { 

247.
if
(Integer.toHexString(
0xFF
& byteArray[i]).length() ==
1
)

248.
md5StrBuff.append(
"0"
).append(Integer.toHexString(
0xFF
& byteArray[i])); 

249.
else

250.
md5StrBuff.append(Integer.toHexString(
0xFF
& byteArray[i])); 

251.
}

252.
return
md5StrBuff.toString(); 

253.
}

254.

255.

256.
//------------------------ 异步加载----------------------------

257.
/**

258.
*占位的 图片 或者 颜色      用来绑定 相应的图片

259.
*/

260.
class
Zhanwei_Image
extends
ColorDrawable{

261.
//里面存放 相应 的异步 处理时加载好的图片 ----- 相应的 task

262.
private
final
WeakReference<ImageDownloadTask>taskReference;

263.
public
Zhanwei_Image(ImageDownloadTasktask){ 

264.
super
(Color.BLUE);

265.
taskReference =
new
WeakReference<MyImageLoader.ImageDownloadTask>(task); 

266.
}

267.
//返回去这个 task 用于比较

268.
public
ImageDownloadTaskgetImageDownloadTask(){

269.
return
taskReference.get();

270.
}

271.
}

272.

273.

274.
//根据 给 的 iamgeView、 得到里面的 task  用于和当前的 task比较是不是同1个

275.
private
ImageDownloadTaskgetImageDownloadTask(ImageView imageView){

276.
if
(
null
!= imageView){

277.
Drawable drawable = imageView.getDrawable();

278.
if
(drawable 
instanceof
Zhanwei_Image)

279.
return
((Zhanwei_Image)drawable).getImageDownloadTask();

280.

281.
}

282.
return
null
;

283.
}

284.

285.

286.

287.
/**

288.
*把图片 添加到缓存中

289.
*/

290.
public
void
addBitmap(String key,Bitmap bitmap) {

291.
if
(
null
!= bitmap) {

292.
synchronized
(link_hashmap) { 
//添加到一级 缓存中

293.
link_hashmap.put(key,bitmap);

294.
}

295.
}

296.
}

297.

298.

299.
/**在后台 加载每个图片 

300.
*第一个参数 第2个要进度条不 第三个返回结果 bitmap

301.
*/

302.
class
ImageDownloadTask
extends
AsyncTask<String,Void,Bitmap> {

303.

304.
private
String key;

305.
private
WeakReference<ImageView> imgViReference;

306.

307.
public
ImageDownloadTask(ImageView imageView) {

308.
//imageView 传进来 。。要给哪个iamgeView加载图片

309.
imgViReference =
new
WeakReference<ImageView>(

310.
imageView);

311.
}

312.

313.
@Override

314.
protected
Bitmap doInBackground(String... params){

315.
key = params[
0
];

316.
//调用下载函数 根据 url 下载

317.
return
downloadBitmap(key);

318.
}

319.

320.
@Override

321.
protected
void
onPostExecute(Bitmap result) {

322.
if
(isCancelled()){

323.
result =
null
;

324.
}

325.

326.
System.out.println(
"result=="
+ result.getByteCount()+
"---memClassmemery="
+memClass);

327.

328.
if
(
null
!= result){

329.
//保存到缓存中

330.
addBitmap(key,result);

331.
ImageView  imageView = imgViReference.get();

332.
if
(
null
!= imageView){

333.
//向 imageView 里面放入 bitmap

334.
ImageDownloadTasktask =getImageDownloadTask(imageView);

335.

336.
/**

337.
*判断 是不是 同一个 task() 

338.
*如果当前这个 task  ==  imageView 里面的那个 task 就是同1个

339.
*/

340.
if
(
this
== task ){

341.
imageView.setImageBitmap(result);

342.

343.
}

344.
}

345.
}

346.
}

347.
}

348.

349.

350.
/**

351.
*连接网络 客户端 下载图片

352.
*/

353.
private
Bitmap downloadBitmap(String url) {

354.

355.
final
HttpClient client = AndroidHttpClient.newInstance(
"Android"
);

356.
final
HttpGet getRequest =
new
HttpGet(url); 

357.
try
{

358.
HttpResponse response = client.execute(getRequest);

359.
final
int
statusCode = response.getStatusLine().getStatusCode();

360.

361.
if
(statusCode != HttpStatus.SC_OK) {

362.

363.
Log.w(
"ImageDownloader"
,
"Error "
+ statusCode +
" while retrieving bitmap from "
+ url);

364.
return
null
;

365.
}

366.

367.
final
HttpEntity entity = response.getEntity();

368.
if
(entity !=
null
) {

369.
InputStream inputStream =
null
;

370.
try
{

371.

372.
inputStream = entity.getContent(); 

373.
/**

374.
*1.没有压缩直接将生成的bitmap返回去

375.
*/

376.
//                 return BitmapFactory.decodeStream(inputStream);

377.

378.
/**

379.
*2.得到data后在这里把图片进行压缩

380.
*/

381.
byte
[] data = StreamTool.read(inputStream); 

382.
return
BitmapManager.scaleBitmap(context,data,
0
.3f);

383.
//                  return BitmapFactory.decodeStream(new FlushedInputStream(inputStream));

384.
}
finally
{

385.
if
(inputStream !=
null
) {

386.
inputStream.close();

387.
}

388.
entity.consumeContent();

389.
}

390.
}

391.
}
catch
(IOException e) {

392.
getRequest.abort();

393.
}
catch
(IllegalStateException e) {

394.
getRequest.abort();

395.
}
catch
(Exception e) {

396.
getRequest.abort();

397.
}
finally
{

398.
if
((client
instanceof
AndroidHttpClient)) {

399.
((AndroidHttpClient) client).close();

400.
}

401.
}

402.
return
null
;

403.
}

404.

405.
}


StreamTool.java

01.
public
class
StreamTool {

02.

03.
public
static
byte
[] read(InputStream in)
throws
Exception{

04.
ByteArrayOutputStream  out_byte =
new
ByteArrayOutputStream();

05.
byte
[] buff =
new
byte
[
1024
];

06.
int
len=
0
;

07.
while
((len = in.read(buff))!= -
1
){

08.
//写到内存中  字节流

09.
out_byte.write(buff,
0
,len);

10.
}

11.
out_byte.close(); 

12.
//把内存数据返回

13.
return
out_byte.toByteArray(); 

14.
}

15.
}


BitmapManager.java (这个类里面对 网络资源的图片 进行了优化)

001.
public
class
BitmapManager {

002.

003.
/**

004.
*按屏幕适配Bitmap

005.
*/

006.
public
static
Bitmap scaleBitmap(Context context,
byte
[] data ,
float
percent) {

007.

008.
//这里我不获取了,假设是下面这个分辨率

009.
int
screenWidth =
540
;

010.
int
screenrHeight =
950
;

011.
//设置 options

012.
BitmapFactory.Options options =
new
BitmapFactory.Options();

013.
/**

014.
*BitmapFactory.Options这个类,有一个字段叫做 inJustDecodeBounds.SDK中对这个成员的说明是这样的:

015.
*If set to true,the decoder will return null (no bitmap),but the out…

016.
*也就是说,如果我们把它设为true,那么BitmapFactory.decodeFile(String path,Options opt)并不会真的返回一个Bitmap给你,

017.
*它仅仅会把它的宽,高取回来给你,这样就不会占用太多的内存,也就不会那么频繁的发生OOM了。

018.
*/

019.
options.inJustDecodeBounds =
true
;

020.

021.
//读取

022.
Bitmap bitmap =BitmapFactory.decodeByteArray(data,
0
,data.length,options);

023.

024.
int
imgWidth = options.outWidth;

025.
int
imgHeight = options.outHeight;

026.

027.
//如果比你设置的宽高大  就进行缩放,

028.
if
(imgWidth > screenWidth *percent || imgHeight > screenrHeight *percent) {

029.
options.inSampleSize =calculateInSampleSize(options,screenWidth,screenrHeight,percent);

030.
}

031.

032.

033.
/**

034.
*If set to true,the decoder will return null (no bitmap),but the out... fields will still be set,allowing the caller 

035.
*to query the bitmap without having to allocate the memory for its pixels.

036.
*

037.
*如果设置成 true,这个编码将会返回1个null , 但是那个区域仍将被设置(也就是存在),允许(调用者)去查询那个没有分配 内存的像素  bitmap 

038.
*/

039.
options.inJustDecodeBounds =
false
;

040.

041.
/**

042.
*Android的Bitmap.Config给出了bitmap的一个像素所对应的存储方式,

043.
*有RGB_565,ARGB_8888,ARGB_4444,ALPHA_8四种。RGB_565表示的是红绿蓝三色分别用5,6,5个比特来存储,

044.
*一个像素占用了5+6+5=16个比特。ARGB_8888表示红绿蓝和半透明分别用8,8,8,8个比特来存储,

045.
*一个像素占用了8+8+8+8=32个比特。这样的话如果图片是以RGB_8888读入的,那么占用内存的大小将是RGB_565读入方式的2倍。

046.
*通常我们给Imagview加载图片是通过setDrawable或者在xml文件中用android:src来设置

047.
*默认的加载图片大小的方式是以RGB_8888读入的。

048.
*

049.
*/

050.
options.inPreferredConfig = Bitmap.Config.RGB_565;

051.

052.
/**

053.
*If this is set to true,then the resulting bitmap will allocate its pixels such that they can be purged 

054.
*if the system needs to reclaim memory.

055.
*

056.
*如果设置成 true, 这个结果bitmap 将会被分配像素,这样他们就能被 系统回收了,当系统需要回收内存的时候

057.
*/

058.
options.inPurgeable =
true
;

059.

060.
/**

061.
*This field works in conjuction with inPurgeable.

062.
*这个方法是在   inPurgeable 的基础上工作的

063.
*/

064.
options.inInputShareable =
true
;

065.

066.

067.
bitmap =BitmapFactory.decodeByteArray(data,
0
,data.length,options);

068.

069.
System.out.println(
"data==="
+  data.length +
"  change == bitmap byte "
+ bitmap.getByteCount());

070.
return
bitmap;

071.
}

072.

073.

074.

075.
//                                                   options       reqWidth 屏幕宽      reqHeight屏幕高      你的view是屏幕的多大

076.
public
static
int
calculateInSampleSize(BitmapFactory.Options options,
int
screenWidth,
int
screenHeight ,
float
percent) {

077.

078.
//原始图片宽高

079.
final
int
height = options.outHeight;

080.
final
int
width = options.outWidth;

081.
//倍数

082.
int
inSampleSize =
1
;

083.

084.
if
(height > screenHeight *percent || width > screenWidth *percent) {

085.

086.
//计算目标宽高与原始宽高的比值

087.
final
int
inSampleSize_h = Math.round((
float
) height / (
float
)(screenHeight *percent));

088.

089.
final
int
inSampleSize_w = Math.round((
float
) width / (
float
)(screenWidth *percent));

090.

091.
//选择两个比值中较小的作为inSampleSize的

092.
inSampleSize =inSampleSize_h < inSampleSize_w ? inSampleSize_h : inSampleSize_w;

093.

094.
System.out.println(
"inSampleSize===="
+ inSampleSize);

095.
//

096.
if
(inSampleSize <
1
) {

097.
inSampleSize =
1
;

098.
}

099.
}

100.
//简单说这个数字就是 缩小为原来的几倍,根据你的image需要占屏幕多大动态算的(比如你用的权重设置layout)

101.
return
inSampleSize;

102.
}

103.
}


这个是代码输出的最多给这个进程分配的内存 128M



可以看到我上面的bitmapManager 里面有个 options.inPreferredConfig 注释写的很清楚,可以上去看一下,接下来贴几种格式的效果图

rgb565 和 argb_444 所占的内存 (54000)



看一下 argb_8888 (108000)



当然可能仔细看的人会看到我一开始截的 鸣人的效果图 上半部分 和 下半部分的颜色会有点问题。上面的rgb_565 生成的,和原图色彩可能会有点出入。

但是内存真心少了一半,所以各种取舍就看个人了,代码注释都谢的很清楚了。

至于 : MyImageLoaderLru.java 其实就是 MyImageLoader.java

先贴出代码不同地方的代码 : 就是在强引用的地方 把 LinkedHashMap 换成了 LruCache

01.
//获取单个进程可用内存的最大值  

02.
//方式一:使用ActivityManager服务(计量单位为M)  

03.
/*int memClass = ((ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE)).getMemoryClass();*/

04.
//方式二:使用Runtime类(计量单位为Byte)  

05.
final
static
int
memClass = (
int
) Runtime.getRuntime().maxMemory();

06.
//3. 定义一级缓存容器  强引用       (catch_num /2,0.75f,true) 默认参 数                                                                                                                        2.加载因子默认        3.排序模式 true

07.
final
static
int
max = memClass/
5
;

08.

09.
//LruCache 用强引用将  图片放入     LinkedHashMap 

10.
private
static
LruCache<String,Bitmap> lrucache = 
new
LruCache<String,Bitmap>(max) {

11.
protected
int
sizeOf(String key,Bitmap value) {

12.
if
(value !=
null
) {

13.
//计算存储bitmap所占用的字节数  

14.
return
value.getRowBytes() *value.getHeight();

15.
}
else
{

16.
return
0
;

17.
}

18.
}

19.

20.
@Override

21.
protected
void
entryRemoved(
boolean
evicted,String key,Bitmap oldValue,Bitmap newValue) {

22.
if
(oldValue !=
null
) {

23.
//当硬引用缓存容量已满时,会使用LRU算法将最近没有被使用的图片转入软引用缓存  

24.
current_hashmap.put(key,
new
SoftReference<Bitmap>(oldValue));

25.
}

26.
}

27.
};


1. 强引用:LruCache 后面再说,其实他内的内部封装的就是1个 LinkedHashMap 。LinkedHashMap 是线程不安全的,所以上面都会用到同步。

2. 软引用:ConcurrentHashMap 是线程安全的,并且支持高并发很有效率,这个后面也会说到,为什么要用 软引用 SoftReference,这个是在系统将要oom时,就会回收

软引用的对象资源,所以才会用到他,防止程序出异常 。

3. 磁盘缓存: 这个经常会看到网易新闻等,应用有些界面你看了很多图片,往上翻很多, 其实没有再次访问网络,会将部分image缓存在sdcard里。

4. 其中1个优化: 当比如用户快速滑动到 最底部,其实是最先加载显示给用户的部分的内容的,这样就是用户看到哪加载哪,1个是快,1个是避免资源浪费。

原理: 当用户进入界面加载图片 ,首先会从1级缓存强引用中找,找不到回去2级缓存软引用中找,找不到再去sdcard中找,再找不到才会去请求网络加载资源。

当然sdcard的缓存 看个人需求是否需要。

注: android 4.0 后 对 SoftReference 的回收机制进行了改变,所以你是可以不用 2级缓存的,直接去掉就好了。

只要控制好你的 lrucache 或者 linkedhashmap就好了。

免费培训课:http://www.jinhusns.com/Products/Curriculum/?type=xcj
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: