简单练手的Launcher(一)

文章目录

  • 前言
  • Launcher介绍
  • 目标效果
  • 开发环境
  • 实现
    • 1.新建一个项目
      • 1.1.去掉标题栏
      • 1.2.设置分类
        • 关于intent
    • 2.选择布局方案
    • 2.1.整体布局设计
    • 2.2.主界面布局设计
    • 2.3.APP层的设计
        • APP的布局
        • 页指示布局
    • 2.4.页动画效果层
    • 2.5.浮动图标层
  • 总结

前言

最近想系统的学习android,无奈之前的基础太差(linux),所以算是一切从头开始学习。

从Android的启动流程开始,到Launcher这边的时候,看了Launcher3的一点源码分析,因为不懂android框架API和java的一些语法,大多看的云里雾里的。所以想自己做一个简单的Launcher练练手。因为Launcher说到底还是个APP,也顺遍学习学习android应用的开发。

趁着元旦假期和后面的两三个周末时间,自娱自乐勉勉强强做了一个能看的Launcher。怕脑子有点不好使,看过的东西回忘,为了方便还是把整个过程和思路及要点都理一下,很多东西都是东拼西凑边写边做的。

由于不太懂JAVA的语法加上第一次接触android应用,Launcher3的我也没借鉴太多,很多东西都是我按自己的套路来套的(甚至一些语言上命名习惯上也一时难以纠正),所以一些错误的思路和方案选择在所难免,主要目的还是在于可以入门了解Android应用开发为主。。

下面的讲解,不会去分析自己的代码,因为没有意义,着重还是在于理思路,以及总结过程需要用到的知识点。其实中间很多地方,很多原理摊开来讲都很多,这里为了方便就不细讲了,其实很多我也没有去细究过甚至有点自己被绕进去了的感觉,不过方向就在那里,查一下也很方便。

内容实现较多,所以分了几篇,先搭上个电梯:

代码上传GITHUB:

Launcher介绍

写Launcer之前需要了解什么是Launcher。

Google 即时桌面与其他的桌面/启动器应用基本功能无异,可以用来启动其他应用,用户也可以在 Google 即时桌面中随意设置 Widget 以及其他样式。同时拥有一个应用抽屉,用以显示用户安装的所有应用。

Launcher的介绍:

https://juejin.im/entry/580088a8bf22ec0064c1884e

https://blog.csdn.net/dddxxxx/article/details/78708971

因为这里只是单纯写一个APP,还没有讨论到定制系统的Launcher的问题,所以这个暂时放到一边。(本来还误认为把setting也以为是Launcher的一部分,把虚拟键也认为是Launcher的一部分,现在看来感觉有点蠢了)

从大致的介绍上看,最主要的功能还是显示APP,打开卸载操作APP等。因为Launcher本身就是可以定制的,然后很多功能效果都是可以自己加的。为了简化程序,就照着旁边一个会议电视机的Launcher的效果(去了一些麻烦的和没看出逻辑的效果),做了一个简易版本的。

目标效果

首先Launcher整体的结构分为两层,第一层放置着一些常用的APP图标和日期时间的显示。

第二层类似于Launcher中的抽屉,放置APP。

  • 多页放置APP应用
  • 左右滑动进行翻页,同时有跟随滑动的效果
  • 下方有个页指示来说明当前处于哪一页
  • APP图标点击释放,将打开APP,同时产生图标放大效果
  • APP长按进入卸载移动模式,抖动效果提示
  • 进入卸载移动模式后,选择APP图标,可以移动APP
  • 移动APP的过程中原图标消失,产生一个缩略图,指示最近的图标在某个位置替换区域提示。
  • 移动APP支持跨页移动。当放在左右边缘一定时间后自动切换到上一页或下一页
  • 移动APP抬手后会自动替换到抬手区域,如果抬手区域内有APP图标了,则该位置上的APP和原位置APP替换
  • 替换APP后,重启Launcher, APP的位置将和上次退出时一致
  • APP进入抖动的效果的同时左上角会出现一个X,选择则进行对APP的卸载提示框,来引导用户进行卸载功能
  • 页管理器,实现对页的增加和删除功能,因为时间原因暂时没做

开发环境

支持Android 5.1以上的。

开发工具:Android Studio

屏幕大小应该没什么关系,我的想法基本是按分辨率自适应的。

实现

1.新建一个项目

新建一个环境没什么特别的,按一般的android工程建就好了。
需要注意两点。

1.1.去掉标题栏

因为我建了一个新项目是空项目,头顶上的那个标题栏看着很难受,而且Launcher不需要,所以需要把他删了。

网上的大多方法是修改Android——res——styles.xml的样式。在sytle的标签下新加了一个item的标签,如下:

true

整体来说看到这里,大概可以理解成android的样式和代码是分开的,而我们开发通过XML来方便的设置布局,那么以一定也有个解析其解析出参数传入框架。

注:这里可以也可以设置背景为透明,但本身我就想固定整个背景了,所以就不修改了

1.2.设置分类

这个分类是一定要设置的,后面替换Launcher会用到。
从AOSP的源码中可知道,读取 在桌面应用的时候会使用intent_filter找出类型是HOME的APP。所以把这个改了,然后重新启动板卡就会出现2个桌面应用,一个是系统自带的,还有就是这个launcher.

系统启动这里Launcher有个过程,大概是从init到启动Zygote,Zygote调AndroidRuntimeStart这个方法,里面会fork一个system_server的紫禁城,在通过反射调用启动SystemSercer。这里面会做很多很多工作,像加载JNI,启动Android服务等,然后里面有个ActivityMangerService它会启动调用第一个App:Launcher。

boolean startHomeActivityLocked(int userId) {
    if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL
            && mTopAction == null) {
        // We are running in factory test mode, but unable to find
        // the factory test app, so just sit around displaying the
        // error message and don't try to start anything.
        return false;
    }
    Intent intent = getHomeIntent();
    ActivityInfo aInfo =
        resolveActivityInfo(intent, STOCK_PM_FLAGS, userId);
    if (aInfo != null) {
        intent.setComponent(new ComponentName(
                aInfo.applicationInfo.packageName, aInfo.name));
        // Don't do this if the home app is currently being
        // instrumented.
        aInfo = new ActivityInfo(aInfo);
        aInfo.applicationInfo = getAppInfoForUser(aInfo.applicationInfo, userId);
        ProcessRecord app = getProcessRecordLocked(aInfo.processName,
                aInfo.applicationInfo.uid, true);
        if (app == null || app.instrumentationClass == null) {
            intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
            mStackSupervisor.startHomeActivity(intent, aInfo);
        }
    }

    return true;
}

修改使之成为默认启动APP的地方在AndroidManifest.xml文件里,增加:

 
    
        
        
        
    

参考:

CATEGORY_HOME

added in API level 1

public static final String CATEGORY_HOME

This is the home activity, that is the first activity that is displayed when the device boots.

Constant Value: “android.intent.category.HOME”

https://developer.android.com/reference/android/content/Intent#CATEGORY_DEFAULT

官方给的解释是CATEGORY_HOME是设备启动的第一个activity。

关于intent

这里特地研究一下这个intent的东西,总体概括为:多个activity间的通信方式。后面还会说到包管理器和intent过滤器的联合使用。

可以参考:

https://developer.android.com/reference/android/content/Intent

https://developer.android.com/guide/components/intents-filters?hl=zh-cn

2.选择布局方案

这里关于什么是布局和设置布局就不细说了,我直接在android下的app–res–layout里面的XML文件直接设置了,语法就是XML的语法,就是标签和属性是特定的一些,查文档就可以了,算事比较好理解。此外,底下的TEXT是对应的XML图,DESIGN对应的是预览,也可以直接在上面拖控件和布局。我这里之前会出现XML的DESIGN无法预览的情况。

解决方法是将Style中的style标签下的parent属性前部分加一个“Base.”