Launcher3 壁纸流程分析

时间:2021-10-28 09:19:56

Launcher3 壁纸分析

1. WallpaperPickerActivity结构

1.1 父类WallpaperCropActivity

WallpaperPickerActivity是WallpaperCropActivity的派生类。当前者执行onCreate()时,它会调用父类的onCreate(),在父类执行onCreate()时又会调用init(),而WallpaperPickerActivity复写了init()方法,故又回到自己的init()中。 
Launcher3 壁纸流程分析

1.2 布局文件wallpaper_picker.xml

在init()方法中,对布局文件wallpaper_picker.xml中的许多控件进行了初始化。以下是wallpaper_picker.xml的部分代码。

<com.android.launcher3.WallpaperRootView  android:id="@+id/wallpaper_root">
    <com.android.launcher3.CropView  android:id="@+id/cropView"/>
    <ProgressBar  android:id="@+id/loading"/>
    <LinearLayout  android:id="@+id/wallpaper_strip">
        <View  android:layout_width="match_parent" android:layout_height="2dp" android:background="@drawable/tile_shadow_top" />
        <HorizontalScrollView  android:id="@+id/wallpaper_scroll_container">
            <LinearLayout android:id="@+id/master_wallpaper_list">
                <LinearLayout android:id="@+id/wallpaper_list"/>
                <LinearLayout android:id="@+id/live_wallpaper_list"/>
                <LinearLayout android:id="@+id/third_party_wallpaper_list"/>
            </LinearLayout>
        </HorizontalScrollView>
        <View  android:layout_width="match_parent" android:layout_height="2dp" android:background="@drawable/tile_shadow_bottom" />
    </LinearLayout>
</com.android.launcher3.WallpaperRootView>
  • 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
  • 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

com.Android.launcher3.CropView是一个自定义View,用于显示壁纸大图。 
HorizontalScrollView下面有一个LinearLayout,master_wallpaper_list,它又有两个子Layout,wallpaper_list和live_wallpaper_list,third_party_wallpaper_list节点已经被移除。

布局中各节点的位置如下图所示:

Launcher3 壁纸流程分析

在图 2中,壁纸大图对应的是CropView,常规壁纸对应wallpaper_list的LinearLayout,而动态壁纸则是live_wallpaper_list。

2. 初始化流程

2.1 加载壁纸列表

在init()方法中,系统壁纸和用户从图库中选择过的壁纸会被加载到视图中,下列三小节会描述这三种壁纸的加载过程。

2.1.1 系统壁纸

在init()中,先从findBundledWallpapers()中获取一个WallpaperTileInfo类型的ArrayList。在findBundledWallpapers()中,需要从资源中获取壁纸。根据/WallpaperPicker/res/values-nodpi/wallpapers.xml中的wallpapers数组,把壁纸资源生成WallpaperTileInfo对象加入到ArrayList中。

2.1.2 图库壁纸

用户如果在图库中选择过壁纸,那么在init过程中,我们还要读取那些用户选择的壁纸,并把它们加入到壁纸图块列表中。

mSavedImages是一个SavedWallpaperImages对象,该类时BaseAdapter的派生类,在loadThumbnailsAndImageIdList()方法中,把壁纸从数据库中加载到Adapter中,然后再通过。populateWallpapersFromAdapter()方法把图片列表加入到父布局中。

mSavedImages = new SavedWallpaperImages(this);
mSavedImages.loadThumbnailsAndImageIdList();
populateWallpapersFromAdapter(mWallpapersView, mSavedImages, true);
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

2.1.3 动态壁纸

动态壁纸的加载方式与前两种壁纸稍有区别。因为加载动态壁纸所需要的时间更长,所以对LiveWallpaperListAdapter对象注册了DataSetObserver。在动态壁纸列表的数据加载完成时会调用DataSetObserver的onChanged()回调方法,把壁纸图块加入LinearLayout中。

2.2 加载图库壁纸按键

在上述几种类型的壁纸加载完成后,列表中还要加载一个从图库中选择壁纸的按键,这个按键是动态加入到LinearLayout中的,所以在wallpaper_picker不会出现。 
该按键的初始化代码如下:

LinearLayout masterWallpaperList = (LinearLayout)findViewById(R.id.master_wallpaper_list);
FrameLayout pickImageTile = (FrameLayout) getLayoutInflater().
inflate(R.layout.wallpaper_picker_image_picker_item, masterWallpaperList, false);

mPickImageTile = pickImageTile;

setWallpaperItemPaddingToZero(pickImageTile);
masterWallpaperList.addView(pickImageTile, 0);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

可以看到,该按键是以一个FrameLayout的形式加入到壁纸列表中的,与populateWallpapersFromAdapter()方法中的形式相同。 
该按键是一个CheckableFrameLayout,顾名思义,这种Layout是可以被点击。它包含了一张图片和一个TextView,具体的布局文件是WallpaperPicker/res/layout/wallpaper_picker_image_picker_item.xml。上面的代码是把该布局inflate进来作为一个按键并加入到壁纸列表中。

2.3 Actionbar的初始化和响应

在壁纸的初始化过程中,ActionBar的样式被改变了。通过调用actionBar.setCustomView(R.layout.actionbar_set_wallpaper),可以把自定义的布局设置为ActionBar的视图。该布局中是一个AlphaDisableableButton,它重写了View.setEnabled()方法。 
ActionBar的点击事件是用于确认当前选择壁纸的。在点击ActionBar后,获取当前选定的图块Info,尝试将其设为壁纸,并finish当前Activity,把结果传回上一个Activity。

2.4 点击事件

在描述点击事件之前,首先看看一个抽象类,WallpaperTileInfo。这个类中有一个View,一个Drawable以及onClick(),onSave()等方法。WallpaperTileInfo有几个派生类,如下图所示: 
Launcher3 壁纸流程分析

这些派生类在加载不同类别的壁纸时会有不同的实现。比如PickImageInfo,它代表上文中说到的加载图库壁纸按键的类型。它的onClick()方法中的实现是发一个Intent去打开DocumentsUI,挑选一张壁纸。其他派生类,如果是壁纸的话,onClick()方法中则会根据自己的壁纸信息,计算宽高和坐标,把缩略图对应的大图设为背景,这样用户就可以预览壁纸效果。 
在初始化过程中,有一个专门用于壁纸列表的监听器,mThumbnailOnClickListener。它的onClick()方法实现中有如下语句:

WallpaperTileInfo info = (WallpaperTileInfo) v.getTag();
if (info == null) {
    return;
}
if (info.isSelectable() && v.getVisibility() == View.VISIBLE) {
    selectTile(v);
}
info.onClick(WallpaperPickerActivity.this);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

在前文中提到的populateWallpapersFromAdapter()方法中,所有壁纸图块,包括mPickImageTile,都将此listener作为监听器。这样当他们被点击时,会拥有自己的行为