
[转] 一篇文章看明白 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中。现在想通过点击相应图标进入对应应用程序,应该怎么样实现等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)