安装的应用,应用图标会在主页未满的情况下直接跳转到第二页显示
Launcher3 是一个应用app ,主要作用是 管理手机桌面的图标小部件的显示等相关管理的功能
所以本文问题的关键就在于 处理图标显示的处理逻辑上
@Override
protected void onCreate(Bundle savedInstanceState) {
***省略N行代码***
// 初始化里做了很多界面以及管理器的初始化,这里三行才是本文问题的关键
// 主要是LauncherAppState 和 mModel(LauncherModel)
// 这两个文件是和应用管理相关的
LauncherAppState app = LauncherAppState.getInstance(this);
mOldConfig = new Configuration(getResources().getConfiguration());
mModel = app.getModel();
***省略N行代码***
}
然后我们可以简单看下
// 可以看到LauncherAppState是个单例,MainThreadInitializedObject是个壳
// 目的是限定单例对象定义在主线程上
public static final MainThreadInitializedObject<LauncherAppState> INSTANCE =
new MainThreadInitializedObject<>(LauncherAppState::new);
public static LauncherAppState getInstanceNoCreate() {
return INSTANCE.getNoCreate();
}
***省略N行代码***
public LauncherAppState(Context context, @Nullable String iconCacheFileName) {
mContext = context;
mInvariantDeviceProfile = InvariantDeviceProfile.INSTANCE.get(context);
mIconProvider = new IconProvider(context, Themes.isThemedIconEnabled(context));
mIconCache = new IconCache(mContext, mInvariantDeviceProfile,
iconCacheFileName, mIconProvider);
mWidgetCache = new DatabaseWidgetPreviewLoader(mContext, mIconCache);
// 这里可以看到,在LauncherAppState构造里,初始化了LauncherModel实例
// 将LauncherModel实例绑定到了LauncherAppState单例上,suoyi
mModel = new LauncherModel(context, this, mIconCache, new AppFilter(mContext));
mOnTerminateCallback.add(mIconCache::close);
}
接下来,看看
/**
- Maintains in-memory state of the Launcher. It is expected that there should be only one
- LauncherModel object held in a static. Also provide APIs for updating the database state
- for the Launcher.
*/
翻译一下:保持启动器的内存状态。预计静态中应该只有一个LauncherModel对象。还提供用于更新启动器数据库状态的API。
其实这就是相当于Launcher3 的一个数据管理器
看代码有如下相关代码:
/**
* Adds the provided items to the workspace.
*/
public void addAndBindAddedWorkspaceItems(List<Pair<ItemInfo, Object>> itemList) {
addAndBindAddedWorkspaceItems(itemList, true, false);
}
/**
* Adds the provided items to the workspace.
*/
public void addAndBindAddedWorkspaceItems(List<Pair<ItemInfo, Object>> itemList,
boolean animated, boolean ignoreLoaded) {
for (Callbacks cb : getCallbacks()) {
cb.preAddApps();
}
// 看注释已经说的很直白了,添加项目到工作空间(翻译一下:添加桌面元素到桌面上)
// 这里注意初始化了AddWorkspaceItemsTask这个类,后面我们进去看下
AddWorkspaceItemsTask awit = new AddWorkspaceItemsTask(itemList);
awit.setEnableAnimated(animated).setIgnoreLoaded(ignoreLoaded);
enqueueModelUpdateTask(awit);
}
接着看下AddWorkspaceItemsTask.java
@Override
public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList apps) {
if (mItemList.isEmpty()) {
return;
}
***省略N行代码***
InstallSessionHelper packageInstaller =
InstallSessionHelper.INSTANCE.get(app.getContext());
LauncherApps launcherApps = app.getContext().getSystemService(LauncherApps.class);
for (ItemInfo item : filteredItems) {
// Find appropriate space for the item.
// 这里核心的是 findSpaceForItem 这个方法
// 这个方法就是给要显示存放的桌面元素,寻找可以放置的screen(屏幕/页面)
int[] coords = findSpaceForItem(app, dataModel, workspaceScreens,
addedWorkspaceScreensFinal, item.spanX, item.spanY);
int screenId = coords[0];
***这里省略的逻辑主要是桌面元素的差分处理以及后面与获取的屏幕/页面数据绑定***
// log bitmap and label
FileLog.d(LOG, "Adding item info to workspace: " + itemInfo);
}
***省略N行代码***
}
/**
* Find a position on the screen for the given size or adds a new screen.
* @return screenId and the coordinates for the item in an int array of size 3.
*/
protected int[] findSpaceForItem( LauncherAppState app, BgDataModel dataModel,
IntArray workspaceScreens, IntArray addedWorkspaceScreensFinal, int spanX, int spanY) {
***省略N行代码***
int screenId = 0;
int[] cordinates = new int[2];
boolean found = false;
int screenCount = workspaceScreens.size();
// First check the preferred screen.
int preferredScreenIndex = workspaceScreens.isEmpty() ? 0 : 1;
if (preferredScreenIndex < screenCount) {
screenId = workspaceScreens.get(preferredScreenIndex);
found = findNextAvailableIconSpaceInScreen(
app, screenItems.get(screenId), cordinates, spanX, spanY);
}
if (!found) {
// Search on any of the screens starting from the first screen.
// 注意看:这里就是这个问题的核心,for循环里 screen 直接定义从1开始,那么不言而喻
for (int screen = 1; screen < screenCount; screen++) {
screenId = workspaceScreens.get(screen);
if (findNextAvailableIconSpaceInScreen(
app, screenItems.get(screenId), cordinates, spanX, spanY)) {
// We found a space for it
found = true;
break;
}
}
}
***省略N行代码***
}
所以要解决本文的问题:解决方案就是让for循环里screen从0开始寻找,问题即可解决
for (int screen = 1; screen < screenCount; screen++) {
修改为
for (int screen = 0; screen < screenCount; screen++) {