Launcher3 安装App加载显示过程分析,开源新作

这篇具有很好参考价值的文章主要介绍了Launcher3 安装App加载显示过程分析,开源新作。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

/**

  • Called before the task is posted to initialize the internal state.

*/

void init(LauncherAppState app, LauncherModel model,

BgDataModel dataModel, AllAppsList allAppsList, Executor uiExecutor);

}

public abstract class BaseModelUpdateTask implements ModelUpdateTask {

PackageUpdatedTask 处理由于程序包管理器中的更改(应用程序安装、更新、删除)或用户可用性更改而引起的更新。

/**

  • Handles updates due to changes in package manager (app installed/updated/removed)

  • or when a user availability changes.

*/

public class PackageUpdatedTask extends BaseModelUpdateTask {

private static final boolean DEBUG = true;

private static final String TAG = “PackageUpdatedTask”;

public static final int OP_NONE = 0;

public static final int OP_ADD = 1;

public static final int OP_UPDATE = 2;

public static final int OP_REMOVE = 3; // uninstalled

public static final int OP_UNAVAILABLE = 4; // external media unmounted

public static final int OP_SUSPEND = 5; // package suspended

public static final int OP_UNSUSPEND = 6; // package unsuspended

public static final int OP_USER_AVAILABILITY_CHANGE = 7; // user available/unavailable

@Override

public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList appsList) {

final Context context = app.getContext();

final IconCache iconCache = app.getIconCache();

final String[] packages = mPackages;

final int N = packages.length;

FlagOp flagOp = FlagOp.NO_OP;

final HashSet packageSet = new HashSet<>(Arrays.asList(packages));

ItemInfoMatcher matcher = ItemInfoMatcher.ofPackages(packageSet, mUser);

switch (mOp) {

case OP_ADD: {

for (int i = 0; i < N; i++) {

if (DEBUG) Log.d(TAG, "mAllAppsList.addPackage " + packages[i]);

iconCache.updateIconsForPkg(packages[i], mUser);

if (FeatureFlags.LAUNCHER3_PROMISE_APPS_IN_ALL_APPS) {

appsList.removePackage(packages[i], Process.myUserHandle());

}

appsList.addPackage(context, packages[i], mUser);

// Automatically add homescreen icon for work profile apps for below O device.

if (!Utilities.ATLEAST_OREO && !Process.myUserHandle().equals(mUser)) {//del by mjf for receive package changed msg

SessionCommitReceiver.queueAppIconAddition(context, packages[i], mUser);

}

}

flagOp = FlagOp.removeFlag(ShortcutInfo.FLAG_DISABLED_NOT_AVAILABLE);

break;

}

final ArrayList addedOrModified = new ArrayList<>();

addedOrModified.addAll(appsList.added);

//add for load new install app on workspace start by lhw

if(FeatureFlags.DISABLE_ALL_APP){

ArrayList<Pair<ItemInfo, Object>> installQueue = new ArrayList<>();

final List profiles = UserManagerCompat.getInstance(context).getUserProfiles();

ArrayList<InstallShortcutReceiver.PendingInstallShortcutInfo> added = new ArrayList<InstallShortcutReceiver.PendingInstallShortcutInfo>();

for (UserHandle user : profiles) {

final List apps = LauncherAppsCompat.getInstance(context).getActivityList(null, user);

synchronized (this) {

for (LauncherActivityInfo info : apps) {

if(DmConfig.isHiddenPackage(info.getComponentName())){continue;}//hide app by lhw

for (AppInfo appInfo : appsList.added) {

if(info.getComponentName().equals(appInfo.componentName)){

InstallShortcutReceiver.PendingInstallShortcutInfo mPendingInstallShortcutInfo

= new InstallShortcutReceiver.PendingInstallShortcutInfo(info,context);

added.add(mPendingInstallShortcutInfo);

installQueue.add(mPendingInstallShortcutInfo.getItemInfo());

}

}

}

}

}

if (!added.isEmpty()) {

app.getModel().addAndBindAddedWorkspaceItems(installQueue);

}

}

//add for load new install app on workspace end by lhw

appsList.added.clear();

addedOrModified.addAll(appsList.modified);

appsList.modified.clear();

final ArrayList removedApps = new ArrayList<>(appsList.removed);

appsList.removed.clear();

final ArrayMap<ComponentName, AppInfo> addedOrUpdatedApps = new ArrayMap<>();

if (!addedOrModified.isEmpty()) {

scheduleCallbackTask(new CallbackTask() {

@Override

public void execute(Callbacks callbacks) {

//TODO bindAppsAddedOrUpdated 通过AllAppsStore的addOrUpdateApps方法去通知AllApps界面刷新 LHW

callbacks.bindAppsAddedOrUpdated(addedOrModified);

}

});

for (AppInfo ai : addedOrModified) {

addedOrUpdatedApps.put(ai.componentName, ai);

}

}

  • 通过execute 执行应用的添加 删除 更新操作
  1. iconCache.updateIconsForPkg 更新应用图标信息

/**

  • Updates the entries related to the given package in memory and persistent DB.

*/

public synchronized void updateIconsForPkg(String packageName, UserHandle user) {

removeIconsForPkg(packageName, user);

try {

PackageInfo info = mPackageManager.getPackageInfo(packageName,

PackageManager.GET_UNINSTALLED_PACKAGES);

long userSerial = mUserManager.getSerialNumberForUser(user);

for (LauncherActivityInfo app : mLauncherApps.getActivityList(packageName, user)) {

addIconToDBAndMemCache(app, info, userSerial, false /replace existing/);

}

} catch (NameNotFoundException e) {

Log.d(TAG, “Package not found”, e);

}

}

  1. 通过appsList.addPackage方法将新应用信息缓存到AllAppsList

/**

  • Add the icons for the supplied apk called packageName.

*/

public void addPackage(Context context, String packageName, UserHandle user) {

final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context);

final List matches = launcherApps.getActivityList(packageName,

user);

for (LauncherActivityInfo info : matches) {

add(new AppInfo(context, info, user), info);

}

}

/**

  • Add the supplied ApplicationInfo objects to the list, and enqueue it into the

  • list to broadcast when notify() is called.

  • If the app is already in the list, doesn’t add it.

*/

public void add(AppInfo info, LauncherActivityInfo activityInfo) {

if (!mAppFilter.shouldShowApp(info.componentName)) {

return;

}

if (findAppInfo(info.componentName, info.user) != null) {

return;

}

mIconCache.getTitleAndIcon(info, activityInfo, true /* useLowResIcon */);

data.add(info);

added.add(info);

}

  1. 通过bindAppsAddedOrUpdated方法回调launcher,进行界面更新的处理。

final ArrayMap<ComponentName, AppInfo> addedOrUpdatedApps = new ArrayMap<>();

if (!addedOrModified.isEmpty()) {

scheduleCallbackTask(new CallbackTask() {

@Override

public void execute(Callbacks callbacks) {//TODO bindAppsAddedOrUpdated 通过AllAppsStore的addOrUpdateApps方法去通知AllApps界面刷新 LHW

callbacks.bindAppsAddedOrUpdated(addedOrModified);

}

});

for (AppInfo ai : addedOrModified) {

addedOrUpdatedApps.put(ai.componentName, ai);

}

}

4.Launcher.java 中通过AllAppsStore的addOrUpdateApps方法去通知AllApps界面刷新

/**

  • Default launcher application.

*/

public class Launcher extends BaseDraggingActivity implements LauncherExterns,

LauncherModel.Callbacks, LauncherProviderChangeListener, UserEventDelegate{

public static final String TAG = “Launcher”;

/**

  • A package was updated.

  • Implementation of the method from LauncherModel.Callbacks.

*/

@Override

public void bindAppsAddedOrUpdated(ArrayList apps) {

mAppsView.getAppsStore().addOrUpdateApps(apps);

}

5.在AllAppsStore中更新App 列表

/**

  • A utility class to maintain the collection of all apps.

*/

public class AllAppsStore {

/**

  • Adds or updates existing apps in the list

*/

public void addOrUpdateApps(List apps) {

for (AppInfo app : apps) {

Log.d(“LHW_L”,“addOrUpdateApps-==”+app.title+“,=apps.size=”+apps.size());

mComponentToAppMap.put(app.toComponentKey(), app);

}

notifyUpdate();

}

  1. AllAppsContainerView 获取 AllAppsStore 所有应用数据,通过all_apps_rv_layout.xml中AllAppsRecyclerView显示

/**

  • The all apps view container.

*/

public class AllAppsContainerView extends SpringRelativeLayout implements DragSource,

Insettable, OnDeviceProfileChangeListener {

private final AllAppsStore mAllAppsStore = new AllAppsStore();

public AllAppsContainerView(Context context, AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

mLauncher = Launcher.getLauncher(context);

mLauncher.addOnDeviceProfileChangeListener(this);

mSearchQueryBuilder = new SpannableStringBuilder();

Selection.setSelection(mSearchQueryBuilder, 0);

mAH = new AdapterHolder[2];

mAH[AdapterHolder.MAIN] = new AdapterHolder(false /* isWork */);

mAH[AdapterHolder.WORK] = new AdapterHolder(true /* isWork */);

mNavBarScrimPaint = new Paint();

mNavBarScrimPaint.setColor(Themes.getAttrColor(context, R.attr.allAppsNavBarScrimColor));

mAllAppsStore.addUpdateListener(this::onAppsUpdated);

addSpringView(R.id.all_apps_header);

addSpringView(R.id.apps_list_view);

addSpringView(R.id.all_apps_tabs_view_pager);

}

  1. AllAppsContainerView中 AdapterHolderAllAppsGridAdapter加载 显示所有App信息到视图

/**

  • A RecyclerView with custom fast scroll support for the all apps view.

*/

public class AllAppsRecyclerView extends BaseRecyclerView implements LogContainerProvider {

public class AdapterHolder {

public static final int MAIN = 0;

public static final int WORK = 1;

public final AllAppsGridAdapter adapter;

final LinearLayoutManager layoutManager;

final AlphabeticalAppsList appsList;

final Rect padding = new Rect();

AllAppsRecyclerView recyclerView;

boolean verticalFadingEdge;

AdapterHolder(boolean isWork) {

appsList = new AlphabeticalAppsList(mLauncher, mAllAppsStore, isWork);

adapter = new AllAppsGridAdapter(mLauncher, appsList);

appsList.setAdapter(adapter);

layoutManager = adapter.getLayoutManager();

}

void setup(@NonNull View rv, @Nullable ItemInfoMatcher matcher) {

appsList.updateItemFilter(matcher);

recyclerView = (AllAppsRecyclerView) rv;

recyclerView.setEdgeEffectFactory(createEdgeEffectFactory());

recyclerView.setApps(appsList, mUsingTabs);

recyclerView.setLayoutManager(layoutManager);

recyclerView.setAdapter(adapter);

recyclerView.setHasFixedSize(true);

// No animations will occur when changes occur to the items in this RecyclerView.

recyclerView.setItemAnimator(null);

FocusedItemDecorator focusedItemDecorator = new FocusedItemDecorator(recyclerView);

recyclerView.addItemDecoration(focusedItemDecorator);

adapter.setIconFocusListener(focusedItemDecorator.getFocusListener());

applyVerticalFadingEdgeEnabled(verticalFadingEdge);

applyPadding();

}

  1. AllAppsGridAdapter 获取数据显示App 图标和信息

@Override

public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

switch (viewType) {

case VIEW_TYPE_ICON:

BubbleTextView icon = (BubbleTextView) mLayoutInflater.inflate(

R.layout.all_apps_icon, parent, false);

icon.setOnClickListener(ItemClickHandler.INSTANCE);

icon.setOnLongClickListener(ItemLongClickListener.INSTANCE_ALL_APPS);

icon.setLongPressTimeout(ViewConfiguration.getLongPressTimeout());

icon.setOnFocusChangeListener(mIconFocusListener);

// Ensure the all apps icon height matches the workspace icons in portrait mode.

icon.getLayoutParams().height = mLauncher.getDeviceProfile().allAppsCellHeightPx;

return new ViewHolder(icon);

all_apps_icon.xml 中 BubbleTextView 显示桌面图标信息

<com.android.launcher3.BubbleTextView

xmlns:android=“http://schemas.android.com/apk/res/android”

xmlns:launcher=“http://schemas.android.com/apk/res-auto”

style=“@style/BaseIcon”

android:id=“@+id/icon”

android:layout_width=“match_parent”

android:layout_height=“wrap_content”

android:stateListAnimator=“@animator/all_apps_fastscroll_icon_anim”

launcher:iconDisplay=“all_apps”

launcher:centerVertically=“true”

android:paddingLeft=“@dimen/dynamic_grid_cell_padding_x”

android:paddingRight=“@dimen/dynamic_grid_cell_padding_x” />

onBindViewHolder applyFromApplicationInfo 填充App信息数据

@Override

public void onBindViewHolder(ViewHolder holder, int position) {

switch (holder.getItemViewType()) {

case VIEW_TYPE_ICON:

AppInfo info = mApps.getAdapterItems().get(position).appInfo;

BubbleTextView icon = (BubbleTextView) holder.itemView;

icon.reset();

icon.applyFromApplicationInfo(info);

break;

Launcher 自定义 BubbleTextView 显示应用图标和信息

/**

  • TextView that draws a bubble behind the text. We cannot use a LineBackgroundSpan

  • because we want to make the bubble taller than the text and TextView’s clip is

  • too aggressive.

*/

public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, OnResumeCallback {

public void applyFromApplicationInfo(AppInfo info) {

applyIconAndLabel(info);

// We don’t need to check the info since it’s not a ShortcutInfo

super.setTag(info);

// Verify high res immediately

verifyHighRes();

if (info instanceof PromiseAppInfo) {

PromiseAppInfo promiseAppInfo = (PromiseAppInfo) info;

applyProgressLevel(promiseAppInfo.level);

}

applyBadgeState(info, false /* animate */);

}

private void applyIconAndLabel(ItemInfoWithIcon info) {

FastBitmapDrawable iconDrawable = DrawableFactory.get(getContext()).newIcon(info);

mBadgeColor = IconPalette.getMutedColor(info.iconColor, 0.54f);

setIcon(iconDrawable);

setText(info.title);

if (info.contentDescription != null) {

setContentDescription(info.isDisabled()

? getContext().getString(R.string.disabled_app_label, info.contentDescription)
info.contentDescription);

}

}

/**

  • Sets the icon for this view based on the layout direction.

*/

private void setIcon(Drawable icon) {

if (mIsIconVisible) {

applyCompoundDrawables(icon);

}

mIcon = icon;

}

protected void applyCompoundDrawables(Drawable icon) {

// If we had already set an icon before, disable relayout as the icon size is the

// same as before.

mDisableRelayout = mIcon != null;

icon.setBounds(0, 0, mIconSize, mIconSize);

if (mLayoutHorizontal) {

setCompoundDrawablesRelative(icon, null, null, null);

} else {

setCompoundDrawables(null, icon, null, null);

}

mDisableRelayout = false;

}

Launcher 初始加载所有应用信息

Launcher.java文件 在onCreate 通过 LauncherModel 的 startLoader 函数进行数据的绑定加载和更新

/**

  • Default launcher application.

*/

public class Launcher extends BaseDraggingActivity implements LauncherExterns,

LauncherModel.Callbacks, LauncherProviderChangeListener, UserEventDelegate{

public static final String TAG = “Launcher”;

static final boolean LOGD = false;

@Override

protected void onCreate(Bundle savedInstanceState) {

TraceHelper.beginSection(“Launcher-onCreate”);

super.onCreate(savedInstanceState);

TraceHelper.partitionSection(“Launcher-onCreate”, “super call”);

LauncherAppState app = LauncherAppState.getInstance(this);

mOldConfig = new Configuration(getResources().getConfiguration());

//获取初始化 LauncherModel 进行广播监听数据绑定和更新加载

mModel = app.setLauncher(this);

initDeviceProfile(app.getInvariantDeviceProfile());

// We only load the page synchronously if the user rotates (or triggers a

// configuration change) while launcher is in the foreground

int currentScreen = PagedView.INVALID_RESTORE_PAGE;

if (savedInstanceState != null) {

currentScreen = savedInstanceState.getInt(RUNTIME_STATE_CURRENT_SCREEN, currentScreen);

}

// LauncherModel startLoader 开启线程进行数据加载

if (!mModel.startLoader(currentScreen)) {

if (!internalStateHandled) {

// If we are not binding synchronously, show a fade in animation when

// the first page bind completes.

mDragLayer.getAlphaProperty(ALPHA_INDEX_LAUNCHER_LOAD).setValue(0);

}

} else {

// Pages bound synchronously.

mWorkspace.setCurrentPage(currentScreen);

setWorkspaceLoading(true);

}

// For handling default keys

setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL);

setContentView(mLauncherView);

LauncherModel 广播监听Launcher数据处理和接口回调

startLoader() 绑定和加载所用应用信息、小组件、快捷方式等到Workspace

/**

  • 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.

*/

public class LauncherModel extends BroadcastReceiver

implements LauncherAppsCompat.OnAppsChangedCallbackCompat {

private static final boolean DEBUG_RECEIVER = !com.android.launcher3.Log.IS_USER_VERSON;//true;

/**

  • Starts the loader. Tries to bind {@params synchronousBindPage} synchronously if possible.

  • @return true if the page could be bound synchronously.

*/

public boolean startLoader(int synchronousBindPage) {

// Enable queue before starting loader. It will get disabled in Launcher#finishBindingItems

InstallShortcutReceiver.enableInstallQueue(InstallShortcutReceiver.FLAG_LOADER_RUNNING);

synchronized (mLock) {

// Don’t bother to start the thread if we know it’s not going to do anything

if (mCallbacks != null && mCallbacks.get() != null) {

final Callbacks oldCallbacks = mCallbacks.get();

// Clear any pending bind-runnables from the synchronized load process.

// begin modify by mjf for REQ006

//mUiExecutor.execute(oldCallbacks::clearPendingBinds);

final Runnable runnable = new Runnable() {

@Override

public void run() {

oldCallbacks.clearPendingBinds();

}

};

mUiExecutor.execute(runnable);

// end

// If there is already one running, tell it to stop.

stopLoader();

LoaderResults loaderResults = new LoaderResults(mApp, sBgDataModel,

mBgAllAppsList, synchronousBindPage, mCallbacks);

if (mModelLoaded && !mIsLoaderTaskRunning) {

// Divide the set of loaded items into those that we are binding synchronously,

// and everything else that is to be bound normally (asynchronously).

loaderResults.bindWorkspace();

// For now, continue posting the binding of AllApps as there are other

// issues that arise from that.

loaderResults.bindAllApps();

loaderResults.bindDeepShortcuts();

loaderResults.bindWidgets();

return true;

} else {

startLoaderForResults(loaderResults);

}

}

}

return false;

}

  • startLoaderForResults() 开始加载和返回数据结果

public void startLoaderForResults(LoaderResults results) {

synchronized (mLock) {

stopLoader();

mLoaderTask = new LoaderTask(mApp, mBgAllAppsList, sBgDataModel, results);

runOnWorkerThread(mLoaderTask);

onPackageChanged(DmConfig.mCalenderPkgName, android.os.Process.myUserHandle()); /* add by mjf for HCT_CUSTOM_CALENDAR */

}

}

public void startLoaderForResultsIfNotLoaded(LoaderResults results) {

synchronized (mLock) {

if (!isModelLoaded()) {

Log.d(TAG, “Workspace not loaded, loading now”);

startLoaderForResults(results);

}

}

}

  • LoaderTask.java 启动线程去处理桌面数据显示信息,所有桌面图标、组件、文件夹等信息

在run 函数里进行处理 分步骤进行数据的处理加载,将 AllAppsContainerView 中的图标加载到 Workspace

/**

  • Runnable for the thread that loads the contents of the launcher:

    • workspace icons
    • widgets
    • all apps icons
    • deep shortcuts within apps

*/

public class LoaderTask implements Runnable {

private static final String TAG = “LoaderTask”;

public LoaderTask(LauncherAppState app, AllAppsList bgAllAppsList, BgDataModel dataModel,

LoaderResults results) {

mApp = app;

mBgAllAppsList = bgAllAppsList;

mBgDataModel = dataModel;

mResults = results;

mLauncherApps = LauncherAppsCompat.getInstance(mApp.getContext());

mUserManager = UserManagerCompat.getInstance(mApp.getContext());

mShortcutManager = DeepShortcutManager.getInstance(mApp.getContext());

mPackageInstaller = PackageInstallerCompat.getInstance(mApp.getContext());

mAppWidgetManager = AppWidgetManagerCompat.getInstance(mApp.getContext());

mIconCache = mApp.getIconCache();

}

public void run() {

synchronized (this) {

// Skip fast if we are already stopped.

if (mStopped) {

return;

}

}

TraceHelper.beginSection(TAG);

try (LauncherModel.LoaderTransaction transaction = mApp.getModel().beginLoader(this)) {

TraceHelper.partitionSection(TAG, “step 1.1: loading workspace”);

loadWorkspace();

verifyNotStopped();

TraceHelper.partitionSection(TAG, “step 1.2: bind workspace workspace”);

mResults.bindWorkspace();

// Notify the installer packages of packages with active installs on the first screen.

TraceHelper.partitionSection(TAG, “step 1.3: send first screen broadcast”);

sendFirstScreenActiveInstallsBroadcast();

// Take a break

TraceHelper.partitionSection(TAG, “step 1 completed, wait for idle”);

waitForIdle();

verifyNotStopped();

// second step

TraceHelper.partitionSection(TAG, “step 2.1: loading all apps”);

loadAllApps();

//可以定义一个宏开关进行控制

if(FeatureFlags.DISABLE_ALL_APP){

verifyApplications();

}

TraceHelper.partitionSection(TAG, “step 2.2: Binding all apps”);

verifyNotStopped();

mResults.bindAllApps();

verifyNotStopped();

TraceHelper.partitionSection(TAG, “step 2.3: Update icon cache”);

updateIconCache();

// Take a break

TraceHelper.partitionSection(TAG, “step 2 completed, wait for idle”);

waitForIdle();

verifyNotStopped();

// third step

TraceHelper.partitionSection(TAG, “step 3.1: loading deep shortcuts”);

loadDeepShortcuts();

verifyNotStopped();

TraceHelper.partitionSection(TAG, “step 3.2: bind deep shortcuts”);

mResults.bindDeepShortcuts();

// Take a break

TraceHelper.partitionSection(TAG, “step 3 completed, wait for idle”);

waitForIdle();

verifyNotStopped();

// fourth step

TraceHelper.partitionSection(TAG, “step 4.1: loading widgets”);

mBgDataModel.widgetsModel.update(mApp, null);

verifyNotStopped();

TraceHelper.partitionSection(TAG, “step 4.2: Binding widgets”);

mResults.bindWidgets();

transaction.commit();
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

Launcher3 安装App加载显示过程分析,开源新作,程序员,开源

Launcher3 安装App加载显示过程分析,开源新作,程序员,开源

Launcher3 安装App加载显示过程分析,开源新作,程序员,开源

Launcher3 安装App加载显示过程分析,开源新作,程序员,开源

Launcher3 安装App加载显示过程分析,开源新作,程序员,开源

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

Launcher3 安装App加载显示过程分析,开源新作,程序员,开源

最后

这里我希望可以帮助到大家提升进阶。

内容包含:Android学习PDF+架构视频+面试文档+源码笔记高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料 这几块的内容。非常适合近期有面试和想在技术道路上继续精进的朋友。

喜欢本文的话,不妨给我点个小赞、评论区留言或者转发支持一下呗~

Launcher3 安装App加载显示过程分析,开源新作,程序员,开源

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!文章来源地址https://www.toymoban.com/news/detail-858413.html

loading widgets");

mBgDataModel.widgetsModel.update(mApp, null);

verifyNotStopped();

TraceHelper.partitionSection(TAG, “step 4.2: Binding widgets”);

mResults.bindWidgets();

transaction.commit();
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

[外链图片转存中…(img-zGLpZERn-1712781574022)]

[外链图片转存中…(img-pftetYII-1712781574023)]

[外链图片转存中…(img-sUmF51xL-1712781574023)]

[外链图片转存中…(img-SUB5JODs-1712781574024)]

[外链图片转存中…(img-mz0cevJb-1712781574024)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

Launcher3 安装App加载显示过程分析,开源新作,程序员,开源

最后

这里我希望可以帮助到大家提升进阶。

内容包含:Android学习PDF+架构视频+面试文档+源码笔记高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料 这几块的内容。非常适合近期有面试和想在技术道路上继续精进的朋友。

喜欢本文的话,不妨给我点个小赞、评论区留言或者转发支持一下呗~

Launcher3 安装App加载显示过程分析,开源新作,程序员,开源

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

到了这里,关于Launcher3 安装App加载显示过程分析,开源新作的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【干货】Android系统定制基础篇:第二部分(Launcher3支持键盘切换焦点、开发者模式密码确认、禁止非预装应用安装、配置时间)

    Android Launcher3 默认并不支持键盘操作,无法切换焦点,在一些需要支持键盘或遥控操作的设备中无法使用,因些对 Launcher3 做简单修改,使其支持键盘切换焦点。 在安全性要求比较高的产品中,一般会默认关闭『adb调试』,同时禁止用户打开『adb调试』功能。在Android8.1中默认

    2024年02月10日
    浏览(55)
  • Android 9.0 当系统内置两个Launcher时默认设置Launcher3以外的那个Launcher为默认Launcher

    在9.0系统rom定制化开发中,由于产品开发需要要求系统内置两个Launcher,一个是Launcher3,一个是自己开发的Launcher,当系统启动Launcher时, 不要弹出Launcher选择列表 选择哪个Launcher要求默认选择自己开发的Launcher作为默认Launcher,关于选择Launcher列表 其实都是在ResolverActivity.java中处理

    2024年01月18日
    浏览(49)
  • Android 10.0 当系统内置两个Launcher时默认设置Launcher3以外的那个Launcher为默认Launcher

    在10.0定制化开发中,由于产品开发需要要求系统内置两个Launcher,一个是Launcher3,一个是自己开发的Launcher,当系统启动Launcher时, 不要弹出Launcher选择列表 选择哪个Launcher要求默认选择自己开发的Launcher作为默认Launcher,关于选择Launcher列表 其实都是在ResolverActivity.java中处理的具

    2024年02月10日
    浏览(48)
  • Android10/11 原生Launcher3深度定制

    一、引言 关于Android10和11系统Launcher3的定制有很多,根据项目的需求会进行各种定制开发, 于是就需要研究Launcher3的源码。本文主要从Android 11的Launcher3QuickStep着手 (go版本或者其他版本类似)从常用的修改进行分析,首先就得大致理解 Launcher3各个 类的作用。 1.1、常用类简

    2023年04月17日
    浏览(50)
  • Android 9.0 Launcher3去掉抽屉模式 双层改成单层系列一

      在9.0的系统产品开发中,在Launcher3中系统默认是上滑抽屉模式,通过上滑可以拉出app列表页,产品需求要求改成去掉上滑抽屉模式 就是改成单层模式,所以本系列就来讲解下双层改单层系列第一讲

    2024年02月03日
    浏览(43)
  • Android 13.0 Launcher3定制之双层改单层(去掉抽屉式二)

      在13.0的系统产品开发中,对于在Launcher3中的抽屉模式也就是双层模式,在系统原生的Launcher3中就是双层抽屉模式的, 但是在通过抽屉上滑的模式拉出app列表页,但是在一些产品开发中,对于单层模式的Launcher3的产品模式也是常用的功能, 所以需要了解抽屉模式,然后修改

    2024年02月09日
    浏览(50)
  • Android 13.0 Launcher3定制之双层改单层(去掉抽屉式四)

     在13.0的系统产品开发中,对于在Launcher3中的抽屉模式中,系统默认的就是抽屉单层模式,但是在很多产品中需要默认为单层模式,就是要求去掉双层抽屉模式,接下来看下如何继续实现去掉抽屉双层模式,来变成单层模式第四节 Launcher3定制之双层改单层(去掉抽屉式四)的功

    2024年02月09日
    浏览(87)
  • Android 12.0Launcher3 去掉workspace长按弹出壁纸弹窗

    在12.0的系统开发中,在Launcher3开发中,在长按屏幕的时候,会弹出窗口,修改主屏幕配置,壁纸,等信息,由于要默认设置一些配置 不想让用户修改相关配置,这时候就需要去掉长按弹窗功能了,禁止修改相关配置 下面来分析下workspace相关长按事件的功能实现 先看workspac

    2024年02月07日
    浏览(72)
  • Android framework学习指南之Launcher启动过程原理分析

    Launcher是一个用来显示系统中已经安装的应用程序的应用程序,Launcher 在启动过程中会请求PackageManagerService 返回系统中已经安装的应用程序的信息,并将这些信息封装成一个快捷图标列表显示在系统屏幕上,这样用户可以通过点击这些快捷图标来启动相应的应用程序,它的作

    2024年02月03日
    浏览(50)
  • android 12.0Launcher3长按拖拽时,获取当前是哪一屏,获取当前多少个应用图标

    在12.0定制化开发手机项目中,如果专门适配老年机的时候,这时客户提出要求,如果最后一屏未满时,不让拖拽到后面一屏的空屏中这样就需要获取当前是哪一屏,并且要知道当前有多少个Item,总共一屏最多多少个item 所以就需要从Workspace.java入手,来分析解决这个问题 首选

    2024年02月06日
    浏览(61)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包