面试题答案
一键面试绘制缓存
- 场景:当View的内容相对固定,在每次重绘时变化不大,例如静态图表、固定布局的自定义背景等。
- 选择:使用
Canvas
的缓存机制。在Kotlin中,可以通过Canvas
的saveLayer
方法来创建一个离屏缓存。 - 实现:
override fun onDraw(canvas: Canvas) {
val saveCount = canvas.saveLayer(0f, 0f, width.toFloat(), height.toFloat(), null, Canvas.ALL_SAVE_FLAG)
// 执行复杂绘制操作
// 例如绘制一个复杂的图形
val path = Path()
path.moveTo(100f, 100f)
path.lineTo(200f, 100f)
path.lineTo(200f, 200f)
path.close()
canvas.drawPath(path, Paint())
canvas.restoreToCount(saveCount)
}
资源缓存
- 场景:当自定义View需要加载外部资源,如图片、字体等,且这些资源在不同绘制周期中重复使用时。例如,一个展示多个固定图片的自定义View。
- 选择:
- 图片资源:可以使用
LruCache
(在Android中)或者Cache
相关框架,将加载的图片缓存起来。 - 字体资源:将加载的字体对象进行缓存,避免重复从文件系统或资源中加载。
- 图片资源:可以使用
- 实现:
- 图片资源缓存(以Android的LruCache为例):
class ImageCache(private val maxSize: Int) {
private val cache = LruCache<String, Bitmap>(maxSize) { key, value ->
value.byteCount
}
fun getBitmap(key: String): Bitmap? {
return cache.get(key)
}
fun putBitmap(key: String, bitmap: Bitmap) {
cache.put(key, bitmap)
}
}
在自定义View中使用:
private val imageCache = ImageCache(10 * 1024 * 1024) // 10MB缓存
override fun onDraw(canvas: Canvas) {
val imageKey = "your_image_key"
var bitmap = imageCache.getBitmap(imageKey)
if (bitmap == null) {
// 加载图片
bitmap = BitmapFactory.decodeResource(resources, R.drawable.your_image)
imageCache.putBitmap(imageKey, bitmap)
}
canvas.drawBitmap(bitmap, 0f, 0f, Paint())
}
- **字体资源缓存**:
class FontCache {
private val fontCache = mutableMapOf<String, Typeface>()
fun getTypeface(fontPath: String): Typeface {
return fontCache.getOrPut(fontPath) {
Typeface.createFromAsset(context.assets, fontPath)
}
}
}
在自定义View中使用:
private val fontCache = FontCache()
override fun onDraw(canvas: Canvas) {
val fontPath = "fonts/your_font.ttf"
val typeface = fontCache.getTypeface(fontPath)
val paint = Paint()
paint.typeface = typeface
canvas.drawText("Hello, World!", 100f, 100f, paint)
}
综合策略
- 场景:对于复杂的自定义View,可能同时涉及绘制缓存和资源缓存。例如,一个包含动态数据图表和固定背景图片的自定义View。
- 选择:结合绘制缓存和资源缓存策略,优先使用资源缓存减少资源加载开销,再利用绘制缓存减少绘制开销。
- 实现:在
onDraw
方法中,先处理资源缓存相关逻辑,获取所需资源,然后再进行绘制缓存相关操作,如创建Canvas
离屏缓存进行复杂绘制。
override fun onDraw(canvas: Canvas) {
// 资源缓存逻辑,获取图片
val imageKey = "background_image_key"
var bitmap = imageCache.getBitmap(imageKey)
if (bitmap == null) {
bitmap = BitmapFactory.decodeResource(resources, R.drawable.background_image)
imageCache.putBitmap(imageKey, bitmap)
}
// 绘制缓存逻辑
val saveCount = canvas.saveLayer(0f, 0f, width.toFloat(), height.toFloat(), null, Canvas.ALL_SAVE_FLAG)
canvas.drawBitmap(bitmap, 0f, 0f, Paint())
// 绘制动态图表
// 例如绘制柱状图
// 逻辑代码
canvas.restoreToCount(saveCount)
}