Android 从点击应用图标到界面显示的过程

Android 从点击应用图标到界面显示的过程,第1张

[转] 一篇文章看明白 Android 从点击应用图标到界面显示的过程 (遵循CC 40 BY-SA版权协议)

从点击桌面应用图标到应用显示的过程我们再熟悉不过了,下面我们来分析下这个过程都做了什么。

本文主要对以下问题分析:

如不了解 Android 是如何从开机到 Launcher 启动的过程,请先阅读 Android - 系统启动过程

我们知道 Android 系统启动后已经启动了 Zygote,ServiceManager,SystemServer 等系统进程;ServiceManager 进程中完成了 Binder 初始化;SystemServer 进程中 ActivityManagerService,WindowManagerService,PackageManagerService 等系统服务在 ServiceManager 中已经注册;最后启动了 Launcher 桌面应用。

其实 Launcher 本身就是一个应用程序,运行在自己的进程中,我们看到的桌面就是 Launcher 中的一个 Activity。

应用安装的时候,通过 PackageManagerService 解析 apk 的 AndroidManifestxml 文件,提取出这个 apk 的信息写入到 packagesxml 文件中,这些信息包括:权限、应用包名、icon、apk 的安装位置、版本、userID 等等。packagesxml 文件位于系统目录下/data/system/packagesxml。

同时桌面 Launcher 会为安装过的应用生成不同的应用入口,对应桌面上的应用图标,下面分析点击应用图标的到应用启动的过程。

点击 Launcher 中应用图标将会执行以下方法

在 system_server 进程中的服务端 ActivityManagerService 收到 START_ACTIVITY_TRANSACTION 命令后进行处理,调用 startActivity() 方法。

从 Launcher 点击图标,如果应用没有启动过,则会 fork 一个新进程。创建新进程的时候,ActivityManagerService 会保存一个 ProcessRecord 信息,Activity 应用程序中的AndroidManifestxml 配置文件中,我们没有指定 Application 标签的 process 属性,系统就会默认使用 package 的名称。每一个应用程序都有自己的 uid,因此,这里 uid + process 的组合就可以为每一个应用程序创建一个 ProcessRecord。每次在新建新进程前的时候会先判断这个 ProcessRecord 是否已存在,如果已经存在就不会新建进程了,这就属于应用内打开 Activity 的过程了。

进程创建成功切换至 App 进程,进入 app 进程后将 ActivityThread 类加载到新进程,并调用 ActivityThreadmain() 方法

此时只创建了应用程序的 ActivityThread 和 ApplicationThread,和开启了 Handler 消息循环机制,其他的都还未创建, ActivityThreadattach(false) 又会最终到 ActivityMangerService 的 attachApplication,这个工程其实是将本地的 ApplicationThread 传递到 ActivityMangerService。然后 ActivityMangerService 就可以通过 ApplicationThread 的代理 ApplicationThreadProxy 来调用应用程序 ApplicationThreadbindApplication,通知应用程序的 ApplicationThread 已和 ActivityMangerService 绑定,可以不借助其他进程帮助直接通信了。此时 Launcher 的任务也算是完成了。

在 system_server 进程中的服务端 ActivityManagerService 收到 ATTACH_APPLICATION_TRANSACTION 命令后进行处理,调用 attachApplication()。

发送送完 SCHEDULE_LAUNCH_ACTIVITY_TRANSACTION 命令,还会发送 BIND_APPLICATION_TRANSACTION 命令来创建 Application。

在 app 进程中,收到 BIND_APPLICATION_TRANSACTION 命令后调用 ActivityThreadbindApplication()。

ApplicationThreadProxybindApplication(…) 会传来这个应用的一些信息,如ApplicationInfo,Configuration 等,在 ApplicationThreadbindApplication 里会待信息封装成AppBindData,通过

将信息放到应用里的消息队列里,通过 Handler 消息机制,在 ActivityThreadhandleMeaasge 里处理 HBIND_APPLICATION 的信息,调用 AplicationThreadhandleBindApplication。

Instrumentation:

这时 Application 就创建好了,这点很重要,很多资料里说 Application 是在performLaunchActivity() 里创建的,因为 performLaunchActivity() 也有mInstrumentationnewApplication 这个调用,newApplication() 函数中可看出会先判断是否以及创建了 Application,如果之前已经创建,就返回已创建的 Application 对象。

上面 fork 进程时会发送 SCHEDULE_LAUNCH_ACTIVITY_TRANSACTION 命令,在 app 进程中,收到 SCHEDULE_LAUNCH_ACTIVITY_TRANSACTION 命令后调用 ApplicationThreadscheduleLaunchActivity()。

与 Window 进行关联,具体过程详见: Activity,Window,View 之间的关系

Activity 的整体启动流程如图所示:

先通过下面的getPackages()方法获得所有系统安装的应用,根据打印出来的日志找到你要找的应用的对应的包名,在调用startAppByPackageName()方法启动应用就可以了,主activity不需要的

private ArrayList<PInfo> getPackages() {

ArrayList<PInfo> apps = getInstalledApps();

final int max = appssize();

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

appsget(i)prettyPrint();

}

return apps;

}

class PInfo {

private String appname = "";

private String pname = "";

private String versionName = "";

private int versionCode = 0;

private Drawable icon;

private void prettyPrint() {

Loge("zhm",appname + "\t" + pname + "\t" + versionName + "\t" + versionCode);

}

}

private ArrayList<PInfo> getInstalledApps() {

ArrayList<PInfo> res = new ArrayList<PInfo>();

List<PackageInfo> packs = parentgetPackageManager()getInstalledPackages(0);

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

PackageInfo p = packsget(i);

if (pversionName == null) {

continue ;

}

PInfo newInfo = new PInfo();

newInfoappname = papplicationInfoloadLabel(parentgetPackageManager())toString();

newInfopname = ppackageName;

newInfoversionName = pversionName;

newInfoversionCode = pversionCode;

newInfoicon = papplicationInfoloadIcon(parentgetPackageManager());

resadd(newInfo);

}

return res;

}

public void startAppByPackageName(String packageName){

PackageInfo pi = null;

try {

pi = getPackageManager()getPackageInfo(packageName, 0);

} catch (NameNotFoundException e) {

eprintStackTrace();

}

Intent resolveIntent = new Intent(IntentACTION_MAIN, null);

resolveIntentaddCategory(IntentCATEGORY_LAUNCHER);

resolveIntentsetPackage(pipackageName);

List<ResolveInfo> apps = getPackageManager()queryIntentActivities(resolveIntent, 0);

ResolveInfo ri = appsiterator()next();

if (ri != null ) {

String packageName1 = riactivityInfopackageName;

String className = riactivityInfoname;

Intent intent = new Intent(IntentACTION_MAIN);

intentaddCategory(IntentCATEGORY_LAUNCHER);

intentaddFlags(IntentFLAG_ACTIVITY_NEW_TASK);

ComponentName cn = new ComponentName(packageName1, className);

intentsetComponent(cn);

startActivity(intent);

}

}

这个很简单,给你主要代码

PackageManager pm = getPackageManager(); // 得到PackageManager对象

// List<ApplicationInfo> packs = pmgetInstalledApplications(0); //

// 得到系统安装的所有程序包的PackageInfo对象

List<PackageInfo> packs = pmgetInstalledPackages(0); // 得到用户安装的所有程序包的PackageInfo对象

for (PackageInfo pi : packs) {

map = new HashMap<String, Object>();

// 显示用户安装的应用程序,而不显示系统程序

if ((piapplicationInfoflags & ApplicationInfoFLAG_SYSTEM) == 0

&& (piapplicationInfoflags & ApplicationInfoFLAG_UPDATED_SYSTEM_APP) == 0) {

// 这将会显示所有安装的应用程序,不包括系统应用程序

/

获得文件大小 publicSourceDir获得路径,再通过该路径创建一个文件new File(String dir),

得到该文件长度除以1024则取得该应用的大小。

取得程序大小,通过application的publicSourceDir获得。

取得程序时间,通过application的SourceDir获得。

/

String dir = piapplicationInfopublicSourceDir;

int size = IntegervalueOf((int) new File(dir)length());

long date = new Date(new File(dir)lastModified())getTime();

mapput("appName", piapplicationInfoloadLabel(pm));// 应用程序名称

mapput("icon", piapplicationInfoloadIcon(pm));// 图标

mapput("versionName", "版本 :" + piversionName);// 应用程序版本\

mapput("appSize2", size);// 应用程序大小

mapput("packages", piapplicationInfopackageName); // 应用程序包名

mapput("appSize", "大小 :" + ToSzie(size));// 应用程序大小

mapput("appDate", date);// 应用程序时间

itemsadd(map);

}

}

启动 :

String path ="package:"+vgetTag();

Uri packageURI = Uriparse(path);

Intent uninstallIntent = new Intent(this packageURI);

contextstartActivity(uninstallIntent);

解答如下:

魅族手机的"主题美化"里提供了各种各样的主题供用户下载使用,对于一些好看的主题图标,相信很多魅友都想把它们提取出来,然后保存好。然而魅族的主题包是经过特殊加密的,我们不能直接从主题包里提取。这里我介绍一种不用root权限的图标提取方法:

首先,我们要在主题美化里下载并应用自己喜欢的主题。

到魅族自带的“应用中心”搜索“魅包名”。

下载并安装好“魅包名

打开"魅包名",找到自己喜欢的图标的应用并单击它

在d出的界面中选择“上传图标”

这时可能会提示“网络错误”之类的提示语,没关系,这不影响图标提取。

接下来就是寻找图标文件了,我们要先打开系统自带的“文件管理”

打开如下地址“/sdcard/mpackageview/ignore/icons/”

这时你就可以找到刚才你提取出来的图标了,是png格式的文件哦

还有一个是用第三方应用的图标遮罩部分,命名为“icon_maskpng”,而图标背景名是“icon_backgroundpng”。

*** 作步骤:选一个(大小因为魅族各型号不一样,flyme4是240240)作为遮罩改成全透明,再选一个作为图标背景(大小和遮罩一样)。icons文件里不要制作任何第三方图标,把这两个放进icons文件里,打包制作成主题后应用,然后所有第三方图标都会变成之前作为图标背景的那张。

以上就是关于Android 从点击应用图标到界面显示的过程全部的内容,包括:Android 从点击应用图标到界面显示的过程、我想问一下,android开发时要引用第三方应用,我要怎么知道程序的入口包名和主Activity呢,比较急呢、Android获取到手机应用图标并显示在GridView中。现在想通过点击相应图标进入对应应用程序,应该怎么样实现等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/web/9333551.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-04-27
下一篇2023-04-27

发表评论

登录后才能评论

评论列表(0条)

    保存