編輯:關於android開發
經常會用到 網絡文件 比如查看大圖片數據 資源優化的問題,當然用開源的項目 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.
ImageDownloadTask task =
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.
ImageDownloadTask task = 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(ImageDownloadTask task){
264.
super
(Color.BLUE);
265.
taskReference =
new
WeakReference<MyImageLoader.ImageDownloadTask>(task);
266.
}
267.
// 返回去這個 task 用於比較
268.
public
ImageDownloadTask getImageDownloadTask(){
269.
return
taskReference.get();
270.
}
271.
}
272.
273.
274.
// 根據 給 的 iamgeView、 得到裡面的 task 用於和當前的 task比較是不是同1個
275.
private
ImageDownloadTask getImageDownloadTask(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.
ImageDownloadTask task = 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
Android 手把手帶你玩轉自定義相機 概述 相機幾乎是每個APP都要用到的功能,萬一老板讓你定制相機方不方?反正我是有點方。關於相機的兩天奮斗總結免費送給你。 啟
為什麼 Android Studio 工程文件夾占用空間這麼大?我們來給它減減肥,androidstudio偶然中發現Android Studio的工程文件夾比ADT B
activity切換動畫特效,activity切換特效效果圖: 結構圖: 測試代碼: 布局: 1 <?xml version=1.
AndroidAnnnotations注入框架使用之第三方框架集成RoboGuice(十三) (一).前言: 前面我們已經對於AndroidA