Launcher3之新安装应用加载过程分析

引言

对于Android手机用户来说,每天接触着各式各样的手机应用,应用的安装、更新和卸载操作并不陌生,更不用说看这篇文章的开发者了。那么,当一个新应用安装完成以后,launcher中需要做哪些事情,来完成向用户提供应用图标入口的功能呢?

该篇我就跟大家来探讨下,新应用安装后,launcher中的加载过程。

Workspace新应用加载过程分析

1、外部交互接口

应用安装的实现并不是launcher完成的,而是系统PackageManagerService完成的,但是launcher会向系统注册回调接口,当完成应用安装后,launcher会收到接口回调,进而处理后续事宜。

先来看下相关接口和实现(为了避免干扰,这边省略了其他接口):

public class LauncherAppsCompatVL extends LauncherAppsCompat {

    protected final LauncherApps mLauncherApps;
    protected final Context mContext;

    @Override
    public void addOnAppsChangedCallback(LauncherAppsCompat.OnAppsChangedCallbackCompat callback) {
        WrappedCallback wrappedCallback = new WrappedCallback(callback);
		...
        mLauncherApps.registerCallback(wrappedCallback);//注册
    }
	
	//接口实现
    private static class WrappedCallback extends LauncherApps.Callback {
        private final LauncherAppsCompat.OnAppsChangedCallbackCompat mCallback;

        public WrappedCallback(LauncherAppsCompat.OnAppsChangedCallbackCompat callback) {
            mCallback = callback;
        }

        @Override
        public void onPackageAdded(String packageName, UserHandle user) {
            mCallback.onPackageAdded(packageName, user);
        }
	}
}

LauncherApps是SDK开放给launcher使用的接口类,launcher实现了LauncherApps.Callback接口,然后通过registerCallback方法注册监听,当发生应用改变时,就可以收到回调,进而进行相应处理。
在新应用安装完成后,WrappedCallback实现类的onPackageAdded方法会被回调,再交给OnAppsChangedCallbackCompat接口实现处理。

2、内部回调实现

接着看看launcher中OnAppsChangedCallbackCompat的实现到底来自何方,代码如下:

public class LauncherModel extends BroadcastReceiver
        implements LauncherAppsCompat.OnAppsChangedCallbackCompat {
	...
	
    @Override
    public void onPackageAdded(String packageName, UserHandle user) {
        int op = PackageUpdatedTask.OP_ADD;
        enqueueModelUpdateTask(new PackageUpdatedTask(op, user, packageName));
    }
	
	...
}

public class LauncherAppState {

    private LauncherAppState(Context context) {
		...
	    LauncherAppsCompat.getInstance(mContext).addOnAppsChangedCallback(mModel);
		...
	}
}

原来LauncherModel中实现了OnAppsChangedCallbackCompat接口,并且在LauncherAppState构造函数中完成了注册监听,那么,我们就从LauncherModel中的onPackageAdded接口实现继续追踪吧。

onPackageAdded中唯一调用的方法enqueueModelUpdateTask,看下它的实现:

    public void enqueueModelUpdateTask(ModelUpdateTask task) {
        task.init(mApp, this, sBgDataModel, mBgAllAppsList, mUiExecutor);
        runOnWorkerThread(task);
    }

就两行代码,主要做的事情就是,保证任务在工作线程执行,具体完成任务是PackageUpdatedTask。

3、PackageUpdatedTask类

看下PackageUpdatedTask源码中的注释:

/**
 * Handles updates due to changes in package manager (app installed/updated/removed)
 * or when a user availability changes.
 */
public class PackageUpdatedTask extends BaseModelUpdateTask {

从注释可以看出,PackageUpdatedTask类处理了应用安装、更新和卸载等过程,我们这里只对新应用安装做下分析,其他过程分析类似。

先来看下PackageUpdatedTask的类继承关系:
在这里插入图片描述

下面看下OP_ADD,也就是新应用安装时,代码的真正实现:

public class PackageUpdatedTask extends BaseModelUpdateTask {
    @Override
    public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList appsList) {
		...
		
        final String[] packages = mPackages;
        final int N = packages.length;
        FlagOp flagOp = FlagOp.NO_OP;
		...
        switch (mOp) {
            case OP_ADD: {
                for (int i = 0; i < N; i++) {
					...
                    iconCache.updateIconsForPkg(packages[i], mUser);
					...
                    appsList.addPackage(context, packages[i], mUser);
					...

                }
                flagOp = FlagOp.removeFlag(ShortcutInfo.FLAG_DISABLED_NOT_AVAILABLE);
                break;
            }
		}
		
		final ArrayList<AppInfo> addedOrModified = new ArrayList<>();
        addedOrModified.addAll(appsList.added);
        appsList.added.clear();
        addedOrModified.addAll(appsList.modified);
        appsList.modified.clear();

        ...
        if (!addedOrModified.isEmpty()) {
            scheduleCallbackTask(new CallbackTask() {
                @Override
                public void execute(Callbacks callbacks) {
                    callbacks.bindAppsAddedOrUpdated(addedOrModified);
                }
            });
            ...
        }
	}
]

execute方法中,主要做了两件事:

  • a. 通过appsList.addPackage方法将新应用信息缓存到AllAppsList
    public void addPackage(Context context, String packageName, UserHandle user) {
        final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context);
        final List<LauncherActivityInfo> matches = launcherApps.getActivityList(packageName,
                user);

        for (LauncherActivityInfo info : matches) {
            add(context,new AppInfo(context, info, user), info,false);
        }
    }
	
    public void add(Context context,AppInfo info, LauncherActivityInfo activityInfo,boolean isUpdate) {
		...

        data.add(info);
        boolean success = added.add(info);
		...
    }
  • b. 通过bindAppsAddedOrUpdated方法回调launcher,进行界面更新的处理。
    public final void scheduleCallbackTask(final CallbackTask task) {
        final Callbacks callbacks = mModel.getCallback();
        mUiExecutor.execute(() -> {
            Callbacks cb = mModel.getCallback();
            if (callbacks == cb && cb != null) {
                task.execute(callbacks);
            }
        });
    }

scheduleCallbackTask方法有两个作用:1.切换到UI线程去处理bindAppsAddedOrUpdated回调;2. 通过mModel.getCallback向execute传参

最后看看bindAppsAddedOrUpdated在Launcher中的实现:

public class Launcher extends BaseDraggingActivity implements LauncherExterns,
        LauncherModel.Callbacks, LauncherProviderChangeListener, UserEventDelegate{
    @Override
    public void bindAppsAddedOrUpdated(ArrayList<AppInfo> apps) {
        mAppsView.getAppsStore().addOrUpdateApps(apps);

        if (mLauncherCallbacks != null) {
            mLauncherCallbacks.bindAppsAddedOrUpdated(apps);
        }
    }		
}

最终会通过AllAppsStore的addOrUpdateApps方法去通知AllApps界面刷新。

小结

以上就是AOSP launcher3中新应用的加载过程,如果新应用安装时,有自动添加图标到桌面的需求,或者实现的是单层launcher,没有AllApps的场景,还需要向Workspace添加图标和小部件。

猜你喜欢

转载自blog.csdn.net/qinhai1989/article/details/86523220
今日推荐