http://blog.csdn.net/mdx20072419/article/details/9632779/

launcher,也就是android的桌面应用程序。下图是我正在使用的魅族手机的launcher应用程序:

接下来我们要开发一个自己的launcher,使其替代系统的默认launcher。
怎样使我们的应用程序成为一个launcher?

首先我们要有一个自己的Android应用,在这里,我使用最简单的应用程序Hello,

使用eclipse创建Android项目我这里就省略了,直接上图

来看看我的AndroidManifest.xml

[cpp] view plain copy print?
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"
  3. package="com.example.hello"
  4. android:versionCode="1"
  5. android:versionName="1.0" >
  6. <uses-sdk
  7. android:minSdkVersion="7"
  8. android:targetSdkVersion="7" />
  9. <application
  10. android:allowBackup="true"
  11. android:icon="@drawable/ic_launcher"
  12. android:label="@string/app_name"
  13. android:theme="@style/AppTheme" >
  14. <activity
  15. android:name="com.example.hello.MainActivity"
  16. android:label="@string/app_name" >
  17. <intent-filter>
  18. <action android:name="android.intent.action.MAIN" />
  19. <category android:name="android.intent.category.LAUNCHER" />
  20. </intent-filter>
  21. </activity>
  22. </application>
  23. </manifest>
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.example.hello"android:versionCode="1"android:versionName="1.0" ><uses-sdkandroid:minSdkVersion="7"android:targetSdkVersion="7" /><applicationandroid:allowBackup="true"android:icon="@drawable/ic_launcher"android:label="@string/app_name"android:theme="@style/AppTheme" ><activityandroid:name="com.example.hello.MainActivity"android:label="@string/app_name" ><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity></application></manifest>

我们知道,一个应用程序可以有多个Activity,每个Activity是同级别的。那么在启动程序时,最先启动哪个Activity呢?有些程序可能需要显示在程 序列表里,有些不需要。怎么定义呢?android.intent.action.MAIN决定应用程序最先启动的Activity ,android.intent.category.LAUNCHER决定应用程序是否显示在程序列表里。Main和LAUNCHER同时设定才有意义,如果有多个同级的Activity都有过滤器
<intent-filter>
 <action android:name="android.intent.action.MAIN" />
 <category android:name="android.intent.category.LAUNCHER" />
< /intent-filter>
   则只有最前面的Activity的 <action android:name="android.intent.action.MAIN" /> 有 效,启动该程序时,执行的是该Activity。且在程序列表中有多个图标,这些Activity都在程序列表中显示,该Application有多个入 口,执行不同的Activity,但是整个程序的主入口(整个程序最先运行的那个activity)只有最先定义的那个Activity。

如 果一个应用没有LAUNCHER则该apk仍能安装到设备上,但是在主程序图中看不到。如果给那个Activity 设定了LAUNCHER,且同时设定了Main,则这个Activity就可出现在程序图中;如果没有Main,则不知启动哪个Activity,故也不 会有图标出现。

那如果我们要把一个应用程序做为桌面应用程序,该怎么办呢?

如果了解Android的启动流程的同学都知道,Zygote启动SystemServer,SystemServer的main函数开始启动各种服务。 首先启动init1,然后启动init2. init1这个方法是被Zygote调用来初始化系统的,init1会启动native的服务如SurfaceFlinger,AudioFlinger等等,这些工作做完以后会回调init2来启动Android的service。

[cpp] view plain copy print?
  1. public static final void init2() {
  2. 501         Log.i(TAG, "Entered the Android system server!");
  3. 502         Thread thr = new ServerThread();
  4. 503         thr.setName("android.server.ServerThread");
  5. 504         thr.start();
  6. 505     }
public static final void init2() {
501         Log.i(TAG, "Entered the Android system server!");
502         Thread thr = new ServerThread();
503         thr.setName("android.server.ServerThread");
504         thr.start();
505     }

init2中启动ServerThread线程,ServerThread中启动了一系列的服务,比如ActivityManagerService,EntropyService等等。

当这些服务起来以后,开始  ((ActivityManagerService)ActivityManagerNative.getDefault()).systemReady() 在systemReady后开始开始启动Launcher。

frameworks\base\services\java\com\android\server\am\ActivityManagerService.java

[cpp] view plain copy print?
  1. 8422     public void systemReady(final Runnable goingCallback) {
  2. 8423         // In the simulator, startRunning will never have been called, which
  3. 8424         // normally sets a few crucial variables. Do it here instead.
  4. .........................
  5. 8594           resumeTopActivityLocked(null);
  6. }
8422     public void systemReady(final Runnable goingCallback) {
8423         // In the simulator, startRunning will never have been called, which
8424         // normally sets a few crucial variables. Do it here instead. .........................
8594           resumeTopActivityLocked(null);}

frameworks\base\services\java\com\android\server\am\ActivityManagerService.java

[cpp] view plain copy print?
  1. 2576     private final boolean resumeTopActivityLocked(HistoryRecord prev) {
  2. 2577         // Find the first activity that is not finishing.
  3. 2578         HistoryRecord next = topRunningActivityLocked(null);
  4. 2579
  5. 2580         // Remember how we'll process this pause/resume situation, and ensure
  6. 2581         // that the state is reset however we wind up proceeding.
  7. 2582         final boolean userLeaving = mUserLeaving;
  8. 2583         mUserLeaving = false;
  9. 2584
  10. 2585         if (next == null) {
  11. 2586             // There are no more activities!  Let's just start up the
  12. 2587             // Launcher...
  13. 2588             return startHomeActivityLocked();
  14. 2589         }
 2576     private final boolean resumeTopActivityLocked(HistoryRecord prev) {                       2577         // Find the first activity that is not finishing.2578         HistoryRecord next = topRunningActivityLocked(null);2579 2580         // Remember how we'll process this pause/resume situation, and ensure2581         // that the state is reset however we wind up proceeding.2582         final boolean userLeaving = mUserLeaving;2583         mUserLeaving = false;2584 2585         if (next == null) {2586             // There are no more activities!  Let's just start up the2587             // Launcher...2588             return startHomeActivityLocked();2589         }

frameworks\base\services\java\com\android\server\am\ActivityManagerService.java

[cpp] view plain copy print?
  1. 2457     private boolean startHomeActivityLocked() {
  2. 2458         if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
  3. 2459                 && mTopAction == null) {
  4. 2460             // We are running in factory test mode, but unable to find
  5. 2461             // the factory test app, so just sit around displaying the
  6. 2462             // error message and don't try to start anything.
  7. 2463             return false;
  8. 2464         }
  9. 2465         Intent intent = new Intent(
  10. 2466             mTopAction,
  11. 2467             mTopData != null ? Uri.parse(mTopData) : null);
  12. 2468         intent.setComponent(mTopComponent);
  13. 2469         if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
  14. 2470             intent.addCategory(Intent.CATEGORY_HOME);
  15. 2471         }
 2457     private boolean startHomeActivityLocked() {                                               2458         if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL2459                 && mTopAction == null) {2460             // We are running in factory test mode, but unable to find2461             // the factory test app, so just sit around displaying the2462             // error message and don't try to start anything.2463             return false;2464         }2465         Intent intent = new Intent(2466             mTopAction,2467             mTopData != null ? Uri.parse(mTopData) : null);2468         intent.setComponent(mTopComponent);2469         if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {2470             intent.addCategory(Intent.CATEGORY_HOME);2471         }

frameworks/base/core/java/android/content/Intent.java

[cpp] view plain copy print?
  1. 1881     public static final String CATEGORY_HOME = "android.intent.category.HOME";
1881     public static final String CATEGORY_HOME = "android.intent.category.HOME";  

根据上面代码可知,在寻找Launcher的时候是根据HOME的filter(在Manifest中定义的<category android:name=”android.intent.category.HOME” />)来过滤。 然后根据filter出来的HOME来启动,如果只有一个HOME,则启动这个HOME,如果用户自己装了HOME,那就会弹出来一个列表供用户选择。

既然如此,我们现在就可以更改我们的AndroidManifest.xml来安装自己的HOME。所以我们只需在AndroidManifest.xml添加两行代码:

[cpp] view plain copy print?
  1. <category android:name="android.intent.category.HOME" />
  2. <category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.HOME" />
<category android:name="android.intent.category.DEFAULT" />  

现在重新编译我们的应用程序,把编译生成的APK放到相应的目录下,一般是/system/app,启动开发板,我们可以看到在我们的LCD屏上面,要求用户选择launcher。

到这里,我们不禁要想,如果我们从这里弹出我们自己定制的Launcher,但同时不弹出选择HOME的界面,我们也不希望用户修改我们的home,比如我们的home上放了好多广告,以及强制安装的程序,不希望用户把它干掉。

在这里,我们就可以写一个自己私有的filter选项,然后用这个选项来过滤HOME. 一般情况下我们使用Manifest中定义的<category android:name="android.intent.category.HOME"来过滤的,我们现在增加一个私有的FS_HOME过滤。

这里我们有一种比较暴力的更改方法,就是把系统中原有的public static final String CATEGORY_HOME = "android.intent.category.HOME";

更改成public static final String CATEGORY_FS_HOME = "android.intent.category.FS_HOME";

然后修改和CATEGORY_HOME相关的所有的地方,都改成CATEGORY_FS_HOME.如果不知道修改哪些地方,可以使用如下命令去查找:

[cpp] view plain copy print?
  1. grep  CATEGORY_HOME  -l  *  -R
grep  CATEGORY_HOME  -l  *  -R

查找到的文件大概有这些:


将上述文件中和CATEGORY_HOME相关的所有的地方,都改成CATEGORY_FS_HOME即可。

然后,我们可以把之前的应用程序hello的AndroidManifest.xml更改如下:

[cpp] view plain copy print?
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"
  3. package="com.example.hello"
  4. android:versionCode="1"
  5. android:versionName="1.0" >
  6. <uses-sdk
  7. android:minSdkVersion="7"
  8. android:targetSdkVersion="7" />
  9. <application
  10. android:allowBackup="true"
  11. android:icon="@drawable/ic_launcher"
  12. android:label="@string/app_name"
  13. android:theme="@style/AppTheme" >
  14. <activity
  15. android:name="com.example.hello.MainActivity"
  16. android:label="@string/app_name" >
  17. <intent-filter>
  18. <action android:name="android.intent.action.MAIN" />
  19. <category android:name="android.intent.category.FS_HOME" />
  20. <category android:name="android.intent.category.DEFAULT" />                                                                        <category android:name="android.intent.category.MONKEY" />
  21. </intent-filter>
  22. </activity>
  23. </application>
  24. </manifest>
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.example.hello"android:versionCode="1"android:versionName="1.0" ><uses-sdkandroid:minSdkVersion="7"android:targetSdkVersion="7" /><applicationandroid:allowBackup="true"android:icon="@drawable/ic_launcher"android:label="@string/app_name"android:theme="@style/AppTheme" ><activityandroid:name="com.example.hello.MainActivity"android:label="@string/app_name" ><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.FS_HOME" /> <category android:name="android.intent.category.DEFAULT" />                                                                        <category android:name="android.intent.category.MONKEY" /> </intent-filter></activity></application></manifest>

重新编译我们的应用程序,放到我们开发板相应目录下,就可以看到我们自己的Launcher了!

Android更改桌面应用程序launcher的两种方式相关推荐

  1. rk修改launcher_Android更改桌面应用程序launcher的两种方式

    http://blog.csdn.net/mdx20072419/article/details/9632779/ launcher,也就是android的桌面应用程序.下图是我正在使用的魅族手机的l ...

  2. 返回键捕获 应用程序退出的两种方式(转)

    作为应用程序一个较好的用户体验应该是:在退出应用程序前询问用户是否真正退出?目前普遍做法是,一在退出前询问是否真正退出,二是连续按两下退出. 返回键捕获 应用程序退出的两种方式 实现上述两种应用退出方 ...

  3. java制作oracle程序,Java程序操作Oracle两种方式之简单实现

    Java程序操作Oracle两种方式之简单实现 1.通过JDBC-ODBC桥连接Oracle数据库 (1)创建odbc源,在控制面板->管理工具->数据源(odbc)中添加DSN,比如取名 ...

  4. STM32_基础入门_程序下载的两种方式

    一.ISP串口下载 1.所涉及工具:MDK+FlyMcu 2.硬件连接 3.连接步骤 1.搜索并选择对应串口 2.选择要下载的hex文件,将"编程前重装文件"打勾 3.勾选&quo ...

  5. 【小程序登录的两种方式】

    小程序登录的两种方式 账号密码登录 获取小程序授权登录 账号密码登录 app.json页面顺序 先进入首页 有token就是首页 没有token时redirectTo登录页 {"pages& ...

  6. Android实现资源动态加载的两种方式

    这是Android Apk源加载机制原理分析以及动态加载实现系列文章 的最后一篇.经过前两篇的介绍之后,相关基础都讲的差不多了,现在要实现自己项目中的资源加载框架,这里提供两种方式,区别在于由谁来加载 ...

  7. android数据库侵入,Android中实现侵入式状态栏的两种方式

    最近对"爸比讲故事"Android版本进行代码重构的时候,对之前版本的大部分界面的头部侵入式效果,作了一个总结和梳理,在期间查阅了thinkcool的博客和结合亲身实践,总结了2种 ...

  8. python程序执行的两种方式_012.执行Python程序的两种方式

    一.执行Python程序的两种方式 1.1 交互式 在终端内输入python3,然后输入python代码 交互式环境下,敲完一条命令按下enter键马上能看到结果,调试程序方便.程序无法永久保存,关掉 ...

  9. Android studio中TextView改变字体的两种方式(如仿宋、隶书)

    在Android中系统默认的字体有三种,通过在TextView中加上android:typeface="sans"来改变,而sans就是三种当中的其中的一种,还有两种分别是&quo ...

最新文章

  1. Oracle脚本批量导入时,输出日志文件
  2. 控制台应用程序的根目录
  3. 江苏c语言二级试题及答案,江苏省计算机二级C语言试题及答案.doc
  4. __FUNCTION__, __FILE__, __LINE__ (原)
  5. ListView控件的弧形设计
  6. Java构造函数执行顺序
  7. YGC 问题排查,又涨姿势了!
  8. 服务器响应submit,任务操作:submitJob (REST)
  9. lisp画表盘刻度线_Lisp-Stat翻译 —— 第九章 统计绘图窗体
  10. shuipFCMS收集2
  11. android软路由,软路由体验 篇一:  100块钱还要啥自行车,软路由初体验
  12. cad断点快捷键_入门CAD必备,如何有效记住CAD快捷键
  13. shui0418笔记
  14. stata foreach循环语句的使用
  15. 【Android】SD卡的安全存储问题
  16. 全网舆情监测系统功能板块具体详介
  17. 别再漫无目的分析数据,手把手教你学会,如何体系化搭建数据指标
  18. 用帝国主义竞争算法(ICA)求解旅行商问题(TSP)(Matlab代码实现)
  19. LXC、LXD、Docker的区别与联系(by quqi99)
  20. mac修改shell

热门文章

  1. mpvue 初始化微信小程序
  2. python之修改pip为阿里源
  3. inception mysql 使用_mysql 审核引擎 goInception 的基本使用
  4. 机器视觉硬件选型——镜头选型
  5. Python面向对象——继承
  6. Unity Android记录
  7. 用python写出九九乘法表
  8. 实验四恶意代码分析技术 201421430029
  9. OLAP-impala-大数据Week13-DAY6-impala
  10. SpringBoot实战总汇--详解