• Android更改桌面应用程序launcher的两种方式


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


     

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

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

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



       来看看我的AndroidManifest.xml


     

    <?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-sdk
            android:minSdkVersion="7"
            android:targetSdkVersion="7" />
    
        <application
            android:allowBackup="true"
            android:icon="@drawable/ic_launcher"
            android:label="@string/app_name"
            android:theme="@style/AppTheme" >
            <activity
                android: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。


     

    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。

    frameworksaseservicesjavacomandroidserveramActivityManagerService.java

     

     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);                                                                                         }

    frameworksaseservicesjavacomandroidserveramActivityManagerService.java

     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 ensure
     2581         // 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 the
     2587             // Launcher...
     2588             return startHomeActivityLocked();
     2589         }

    frameworksaseservicesjavacomandroidserveramActivityManagerService.java

     2457     private boolean startHomeActivityLocked() {                                               
     2458         if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
     2459                 && mTopAction == null) {
     2460             // We are running in factory test mode, but unable to find
     2461             // the factory test app, so just sit around displaying the
     2462             // 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

    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添加两行代码:

       

    <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_HOME = "android.intent.category.FS_HOME";

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

     

    grep  CATEGORY_ HOME  -l  *  -R

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


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


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


     

    <?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-sdk
            android:minSdkVersion="7"
            android:targetSdkVersion="7" />
    
        <application
            android:allowBackup="true"
            android:icon="@drawable/ic_launcher"
            android:label="@string/app_name"
            android:theme="@style/AppTheme" >
            <activity
                android: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了!

  • 相关阅读:
    单例模式
    Curator Zookeeper分布式锁
    LruCache算法原理及实现
    lombok 简化java代码注解
    Oracle客户端工具出现“Cannot access NLS data files or invalid environment specified”错误的解决办法
    解决mysql Table ‘xxx’ is marked as crashed and should be repaired的问题。
    Redis 3.0 Cluster集群配置
    分布式锁的三种实现方式
    maven发布项目到私服-snapshot快照库和release发布库的区别和作用及maven常用命令
    How to Use Convolutional Neural Networks for Time Series Classification
  • 原文地址:https://www.cnblogs.com/aukle/p/3228843.html
Copyright © 2020-2023  润新知