Android的Drawable缓存机制源码分析
来源:互联网 发布:宾得wifi软件 编辑:程序博客网 时间:2024/04/30 09:05
Android获取Drawable的方式一般是Resources.getDrawable(int),Framework会返回给你一个顶层抽象的Drawable对象。而在Framework中,系统使用了享元的方式来节省内存。为了证明这一点,我们来写一个小demo:
我们在我们的Android项目中引入一个简单的图片test.png。由于我们只是为了享元的结论,我们定义一个简单的Activity,并复写它的onCreate方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
List<bitmap> list =
new
ArrayList<bitmap>();
Bitmap bitmap =
null
;
@Override
protected
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
for
(
int
i =
0
; i <
10
; i ++) {
bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.test);
list.add(bitmap);
}
ImageView iv =
new
ImageView(
this
);
iv.setImageBitmap(bitmap);
this
.setContentView(iv);
}</bitmap></bitmap>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
List<drawable> list =
new
ArrayList<drawable>();
Drawable bitmap =
null
;
@Override
protected
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
for
(
int
i =
0
; i <
10
; i ++) {
bitmap =
this
.getResources().getDrawable(R.drawable.test);
list.add(bitmap);
}
ImageView iv =
new
ImageView(
this
);
iv.setImageDrawable(bitmap);
this
.setContentView(iv);
}</drawable></drawable>
我们再打印内存,发现内存已经降到了:7844K,这部分数据基本就证明了我们的结论。那么有没有可能是Resources缓存了相同的drawable。当然不是,你可以写一个简单代码测试一下:
1
2
3
Drawable d1 =
this
.getResources().getDrawable(R.drawable.test);
Drawable d2 =
this
.getResources().getDrawable(R.drawable.test);
System.out.println(
">>>d1 == d2 ? = "
+(d1 == d2));
1
2
3
4
5
6
7
Resources.java
Drawable loadDrawable(TypedValue value,
int
id)
throws
NotFoundException {
...
Drawable dr = getCachedDrawable(isColorDrawable ? mColorDrawableCache : mDrawableCache, key);
...
}
从代码可以看出,系统对Drawable主要分成两大类,实际上还有一类熟悉预加载类的Drawable,不过不作为我们讨论的重点,由于我们load的并不属于color类型的Drawable,因此我们对应的享元池由mDrawableCache对象实现。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Resources.java
private
Drawable getCachedDrawable(
LongSparseArray<weakreference<constantstate>> drawableCache,
long
key) {
synchronized
(mAccessLock) {
WeakReference<drawable.constantstate> wr = drawableCache.get(key);
if
(wr !=
null
) {
// we have the key
Drawable.ConstantState entry = wr.get();
if
(entry !=
null
) {
//Log.i(TAG, "Returning cached drawable @ #" +
// Integer.toHexString(((Integer)key).intValue())
// + " in " + this + ": " + entry);
return
entry.newDrawable(
this
);
}
else
{
// our entry has been purged
drawableCache.delete(key);
}
}
}
return
null
;
}</drawable.constantstate></weakreference<constantstate>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public
static
abstract
class
ConstantState {
/**
* Create a new drawable without supplying resources the caller
* is running in. Note that using this means the density-dependent
* drawables (like bitmaps) will not be able to update their target
* density correctly. One should use {@link #newDrawable(Resources)}
* instead to provide a resource.
*/
public
abstract
Drawable newDrawable();
/**
* Create a new Drawable instance from its constant state. This
* must be implemented for drawables that change based on the target
* density of their caller (that is depending on whether it is
* in compatibility mode).
*/
public
Drawable newDrawable(Resources res) {
return
newDrawable();
}
/**
* Return a bit mask of configuration changes that will impact
* this drawable (and thus require completely reloading it).
*/
public
abstract
int
getChangingConfigurations();
/**
* @hide
*/
public
Bitmap getBitmap() {
return
null
;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
final
static
class
BitmapState
extends
ConstantState {
Bitmap mBitmap;
int
mChangingConfigurations;
int
mGravity = Gravity.FILL;
Paint mPaint =
new
Paint(DEFAULT_PAINT_FLAGS);
Shader.TileMode mTileModeX =
null
;
Shader.TileMode mTileModeY =
null
;
int
mTargetDensity = DisplayMetrics.DENSITY_DEFAULT;
boolean
mRebuildShader;
boolean
mAutoMirrored;
BitmapState(Bitmap bitmap) {
mBitmap = bitmap;
}
BitmapState(BitmapState bitmapState) {
this
(bitmapState.mBitmap);
mChangingConfigurations = bitmapState.mChangingConfigurations;
mGravity = bitmapState.mGravity;
mTileModeX = bitmapState.mTileModeX;
mTileModeY = bitmapState.mTileModeY;
mTargetDensity = bitmapState.mTargetDensity;
mPaint =
new
Paint(bitmapState.mPaint);
mRebuildShader = bitmapState.mRebuildShader;
mAutoMirrored = bitmapState.mAutoMirrored;
}
@Override
public
Bitmap getBitmap() {
return
mBitmap;
}
@Override
public
Drawable newDrawable() {
return
new
BitmapDrawable(
this
,
null
);
}
@Override
public
Drawable newDrawable(Resources res) {
return
new
BitmapDrawable(
this
, res);
}
@Override
public
int
getChangingConfigurations() {
return
mChangingConfigurations;
}
}
跟到这,相信大家都跟我一样了解了Bitmap是如何从cache中取出,我们接下来看一下ConstantState是如何存入的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
Resources.loadDrawable()
{
...
InputStream is = mAssets.openNonAsset(
value.assetCookie, file, AssetManager.ACCESS_STREAMING);
// System.out.println("Opened file " + file + ": " + is);
// MIUI MOD:
// dr = Drawable.createFromResourceStream(this, value, is, file, null);
dr = createFromResourceStream(
this
, value, is, file, id);
is.close();
...
if
(dr !=
null
) {
dr.setChangingConfigurations(value.changingConfigurations);
cs = dr.getConstantState();
if
(cs !=
null
) {
if
(mPreloading) {
final
int
changingConfigs = cs.getChangingConfigurations();
if
(isColorDrawable) {
if
(verifyPreloadConfig(changingConfigs,
0
, value.resourceId,
"drawable"
)) {
sPreloadedColorDrawables.put(key, cs);
}
}
else
{
if
(verifyPreloadConfig(changingConfigs,
LAYOUT_DIR_CONFIG, value.resourceId,
"drawable"
)) {
if
((changingConfigs&LAYOUT_DIR_CONFIG) ==
0
) {
// If this resource does not vary based on layout direction,
// we can put it in all of the preload maps.
sPreloadedDrawables[
0
].put(key, cs);
sPreloadedDrawables[
1
].put(key, cs);
}
else
{
// Otherwise, only in the layout dir we loaded it for.
final
LongSparseArray<drawable.constantstate> preloads
= sPreloadedDrawables[mConfiguration.getLayoutDirection()];
preloads.put(key, cs);
}
}
}
}
else
{
synchronized
(mAccessLock) {
//Log.i(TAG, "Saving cached drawable @ #" +
// Integer.toHexString(key.intValue())
// + " in " + this + ": " + cs);
if
(isColorDrawable) {
mColorDrawableCache.put(key,
new
WeakReference<drawable.constantstate>(cs));
}
else
{
mDrawableCache.put(key,
new
WeakReference<drawable.constantstate>(cs));
}
}
}
}
...
}</drawable.constantstate></drawable.constantstate></drawable.constantstate>
可以看出,当你新生成一个Drawable的时候,就会将Drawable的ConstantState从Drawable中取出,然后放入你Cache池中。
原文地址: http://www.2cto.com/kf/201501/373804.html
0 0
- Android的Drawable缓存机制源码分析
- Android的Drawable缓存机制源码分析
- Android:关于Drawable的缓存机制应该了解的知识
- Android drawable资源源码分析
- ListView源码分析缓存机制
- Android 图片的缓存机制分析
- 【oschina android源码分析】缓存的设计
- Android的消息处理机制源码分析
- 结合源码分析android的消息机制
- Android 消息机制的源码分析
- Android Loader的机制以及源码分析
- 源码分析android的事件分发机制
- Android的消息机制源码分析
- drawable源码分析
- android缓存的机制
- (七)android的绘图机制&&Drawable
- 分析Android-Universal-Image-Loader的缓存处理机制
- 分析Hibernate的缓存机制
- 读华为副总裁徐家骏总结的个人心得
- j2ee 开发应用服务器的 404 错误跳转的设置 web.xml
- Android bitmap占用内存解析
- html textarea 自动在底部滚动的实现方法------终于搞定你
- Linux 下安装配置JDK
- Android的Drawable缓存机制源码分析
- Yii2 源码手记
- git in action
- What is EJB
- [Vala+Gtk3.0]Fixed固定布局基本模板
- 不同浏览器获取DOM元素的各种高度
- linux下文本读写:面向二进制字节流方式
- 多下标哈希表——Fast Exact Search in Hamming Space with Multi-Index Hashing
- Codeforces Round #304 (Div. 2) 546D Soldier and Number Game 质因子个数