android显示过程,Android 桌面加载图标过程分析

桌面应用图标流程

前言

本人工作上碰到这么一个需求,开发一款滤镜引擎,将桌面上所有的图标进行统一的滤镜化,这就需要了解一下整个桌面去取图标的过程,了解了整个过程,找到真正拿图标的地方,在真正取图标的地方将图片进行替换,或者滤镜化,之前分析情况,现在整理下,与大家分享。本文所用的代码,是基于Android 5.1

桌面组件介绍

6b5f55e7641b788bbcd5d6da69a7420c.png

一级菜单

WorkSpace:他是一个ViewGroup,要想在桌面上显示东西,就得往这个ViewGroup里添加自己的View

BubbleTextView:他是一个TextView,上方是图标,下方是名称,在桌面上的图标都是由这个类表示

FolderIcon:他也是一个ViewGroup,用来表示桌面上的文件夹图标,里面添加了缩略处理过的bitmap,他的背景图片就是文件夹的形状

HotSeat: 他是个FrameLayout,是桌面下方的固定快捷区,包含了几个常用的图标,中间的AllApp按钮是固定位置,也是一个TextView

7e926dfdb66003389900dd91a6172c05.png

抽屉页面 组件

PagedView:他是一个viewgroup,代表进入抽屉页后的界面,应用图标需要添加到这个viewgoup里面才能显示,一个或几个PagedView 承载了手机上所有的应用图标

PagedViewIcon:他是一个TextView,和BubblTextView一样,只是在抽屉容器里换了个名字

桌面加载图标流程

先来看一张流程图

722af27cff2c184d72c0cd0a758af56f.png

桌面Activity 也就是Launcher.java 类,该类里面维护了一个 LauncherModel,该对象会在onCreate 方法中去调用startLoader() 方法,

下面看一下startLoader() 方法的源码, public void startLoader(boolean isLaunching, int synchronousBindPage) {

synchronized (mLock) {

if (DEBUG_LOADERS) {

Log.d(TAG, "startLoader isLaunching=" + isLaunching);

}

// Clear any deferred bind-runnables from the synchronized load process

// We must do this before any loading/binding is scheduled below.

mDeferredBindRunnables.clear();

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

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

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

// also, don't downgrade isLaunching if we're already running

isLaunching = isLaunching || stopLoaderLocked();

// 这搞了一个异步任务去加载

mLoaderTask = new LoaderTask(mApp.getContext(), isLaunching);

if (synchronousBindPage > -1 && mAllAppsLoaded && mWorkspaceLoaded) {

mLoaderTask.runBindSynchronousPage(synchronousBindPage);

} else {

sWorkerThread.setPriority(Thread.NORM_PRIORITY);

sWorker.post(mLoaderTask);

}

}

}

}

我们看到,这里面有个关键的类,loaderTask,见名只义,可以猜到这里面会起一个线程,去加载一些资源。看看里面去加载什么

LoaderTask.java

可以看到LoaderTask实现了Runnable接口,直接去看该类的run() 方法 public void run() {

boolean isUpgrade = false;

synchronized (mLock) {

mIsLoaderTaskRunning = true;

}

// Optimize for end-user experience: if the Launcher is up and // running with the

// All Apps interface in the foreground, load All Apps first. Otherwise, load the

// workspace first (default).

keep_running: {

// Elevate priority when Home launches for the first time to avoid

// starving at boot time. Staring at a blank home is not cool.

synchronized (mLock) {

if (DEBUG_LOADERS) Log.d(TAG, "Setting thread priority to " +

(mIsLaunching ? "DEFAULT" : "BACKGROUND"));

android.os.Process.setThreadPriority(mIsLaunching

? Process.THREAD_PRIORITY_DEFAULT : Process.THREAD_PRIORITY_BACKGROUND);

}

if (DEBUG_LOADERS) Log.d(TAG, "step 1: loading workspace");

//加载一级菜单的方法

isUpgrade = loadAndBindWorkspace();

if (mStopped) {

break keep_running;

}

// Whew! Hard work done. Slow us down, and wait until the UI thread has

// settled down.

synchronized (mLock) {

if (mIsLaunching) {

if (DEBUG_LOADERS) Log.d(TAG, "Setting thread priority to BACKGROUND");

android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);

}

}

waitForIdle();

// second step

if (DEBUG_LOADERS) Log.d(TAG, "step 2: loading all apps");

//加载二级菜单里面的方法

loadAndBindAllApps();

// Restore the default thread priority after we are done loading items

synchronized (mLock) {

android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);

}

}

// Update the saved icons if necessary

if (DEBUG_LOADERS) Log.d(TAG, "Comparing loaded icons to database icons");

synchronized (sBgLock) {

for (Object key : sBgDbIconCache.keySet()) {

updateSavedIcon(mContext, (ShortcutInfo) key, sBgDbIconCache.get(key));

}

sBgDbIconCache.clear();

}

if (AppsCustomizePagedView.DISABLE_ALL_APPS) {

// Ensure that all the applications that are in the system are

// represented on the home screen.

if (!UPGRADE_USE_MORE_APPS_FOLDER || !isUpgrade) {

verifyApplications();

}

}

// Clear out this reference, otherwise we end up holding it until all of the

// callback runnables are done.

mContext = null;

synchronized (mLock) {

// If we are still the last one to be scheduled, remove ourselves.

if (mLoaderTask == this) {

mLoaderTask = null;

}

mIsLoaderTaskRunning = false;

}

}

可以看到在该类中主要有两个方法,

loadAndBindWorkSpace(), WorkSpace是一级菜单里面的容器类,该方法是加载一及菜单的方法

loadAndBindAllapp() ,这是抽屉内二级菜单的加载方法

下面着重分析下这两个方法的加载流程

####loadAndBindWorkSpace()

这里加载主要分为两个流程一个是 loadWorkSpace 另一个是 bindWorkSpace,可以看下源代码 private boolean loadAndBindWorkspace() {

mIsLoadingAndBindingWorkspace = true;

// Load the workspace

if (DEBUG_LOADERS) {

Log.d(TAG, "loadAndBindWorkspace mWorkspaceLoaded=" + mWorkspaceLoaded);

}

boolean isUpgradePath = false;

if (!mWorkspaceLoaded) {

isUpgradePath = loadWorkspace();

synchronized (LoaderTask.this) {

if (mStopped) {

return isUpgradePath;

}

mWorkspaceLoaded = true;

}

}

// Bind the workspace

bindWorkspace(-1, isUpgradePath);

return isUpgradePath;

}

可以看到并没有直接去加载,而是先判断了一些条件,然后去加载

loadWorkSpace() 方法比较长大概分为三步,

初始化后面要用到的对象实例 final long t = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;

final Context context = mContext;

final ContentResolver contentResolver = context.getContentResolver();

final PackageManager manager = context.getPackageManager();

final AppWidgetManager widgets = AppWidgetManager.getInstance(context);

final boolean isSafeMode = manager.isSafeMode();

LauncherAppState app = LauncherAppState.getInstance();

DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();

int countX = (int) grid.numColumns;

int countY = (int) grid.numRows;

加载默认配置,并保存数据库中 synchronized public void loadDefaultFavoritesIfNecessary(int origWorkspaceResId) {

String spKey = LauncherAppState.getSharedPreferencesKey();

SharedPreferences sp = getContext().getSharedPreferences(spKey, Context.MODE_PRIVATE);

if (sp.getBoolean(EMPTY_DATABASE_CREATED, false)) {

int workspaceResId = origWorkspaceResId;

// Use default workspace resource if none provided

//如果workspaceResId=0,就会加载默认的配置(default_workspace_xxx.xml),并保存到数据库中

if (workspaceResId == 0) {

workspaceResId = sp.getInt(DEFAULT_WORKSPACE_RESOURCE_ID, R.xml.default_workspace);

}

// Populate favorites table with initial favorites

SharedPreferences.Editor editor = sp.edit();

editor.remove(EMPTY_DATABASE_CREATED);

if (origWorkspaceResId != 0) {

editor.putInt(DEFAULT_WORKSPACE_RESOURCE_ID, origWorkspaceResId);

}

mOpenHelper.loadFavorites(mOpenHelper.getWritableDatabase(), workspaceResId);

mOpenHelper.setFlagJustLoadedOldDb();

editor.commit();

}

}

读取数据库,获取需要加载的应用快捷方式

此段代码较多,就是去读取数据库的一些操作,具体过程是根据一些不同的type 存到不同的list中。

bindWorkSpace()

应用信息读取完之后,刚才的几个变量中就存储了该信息,然后将其绑定到workspace中去,这个过程也是很复杂的

创建局部变量,将全局变量的信息复制过来,单独进行操作 ArrayList workspaceItems = new ArrayList();

ArrayList appWidgets = new ArrayList();

HashMap folders = new HashMap();

HashMap itemsIdMap = new HashMap();

ArrayList orderedScreenIds = new ArrayList();

synchronized (sBgLock) {

workspaceItems.addAll(sBgWorkspaceItems);

appWidgets.addAll(sBgAppWidgets);

folders.putAll(sBgFolders);

itemsIdMap.putAll(sBgItemsIdMap);

orderedScreenIds.addAll(sBgWorkspaceScreens);

}

final boolean isLoadingSynchronously = synchronizeBindPage != PagedView.INVALID_RESTORE_PAGE;

int currScreen = isLoadingSynchronously ? synchronizeBindPage : oldCallbacks.getCurrentWorkspaceScreen();

if (currScreen >= orderedScreenIds.size()) {

// There may be no workspace screens (just hotseat items and an empty page).

currScreen = PagedView.INVALID_RESTORE_PAGE;

}

final int currentScreen = currScreen;// 当前screen

final long currentScreenId = currentScreen < 0 ? INVALID_SCREEN_ID : orderedScreenIds.get(currentScreen);// 当前screen id

// Load all the items that are on the current page first (and in the process, unbind

// all the existing workspace items before we call startBinding() below.

unbindWorkspaceItemsOnMainThread();// 先解除绑定

根据item中的screenID将items分成当前screen和其他screen,并进行排序 // Separate the items that are on the current screen, and all the other remaining items

ArrayList currentWorkspaceItems = new ArrayList();// 存放当前workspace上的items

ArrayList otherWorkspaceItems = new ArrayList();// 存放除当前workspace之外的items

ArrayList currentAppWidgets = new ArrayList();// 存放当前workspace上的appwidgets

ArrayList otherAppWidgets = new ArrayList();// 存放除当前workspace之外的appwidgets

HashMap currentFolders = new HashMap();// 存放当前workspace上的folder

HashMap otherFolders = new HashMap();// 存放除当前workspace之外的folder

filterCurrentWorkspaceItems(currentScreenId, workspaceItems, currentWorkspaceItems, otherWorkspaceItems);// 过滤items,区分当前screen和其他screen上的items

filterCurrentAppWidgets(currentScreenId, appWidgets, currentAppWidgets, otherAppWidgets);// 同上

filterCurrentFolders(currentScreenId, itemsIdMap, folders, currentFolders, otherFolders);// 同上

sortWorkspaceItemsSpatially(currentWorkspaceItems);// 对workspace上的items进行排序,按照从上到下和从左到右的顺序

sortWorkspaceItemsSpatially(otherWorkspaceItems);// 同上

runnable执行块,告诉workspace要开始绑定items了,startBinding方法在Launcher中实现,做一些清除工作 // Tell the workspace that we're about to start binding items

r = new Runnable() {

public void run() {

Callbacks callbacks = tryGetCallbacks(oldCallbacks);

if (callbacks != null) {

callbacks.startBinding();

}

}

};

runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);

可以看一下实现类launcher中startBinding()方法 public void startBinding() {

// If we're starting binding all over again, clear any bind calls we'd postponed in

// the past (see waitUntilResume) -- we don't need them since we're starting binding

// from scratch again

mBindOnResumeCallbacks.clear();

// Clear the workspace because it's going to be rebound

mWorkspace.clearDropTargets();

mWorkspace.removeAllWorkspaceScreens();

mWidgetsToAdvance.clear();

if (mHotseat != null) {

mHotseat.resetLayout();

}

}

可以看到主要做的是清除和重置工作

绑定workspace screen bindWorkspaceScreens(oldCallbacks, orderedScreenIds);

具体实现在launcher中

Workspace绑定完成之后,就是将items、widgets和folders放到上面去

loadAndBindAllapp()

可以看到加载过程也是分为两步:如果所有app已经加载过了,就只需要绑定就行了,否则的话,加载所有app,第一次启动肯定是加载所有的,我们按照这种情况来分析

1.获取需要显示到Launcher中的app列表,创建app图标 private void loadAndBindAllApps() {

if (DEBUG_LOADERS) {

Log.d(TAG, "loadAndBindAllApps mAllAppsLoaded=" + mAllAppsLoaded);

}

if (!mAllAppsLoaded) {

loadAllApps();

synchronized (LoaderTask.this) {

if (mStopped) {

return;

}

mAllAppsLoaded = true;

}

} else {

onlyBindAllApps();

}

}

loadAllApps() final long loadTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;

final Callbacks oldCallbacks = mCallbacks.get();

if (oldCallbacks == null) {

// This launcher has exited and nobody bothered to tell us. Just bail.

Log.w(TAG, "LoaderTask running with no launcher (loadAllApps)");

return;

}

final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);

mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);

final List profiles = mUserManager.getUserProfiles();

// Clear the list of apps

mBgAllAppsList.clear();// 清除所有app列表

SharedPreferences prefs = mContext.getSharedPreferences(

LauncherAppState.getSharedPreferencesKey(), Context.MODE_PRIVATE);

for (UserHandleCompat user : profiles) {

// Query for the set of apps

final long qiaTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;

List apps = mLauncherApps.getActivityList(null, user);// 获取需要显示在Launcher上的activity列表

if (DEBUG_LOADERS) {

Log.d(TAG, "getActivityList took "

+ (SystemClock.uptimeMillis()-qiaTime) + "ms for user " + user);

Log.d(TAG, "getActivityList got " + apps.size() + " apps for user " + user);

}

// Fail if we don't have any apps

// TODO: Fix this. Only fail for the current user.

if (apps == null || apps.isEmpty()) {// 没有需要显示的,直接返回

return;

}

// Sort the applications by name

final long sortTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;

Collections.sort(apps, new LauncherModel.ShortcutNameComparator(mLabelCache));// 排序

if (DEBUG_LOADERS) {

Log.d(TAG, "sort took " + (SystemClock.uptimeMillis()-sortTime) + "ms");

}

// Create the ApplicationInfos

for (int i = 0; i < apps.size(); i++) {

LauncherActivityInfoCompat app = apps.get(i);

// This builds the icon bitmaps.

mBgAllAppsList.add(new AppInfo(mContext, app, user, mIconCache, mLabelCache));// 创建应用图标对象,并添加到所有APP列表中

}

if (ADD_MANAGED_PROFILE_SHORTCUTS && !user.equals(UserHandleCompat.myUserHandle())) {

// Add shortcuts for packages which were installed while launcher was dead.

String shortcutsSetKey = INSTALLED_SHORTCUTS_SET_PREFIX + mUserManager.getSerialNumberForUser(user);

Set packagesAdded = prefs.getStringSet(shortcutsSetKey, Collections.EMPTY_SET);

HashSet newPackageSet = new HashSet();

for (LauncherActivityInfoCompat info : apps) {

String packageName = info.getComponentName().getPackageName();

if (!packagesAdded.contains(packageName)

&& !newPackageSet.contains(packageName)) {

InstallShortcutReceiver.queueInstallShortcut(info, mContext);

}

newPackageSet.add(packageName);

}

prefs.edit().putStringSet(shortcutsSetKey, newPackageSet).commit();

}

}

// Huh? Shouldn't this be inside the Runnable below?

final ArrayList added = mBgAllAppsList.added;// 获取自上次更新(notify()广播)后新增加的应用清单,如果是开机初次启动Launcher,那么added就是mBgAllAppsList

mBgAllAppsList.added = new ArrayList();// 将AllAppsList的added清空,不影响后续新增的app

// Post callback on main thread

mHandler.post(new Runnable() {

public void run() {

final long bindTime = SystemClock.uptimeMillis();

final Callbacks callbacks = tryGetCallbacks(oldCallbacks);

if (callbacks != null) {

callbacks.bindAllApplications(added);

if (DEBUG_LOADERS) {

Log.d(TAG, "bound " + added.size() + " apps in "

+ (SystemClock.uptimeMillis() - bindTime) + "ms");

}

} else {

Log.i(TAG, "not binding apps: no Launcher activity");

}

}

});

if (DEBUG_LOADERS) {

Log.d(TAG, "Icons processed in "

+ (SystemClock.uptimeMillis() - loadTime) + "ms");

}

绑定app--bindAllApplications public void bindAllApplications(final ArrayList apps) {

if (LauncherAppState.isDisableAllApps()) {// 判断是否禁用所有app,就是所有应用都显示在一级目录

if (mIntentsOnWorkspaceFromUpgradePath != null) {

if (LauncherModel.UPGRADE_USE_MORE_APPS_FOLDER) {

getHotseat().addAllAppsFolder(mIconCache, apps,

mIntentsOnWorkspaceFromUpgradePath, Launcher.this, mWorkspace);

}

mIntentsOnWorkspaceFromUpgradePath = null;

}

if (mAppsCustomizeContent != null) {

mAppsCustomizeContent.onPackagesUpdated(

LauncherModel.getSortedWidgetsAndShortcuts(this));

}

} else {

if (mAppsCustomizeContent != null) {

mAppsCustomizeContent.setApps(apps);

mAppsCustomizeContent.onPackagesUpdated(LauncherModel.getSortedWidgetsAndShortcuts(this));

}

}

if (mLauncherCallbacks != null) {

mLauncherCallbacks.bindAllApplications(apps);

}

} 可以看到无论是一级桌面拿图标,还是抽屉页面拿图标,都是去走,IconCache的getIcon()方法,

IconCache

getIcon() public Bitmap getIcon(ComponentName component, ResolveInfo resolveInfo,

HashMap labelCache) {

synchronized (mCache) {

if (resolveInfo == null || component == null) {

return null;

}

CacheEntry entry = cacheLocked(component, resolveInfo, labelCache);

return entry.icon;

}

}

这里判断一下条件,会去走cacheLocked() 方法

cacheLocked() private CacheEntry cacheLocked(ComponentName componentName, ResolveInfo info,

HashMap labelCache) {

CacheEntry entry = mCache.get(componentName);

if (entry == null) {

entry = new CacheEntry();

mCache.put(componentName, entry);

ComponentName key = LauncherModel.getComponentNameFromResolveInfo(info);

if (labelCache != null && labelCache.containsKey(key)) {

entry.title = labelCache.get(key).toString();

} else {

entry.title = info.loadLabel(mPackageManager).toString();

if (labelCache != null) {

labelCache.put(key, entry.title);

}

}

if (entry.title == null) {

entry.title = info.activityInfo.name;

}

entry.icon = Utilities.createIconBitmap(

getFullResIcon(info), mContext);

}

return entry;

}

这个方法里面。就是最终去拿图标的方法,里面去拿一些必要信息,去给entry赋值

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/442530.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

android开发者选项打开方式,打开、关闭安卓手机的开发者选项的方法详解

现在使用安卓手机的用户人群很多&#xff0c;大家都知道安卓手机中的“开发人员选项”吧&#xff0c;最近&#xff0c;有用户在问如何关闭或者打开开发者选项。那么小编今天就给大家带来一个打开、关闭安卓手机的开发者选项的方法&#xff0c;有需要的小伙伴赶紧来看看吧。打开…

zynq linux opencv效率,2 - 基于ZYNQ7000的交叉编译工具链Qt+OpenCV+ffmpeg等库支持总结

可以通过输入echo $PATH命令检查环境变量是否设置正确&#xff0c;如下图&#xff1a;可以&#xff0c;编译C文件进行测试&#xff0c;使用gedit在任意目录下编辑hello.c文件如图所示&#xff0c;保存后进入终端。以root身份进入到当前目录下&#xff0c;输入arm-xilinx-linux-…

android l 效果,[原]Android L中水波纹点击效果的实现

博主参加了2014 CSDN博客之星评选&#xff0c;帮我投一票吧。前言前段时间android L(android 5.0)出来了&#xff0c;界面上做了一些改动&#xff0c;主要是添加了若干动画和一些新的控件&#xff0c;相信大家对view的点击效果-水波纹很有印象吧&#xff0c;点击一个view&#…

html表情选择器,原生JS写的emoji表情选择器

//生成表情window.onload function() {var face document.getElementById(‘face‘);for(var i 0; i < 38; i) {var a document.createElement("a");a.href "javascript:;";if(i < 10) {a.innerHTML ‘‘;}else{a.innerHTML ‘‘;}face.appendCh…

3dmax里面cr材质转换vr材质_3DMAX零基础入门视频全套教程

3Dmax基础教程全套视频&#xff1a;点链接就行1.3dmax界面介绍2、3dmax主工具栏3、创建面板与修改面板4、时间轴与视口按钮5、3D视口讲解6、3dmax样条线界面7、CAD如何导入3dmax8、3DMAX绘制初步空间9、3DMAX导入图片与车削10、倒角和倒角剖面11、修改器堆栈|12、弯曲命令13、对…

html5 自定义 datepicker,如何使用 React 构建自定义日期选择器(3)

本文作者&#xff1a;IMWeb howenhuo未经同意&#xff0c;禁止转载Datepicker 组件构建 Datepicker 组件要开始构建 Datepicker 组件&#xff0c;请将以下代码片段添加到 src/components/Datepicker/index.js 文件。import React from "react";import PropTypes from…

群签名和环签名的区别_超级签名和TF签名使用个人开发者账号的区别是什么?...

了解过当前ios签名的朋友都知道&#xff0c;目前ios签名共分为企业签名、超级签名和TF签名&#xff0c;其中企业签名作为签名行业的“老大哥”&#xff0c;深受各路开发者和App运营商的喜爱。而我们今天的主角却是其他两种&#xff1a;超级签名和TF签名。这两种签名方式与企业签…

matlab水蒸气焓值计算_从第一性原理计算出发来理解含能配合物宏观行为的趋势...

欢迎关注微信公众平台"计算材料学"&#xff0c;微信ID&#xff1a;jisuancailiao近日&#xff0c;北京理工大学物理学院郭伟课题组&#xff08;博士研究生孙矗丽&#xff09;与北京理工大学爆炸科学与技术国家重点实验室、机电学院张同来课题组在Physical Chemistry …

抖音文字时钟壁纸html,抖音文字时钟app

抖音文字时钟app是一款蛮火蛮有趣的复古罗盘时钟应用&#xff0c;喜欢刷抖音的用户是不是在抖音上看到了这些的时钟&#xff0c;你是不是对这个罗盘产生了兴趣&#xff0c;今天小编为你提供了设置这个时钟的app&#xff0c;当前只有安卓版&#xff0c;苹果版暂未上线&#xff0…

计算机网络十进制转二进制的应用题,【网络-理论】二进制与十进制的转换

由于计算机中运行的数据都是以二进制数的形式存在的&#xff0c;学习二进制数的计算成为计算机专业必备的一门知识。概述正如字面上的意思&#xff1a;二进制数&#xff0c;满二进一&#xff0c;所以说二进制只由 数字0和数字1组成。十进制&#xff0c;满十进一&#xff0c;所以…

最大化_怎样保证油压缓冲器工作效率最大化?

对于油压缓冲器&#xff0c;广大使用者在采购前普遍考虑的是油压缓冲器的价格、质量、品牌。挑选出合适的油压缓冲器仅仅是第一步&#xff0c;提高其工作效率&#xff0c;增加产能&#xff0c;才能为企业创造更多价值。要保证油压缓冲器工作效率最大化&#xff0c;需要做到以下…

aosp 本地版本管理_谈 DevOps 平台实施:我在本地跑明明成功的,为什么在你平台跑就报错?...

我在本地跑明明成功的&#xff0c;为什么在你平台跑就报错&#xff1f;用户在 Jenkins 上跑构建时&#xff0c;失败了&#xff0c;把日志截图给我看&#xff0c;如下图&#xff1a;在过去几个月&#xff0c;每个星期都会有一两个 Jenkins 用户就会给我发送类似的错误日志。这样…

江苏大学2020计算机考研,江苏大学2020年硕士研究生复试时间及主要安排

根据《江苏大学2020年硕士研究生招生复试及录取办法》(江大研〔2020〕3号)&#xff0c;为做好我校2020年硕士研究生复试及录取工作&#xff0c;现将有关工作安排通知如下&#xff1a;一、复试人选符合我校复试分数线要求的一志愿考生、符合各学院(中心、研究院、所&#xff0c;…

尼康d7200拍照_为什么尼康和佳能的全画幅旗舰单反却只有2000多万像素?

华为P20Pro摄像头都做到了4000万像素&#xff0c;为什么尼康和佳能的全画幅顶级单反却只有2000多万像素&#xff1f;下面我们先来看看目前市场上摄影器材的像素情况。单机身售价高达3万多的尼康旗舰全画幅单反D5总像素是2133万&#xff0c;有效像素是2082万&#xff1b;单机身售…

国家级一级计算机考试题,国家级计算机一级考试试题

国家级计算机一级考试试题1.在Windows中&#xff0c;打开"资源管理器"窗口后&#xff0c;要改变文件或文件夹的显示方式&#xff0c;应选用( )。CA、"文件"菜单B、"编辑"菜单C、"查看"菜单D、"帮助"菜单2.在Windows的"…

重物码垛搬运机器人_节卡机器人:5G下的智慧物流——柔性生产物流系统

随着经济的发展&#xff0c;制造一直面临着劳动力成本迅速攀升、产能过剩、竞争激烈、客户个性化需求日益增长等问题。另一方面招工难&#xff0c;以及缺乏专业人才&#xff0c;制造业转型迫在眉睫。现在&#xff0c;5G、物联网、协作机器人、机器视觉等新兴技术迅速兴起&#…

霍纳法树形流图中处理机p个数_处理机管理(进程管理)

一、进程1.1.进程的定义程序关于某个数据集合的一次执行过程1.2.进程的特征(与程序比较&#xff09;结构特征进程控制块(PCB) 程序 数据 进程实体动态性 -- 最基本特征进程&#xff1a;进程实体的一次执行过程&#xff0c;有生命周期程序&#xff1a;程序是一组有序指令的集…

元胞计算机系统,元胞自动机的应用

【定义】元胞自动机(Cellular Automata, CA)定义在一个具有离散、有限状态的元胞组成的元胞空间上&#xff0c;并按照一定的局部规则&#xff0c;在离散的时间维度上演化的动力学系统。【构成】可以视为由一个元胞空间和定义于该空间的变换函数所组成【构形】在某个时刻&#x…

vue获取当前月最后一天_10月的最后一天,有哪些不想谈恋爱适合发朋友圈的文案?...

小时光提醒&#xff1a;今天是10月月的最后一天&#xff0c;凡是遇往&#xff0c;皆为序章。没关系的&#xff0c;不要给自己太大压力&#xff0c;生活不是选择&#xff0c;而是热爱&#xff01;“慢慢又漫漫&#xff0c;漫漫亦灿灿”我的意思是&#xff0c;所有等待的日子&…

手机psp模拟器哪个好_功能强大,手机微信群控系统和云控哪个好?

互联网信息技术在发展的同时&#xff0c;也在不断刷新我们对新科技的认知。随着微营销发展的风生水起&#xff0c;手机微信群控和云控出现了&#xff0c;主要就是通过一台电脑控制几十上百部手机&#xff0c;场面十分震撼&#xff0c;这样的黑科技&#xff0c;你了解过吗&#…