android WallpaperPicker7.0源码分析

1简介

Wallpaper里面有两个Activity:WallpaperCropActivity(进入界面的步骤:打开图库,点击设置为壁纸),WallpaperPickerActivity(进入界面的步骤:(1)长按桌面空白处,点击壁纸;(2)进入设置,点击显示,点击壁纸);WallpaperCropActivity其实是简易版的WallpaperPickerActivity。

这部分代码实现功能:

(1)生成缩略图View列表

(2)利用 openGL异步加载壁纸

(3)获取壁纸异步设置壁纸

2代码解析

2.1 适配器模式生成缩略图View

 2.1.1 Google提供了丰富的壁纸来源:

壁纸信息对象 壁纸来源 获取壁纸对象集合方法
DefaultWallpaperInfo WallpaperManager getDefaultWallpaper()
ResourceWallpaperInfo mtkPartner
Resources wallpapers.xml 
findBundledWallpapers()
getWallpaperArrayResourceId()
FileWallpaperInfo systemDir findBundledWallpapers()
SavedWallpaperTile saved_wallpaper_images.db loadThumbnailsAndImageIdList()
WallpaperInfo liveWallpaper new LiveWallpaperListAdapter(getContext())
ThirdPartyWallpaperTile ThirdPartyActivityEnter new ThirdPartyWallpaperPickerListAdapter(getContext())

2.1.2 加载缩略图view

利用上表中的数据集合生成Adapter对象,利用populateWallpapersFromAdapter()方法加载对应View上面。这边应该是逻辑太老了。其实用recycleView一个View对象就可以完成了。

android WallpaperPicker7.0源码分析_第1张图片

2.2加载壁纸背景

2.2.1策略模式处理不同壁纸类型点击事件

android WallpaperPicker7.0源码分析_第2张图片

2.2.2壁纸准备

这里逻辑比较简单。这个里面又使用与策略模式类似的方法模板模式。
(1         )WallpaperTileInfo各个子类处理点击事件
(2         )生成对应XXXBitmapSource对象
(3~5    )生成LoadRequest对象,利用handler发消息。
(6~8    )处理XXXBitmapSource对象里面的Bitmap,GLUtils判断该Bitmap是否能被加载
(9~12  )生成BitmapRegionTileSource对象,将bitmap封装成BitmapTexture对象
(13~14)openGL加载图片

android WallpaperPicker7.0源码分析_第3张图片

根据流程图再看一下对象变化,这边还是挺容易被绕晕的。BitmapRegionDecoder和 BimtapTexture到底在干啥?然后我看到这个逻辑



方法6 采用模板模式

模板模式和策略模式基本上可以互用,主要区别是继承和委托。比如WallpaperTileInfo把点击事件委托给各个子类都实现。而这边BimtmapSource替所有子类处理了loadInBackground()逻辑。

android WallpaperPicker7.0源码分析_第4张图片

再根据流程图,看一下对象变化

android WallpaperPicker7.0源码分析_第5张图片

这时候我已经完全糊涂了,BitmRegionDecoder和BitmapTexture到底是干啥的?直到看到这个逻辑。

BitmapRegionDecoder虽然是要加载的大图。但是我屏幕就这么大,为啥要显示屏幕尺寸以外的图片,这个不是浪费性能么?

我就发现这个牛逼的逻辑。手势触发移动。我得到图片的options,我根据区域从BitmapRegionDecoder去获得BitmapTexture mPreview 纹理。只加载屏幕显示的区域。

public Bitmap getTile(int level, int x, int y, Bitmap bitmap) {
        int tileSize = getTileSize();
        int t = tileSize << level;
        mWantRegion.set(x, y, x + t, y + t);

        if (bitmap == null) {
            bitmap = Bitmap.createBitmap(tileSize, tileSize, Bitmap.Config.ARGB_8888);
        }

        mOptions.inSampleSize = (1 << level);
        mOptions.inBitmap = bitmap;

        try {
            bitmap = mDecoder.decodeRegion(mWantRegion, mOptions);
        } finally {
            if (mOptions.inBitmap != bitmap && mOptions.inBitmap != null) {
                mOptions.inBitmap = null;
            }
        }

        if (bitmap == null) {
            Log.w("BitmapRegionTileSource", "fail in decoding region");
        }
        return bitmap;
    }


2.3 openGL加载图片

Google为了保证低运行内存,低配置的手机升级版本还拥有较好的用户体验做了不少努力。
首先使用BitmapRegionDecoder加载宽屏壁纸,最大支持2048*2048像素的图片。图片加载很吃内存,很容易oom。
Google采取3个步骤。
(1)独立进程,WallpaperPicker是运行在com.android.launcher3:wallpaper_chooser中。
(2)openGL加载图片,openGL是独立开辟一块内存加载图片,性能优化极高。
(3)界面启动,不通过读流加载壁纸,而是通过配置android:windowShowWallpaper属性,达到加载壁纸的效果,从而降低启动占用的内存。
(4)上面的神逻辑

android WallpaperPicker7.0源码分析_第6张图片

这边获得值都采用了同步锁,但是我不知道该怎么画图,而且这边逻辑绕的我有点晕,但是大概是因为如果图片很大,处理纹理是耗时操作,所以必须加锁保证能取到值。

这边我自己也没理清楚,所以我觉得我也写不出来什么。所以放个Android openGL的demo连接。使用方法很简单。

(       7       )初始化Google封装的GLSurfaceView

(       8       )设置渲染器 TiledImageRenderer

(       9        )设置加载模式RENDERMODE_WHEN_DIRTY,只有在创建和调用requestRender()时才会刷新。

(14 ~ 15)通知刷新时,TiledImageRenderer首次会回调onSurfaceCreated,onSurfaceChanged,onDrawFrame。之后如果尺寸不改变,只会触发

 onDrawFrame回调。

2.4 设置壁纸

设置壁纸与处理壁纸点击事件的逻辑是同一个逻辑。这里Google采用AsyncTask BitmapCropTask处理异步加载和UI刷新逻辑。

android WallpaperPicker7.0源码分析_第7张图片




你可能感兴趣的:(Android,SourceCode)