版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
【移動應(yīng)用開發(fā)技術(shù)】Android中怎么實現(xiàn)圖片緩存機(jī)制
這期內(nèi)容當(dāng)中在下將會給大家?guī)碛嘘P(guān)Android中怎么實現(xiàn)圖片緩存機(jī)制,文章內(nèi)容豐富且以專業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。Android圖片緩存機(jī)制的深入理解Android加載一張圖片到用戶界面是很簡單的,但是當(dāng)一次加載多張圖片時,情況就變得復(fù)雜起來。很多情況下(像ListView、GridView或ViewPager等組件),屏幕上已顯示的圖片和即將滑動到當(dāng)前屏幕上的圖片數(shù)量基本上是沒有限制的。這些組件通過重用已經(jīng)移除屏幕的子視圖來將降低內(nèi)存的使用,垃圾回收器也會及時釋放那些已經(jīng)不再使用的已下載的圖片,這些都是很好的方法,但是為了保持一個流暢的、快速加載的用戶界面,就應(yīng)該避免當(dāng)再次回到某個頁面時而重新處理圖片。內(nèi)存緩存和磁盤緩存可以幫我們做到這些,它們允許組件快速地重新加載已處理好的圖片。使用內(nèi)存緩存內(nèi)存緩存允許快速地訪問圖片,但它以占用App寶貴的內(nèi)存為代價。LruCache類(APILevel4的SupportLibrary也支持)特別適合來做圖片緩存,它使用一個強(qiáng)引用的LinkedHashMap來保存最近使用的對象,并且會在緩存數(shù)量超出預(yù)設(shè)的大小之前移除最近最少使用的對象。說明:以前流行的內(nèi)存緩存方案是使用軟引用或弱引用來緩存圖片,然而現(xiàn)在不推薦這樣做了,因為從android2.3(APILevel9)起,垃圾收集器更傾向于先回收軟引用或弱引用,這樣就使它們變得低效。另外在Android3.0(APILevel11)之前,圖片的像素數(shù)據(jù)是存儲在本地內(nèi)存(nativememory)中的,它以一種不可預(yù)測的方式釋放,因此可能會導(dǎo)致App超過內(nèi)存限制甚至崩潰。為了給LruCache設(shè)置一個合適的大小,以下是應(yīng)該考慮的一些因素:1.你的Activity或App的可用內(nèi)存是多少?2.一次展示到屏幕上的圖片是多少?有多少圖片需要預(yù)先準(zhǔn)備好以便隨時加載到屏幕?3.設(shè)備的屏幕尺寸和密度是多少?像GalaxyNexus這樣的高分辨率(xhdpi)設(shè)備比NexusS這樣分辨率(hdpi)的設(shè)備在緩存相同數(shù)量的圖片時需要更大的緩存空間。4.圖片的尺寸和配置是怎樣的?每張圖片會占用多少內(nèi)存?5.圖片的訪問頻率如何?是否有一些圖片比另一些訪問更加頻繁?如果這樣的話,或許可以將某些圖片一直保存在內(nèi)存里或者針對不同的圖片分組設(shè)置不同的LruCache對象。6.你能否平衡圖片質(zhì)量和數(shù)量之間的關(guān)系?有時候存儲更多低質(zhì)量的圖片更加有用,當(dāng)在需要的時候,再通過后臺任務(wù)下載高質(zhì)量的圖片。這里沒有一個具體的大小和計算公式適用于所有的App,你需要分析你的使用情況并得到一個合適的方案。當(dāng)一個緩存太小時會導(dǎo)致無益的額外的開銷,而緩存太大時也可能會引起Java.lang.OutOfMemory異常,另外緩存越大,留給App其他部分的內(nèi)存相應(yīng)就越小。這里是一個為圖片設(shè)置LruCache的示例:private
LruCache<String,
Bitmap>
mMemoryCache;
@Override
protected
void
onCreate(Bundle
savedInstanceState)
{
...
//
Get
max
available
VM
memory,
exceeding
this
amount
will
throw
an
//
OutOfMemory
exception.
Stored
in
kilobytes
as
LruCache
takes
an
//
int
in
its
constructor.
final
int
maxMemory
=
(int)
(Runtime.getRuntime().maxMemory()
/
1024);
//
Use
1/8th
of
the
available
memory
for
this
memory
cache.
final
int
cacheSize
=
maxMemory
/
8;
mMemoryCache
=
new
LruCache<String,
Bitmap>(cacheSize)
{
@Override
protected
int
sizeOf(String
key,
Bitmap
bitmap)
{
//
The
cache
size
will
be
measured
in
kilobytes
rather
than
//
number
of
items.
return
bitmap.getByteCount()
/
1024;
}
};
...
}
public
void
addBitmapToMemoryCache(String
key,
Bitmap
bitmap)
{
if
(getBitmapFromMemCache(key)
==
null)
{
mMemoryCache.put(key,
bitmap);
}
}
public
Bitmap
getBitmapFromMemCache(String
key)
{
return
mMemoryCache.get(key);
}說明:在上述例子中,我們分配了應(yīng)用內(nèi)存的1/8作為緩存大小,在一個normal/hdpi的設(shè)備上最少也有4MB(32/8)的大小。一個800*480分辨率的屏幕上的一個填滿圖片的GridView大概占用1.5MB(800*480*4byte)的內(nèi)存,因此該Cache至少可以緩存2.5頁這樣的圖片。當(dāng)加載一張圖片到ImageView時,首先檢查LruCache,如果找到圖片,就直接用來更新ImageView,如果沒找到就開啟一個后臺線程來處理:public
void
loadBitmap(int
resId,
ImageView
imageView)
{
final
String
imageKey
=
String.valueOf(resId);
final
Bitmap
bitmap
=
getBitmapFromMemCache(imageKey);
if
(bitmap
!=
null)
{
mImageView.setImageBitmap(bitmap);
}
else
{
mImageView.setImageResource(R.drawable.image_placeholder);
BitmapWorkerTask
task
=
new
BitmapWorkerTask(mImageView);
task.execute(resId);
}
}上述線程中,在解碼圖片之后,也需要把它添加到內(nèi)存緩存中:class
BitmapWorkerTask
extends
AsyncTask<Integer,
Void,
Bitmap>
{
...
//
Decode
image
in
background.
@Override
protected
Bitmap
doInBackground(Integer...
params)
{
final
Bitmap
bitmap
=
decodeSampledBitmapFromResource(
getResources(),
params[0],
100,
100));
addBitmapToMemoryCache(String.valueOf(params[0]),
bitmap);
return
bitmap;
}
...
}使用磁盤緩存雖然內(nèi)存緩存在快速訪問最近使用的圖片時是很有用的,但是你無法保證你所需要的圖片就在緩存中,類似GridView這樣展示大量數(shù)據(jù)的組件可以很輕易地就占滿內(nèi)存緩存。你的App也可能被類似電話這樣的任務(wù)打斷,當(dāng)App被切換到后臺后也可能被殺死,內(nèi)存緩存也可能被銷毀,一旦用戶回到之前的界面,你的App依然要重新處理每個圖片。磁盤緩存可以用來輔助存儲處理過的圖片,當(dāng)內(nèi)存緩存中圖片不可用時,可以從磁盤緩存中查找,從而減少加載次數(shù)。當(dāng)然,從磁盤讀取圖片要比從內(nèi)存讀取慢并且讀取時間是不可預(yù)期的,因此需要使用后臺線程來讀取。說明:ContentProvider可能是一個合適的存儲頻繁訪問的圖片的地方,比如在ImageGallery應(yīng)用中。這里的示例代碼是從Android源代碼中剝離出來的DiskLruCache,以下是更新后的實例代碼,在內(nèi)存緩存的基礎(chǔ)上增加了磁盤緩存:private
DiskLruCache
mDiskLruCache;
private
final
Object
mDiskCacheLock
=
new
Object();
private
boolean
mDiskCacheStarting
=
true;
private
static
final
int
DISK_CACHE_SIZE
=
1024
*
1024
*
10;
//
10MB
private
static
final
String
DISK_CACHE_SUBDIR
=
"thumbnails";
@Override
protected
void
onCreate(Bundle
savedInstanceState)
{
...
//
Initialize
memory
cache
...
//
Initialize
disk
cache
on
background
thread
File
cacheDir
=
getDiskCacheDir(this,
DISK_CACHE_SUBDIR);
new
InitDiskCacheTask().execute(cacheDir);
...
}
class
InitDiskCacheTask
extends
AsyncTask<File,
Void,
Void>
{
@Override
protected
Void
doInBackground(File...
params)
{
synchronized
(mDiskCacheLock)
{
File
cacheDir
=
params[0];
mDiskLruCache
=
DiskLruCache.open(cacheDir,
DISK_CACHE_SIZE);
mDiskCacheStarting
=
false;
//
Finished
initialization
mDiskCacheLock.notifyAll();
//
Wake
any
waiting
threads
}
return
null;
}
}
class
BitmapWorkerTask
extends
AsyncTask<Integer,
Void,
Bitmap>
{
...
//
Decode
image
in
background.
@Override
protected
Bitmap
doInBackground(Integer...
params)
{
final
String
imageKey
=
String.valueOf(params[0]);
//
Check
disk
cache
in
background
thread
Bitmap
bitmap
=
getBitmapFromDiskCache(imageKey);
if
(bitmap
==
null)
{
//
Not
found
in
disk
cache
//
Process
as
normal
final
Bitmap
bitmap
=
decodeSampledBitmapFromResource(
getResources(),
params[0],
100,
100));
}
//
Add
final
bitmap
to
caches
addBitmapToCache(imageKey,
bitmap);
return
bitmap;
}
...
}
public
void
addBitmapToCache(String
key,
Bitmap
bitmap)
{
//
Add
to
memory
cache
as
before
if
(getBitmapFromMemCache(key)
==
null)
{
mMemoryCache.put(key,
bitmap);
}
//
Also
add
to
disk
cache
synchronized
(mDiskCacheLock)
{
if
(mDiskLruCache
!=
null
&&
mDiskLruCache.get(key)
==
null)
{
mDiskLruCache.put(key,
bitmap);
}
}
}
public
Bitmap
getBitmapFromDiskCache(String
key)
{
synchronized
(mDiskCacheLock)
{
//
Wait
while
disk
cache
is
started
from
background
thread
while
(mDiskCacheStarting)
{
try
{
mDiskCacheLock.wait();
}
catch
(InterruptedException
e)
{}
}
if
(mDiskLruCache
!=
null)
{
return
mDiskLruCache.get(key);
}
}
return
nul
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 幼兒園防樓道踩踏預(yù)案(3篇)
- 二零二五年度水產(chǎn)商品交易市場建設(shè)合同2篇
- 自動投球機(jī)課程設(shè)計
- 軟件課程設(shè)計
- 沖壓廠事故應(yīng)急處理預(yù)案模版(2篇)
- 2025年擔(dān)當(dāng)負(fù)責(zé)爭作為守規(guī)矩心得體會樣本(3篇)
- 中學(xué)檔案人員崗位制度范文(2篇)
- 烘焙專欄課程設(shè)計
- 二零二五年度按摩技師在線咨詢服務(wù)承包合同3篇
- 課題申報書:大學(xué)生學(xué)習(xí)特點與學(xué)習(xí)評價研究
- 近年無發(fā)生的訴訟和仲裁情況承諾書
- 變配電運維知識試題含答案
- 2024年江蘇經(jīng)貿(mào)職業(yè)技術(shù)學(xué)院單招職業(yè)適應(yīng)性測試題庫含答案
- 2022年人教版六年級科學(xué)(上冊)期末題及答案
- 廣告宣傳物料投標(biāo)方案(技術(shù)方案)
- 集合復(fù)習(xí)-章課件
- MOOC 電磁場與電磁波理論-南京郵電大學(xué) 中國大學(xué)慕課答案
- A類《職業(yè)能力傾向測驗》上海市青浦區(qū)2024年事業(yè)單位考試統(tǒng)考試題含解析
- 角的概念推廣(說課課件)
- 2023-2024學(xué)年北京市西城區(qū)高二(上)期末物理試卷(含解析)
- (高清版)DZT 0211-2020 礦產(chǎn)地質(zhì)勘查規(guī)范 重晶石、毒重石、螢石、硼
評論
0/150
提交評論