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對象就可以完成了。


2.2加載壁紙背景

2.2.1策略模式處理不同壁紙類型點擊事件

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加載圖片


根據流程圖再看一下對象變化,這邊還是挺容易被繞暈的。BitmapRegionDecoder和 BimtapTexture到底在幹啥?然後我看到這個邏輯



方法6 採用模板模式

模板模式和策略模式基本上可以互用,主要區別是繼承和委託。比如WallpaperTileInfo把點擊事件委託給各個子類都實現。而這邊BimtmapSource替所有子類處理了loadInBackground()邏輯。


再根據流程圖,看一下對象變化


這時候我已經完全糊塗了,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 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刷新邏輯。





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章