《第一行代码》是学习 Android 的入门经典,该篇以一名 iOS 开发者的视角记录系统学习 Android 的点滴。
第一章 开始启程-你的第一行Android代码
Android 发展史
- 2003年10月,Andy Rubin 等人创办了Android 公司。
- 2005年8月,谷歌收购 Android 公司,并让 Android Rubin 继续负责 Android 项目。
- 2008年,谷歌终于推出了 Android 系统的第一个版本。
- 2010年,Linux 团队把 Android 从 Linux 内核主线中除名。
Android 的发展一直受到重重阻挠,乔布斯认为这是一个抄袭 iPhone 的产品,剽窃了诸多iPhone的创意,并声称一定要毁掉 Android。十几年过去了,iOS 和 Android 两个平台彼此各取所长(或者说抄袭),这对我们开发者和使用者是有益的。平台在进化,我们的技能和使用便利性都在提升。另外,甲骨文针对 Android 侵犯 Java 知识产权问题也向谷歌提起了诉讼。
Android 依然快速前进逐渐占据了全球智能手机操作系统 70% 以上的份额,因为谷歌的开放政策,任何厂商和个人都可以免费获取到 Android 系统源码,并随意使用和定制。
1.1 了解全貌-Android 王国介绍
接下来以一个开发者角度,了解一下这个操作系统。
1.1.1 Android 系统架构
Android 大致分为四层架构:
-
Linux 内核层
Android 系统基于 Linux 内核,内核层为设备硬件提供底层驱动,如:显示驱动、音频驱动、相机驱动、蓝牙驱动、Wifi 驱动、电源管理驱动等。
-
系统运行库层
该层包含两种库:
- C/C++ 库为系统提供主要特性支持,如:SQLite 库提供数据支持、OpenGL|ES 库提供3D绘图支持、WebKit 库提供浏览器内核支持等。
- Android 运行时库,如:核心库允许开发者使用 Java 编写 Android 应用、Dalvik 虚拟机(5.0后改为ART运行环境,为移动定制针对手机内存、CPU 性能有限等情况作了优化)使得每一个 Android 应用都能运行在独立的进程中。
-
应用框架层
这一层提供了构建App可能用到的API,如:XMPP服务、活动管理、窗口管理、视图管理、通知管理、包管理等
-
应用层 所有安装在手机上的App都属于这一层,如:短信、联系人、微信、支付宝等
1.1.2 Android已发布的版本
- 2008年9月 Android 1.0 最早的系统版本
- 2011年2月 Android 3.0 转为平板电脑设计的比较失败而版本
- 2011年10月Android 4.0 不再区分平板和手机,可在两种设备上应用
- 2014年I/O大会 Android 5.0 史上版本改动最大,ART运行环境替代了Dalvik虚拟机,提升了运行速度,并提出了Material Design概念来优化界面设计。并推出了Android Wear系统向可穿戴设备进发。
- 2015年I/O大会 Android 6.0系统,加入运行时权限功能
- 2016年I/O大会 Android 7.0系统,加入多窗口模式
最新数据可访问:(developer.android.google.cn/about/dashb…)
1.1.3 Android应用开发特色
首先看一下Android系统提供了哪些东西,可供我们开发出优秀的App。
-
四大组件
活动(Activity):所有应用的门面、应用中能看到的东西都放在活动中。
服务(Service) :不可见、但会在后台一直默默运行,即使退出应用服务依然可继续运行。
广播接收器(Broadcast Receiver):允许你的应用接收各种广播消息,如电话短信等,你的应用也可以发出广播消息。
内容提供器(Content Provider):为应用程序间共享数据提供支持,如读取电话簿中联系人
-
丰富的系统控件
搭建界面的基础单元,也可自定义
- SQLite数据库
轻量级、运算速度极快的嵌入式关系型数据库
- 强大的多媒体
Android系统提供了API以访问多媒体服务,如:音乐、视频、录音、拍照、闹钟等
- 地理位置定位
Android手机都内置有GPS,结合地图功能,LBS领域潜力无限
1.2 手把手带你搭建开发环境
现在都是用Android Studio开发,使用Mac搭建环境会遇到以下两个问题:
- 官网下载最新安装包:developer.android.com/studio
- 会遇到以下问题:
-
Unable to access Android SDK add-on list
解决方法:在 Android Studio 安装目录 bin/idea.properties 文件最后追加一句:disable.android.first.run=true
-
Your Android SDK is missing, out of date or corrupted
-
studio Connection refused (Connection refused)
解决方法:www.jianshu.com/p/dc12c965a… 我的配置当时删除了: systemProp.http.proxyHost=127.0.0.1 systemProp.https.proxyPort=8118 systemProp.https.proxyHost=127.0.0.1 systemProp.http.proxyPort=8118
1.3 创建第一个 Android 项目
比较简单,一步步操作即可。主要关注创建后的项目是怎么运行起来的。
- 先看 AndroidManifest.xml 文件,可看到如下代码
<activity android:name=".HelloWorldActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
这段配置,表示对 HelloWorldActivity 这个活动进行注册,没有在该配置文件里注册的活动是不能使用的。
intent-filter 中的两个配置分别 xxx.MAIN 和 xxx.LAUNCHER 表示该活动是这个项目的主活动,点击 APP 图标,首先启动的就是这个活动。
- 既然 HelloWorldActivity 是主活动,我们看一下它的代码
public class HelloWorldActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.hello_world_layout);
}
}
介绍四大组件的时候讲过,活动是App的门面,凡是所见的皆是在活动中。我们启动该项目后在手机中看到的界面,其实就是在 HelloWorldActivity 活动中的。
代码中可看到 HelloWorldActivity 继承自 AppCompatActivity,Compat 有兼容之意 AppCompatActivity 是一种向下兼容的 Activity ,最低支持 2.1 系统。
然后,可以看到有一个 onCreate 方法,这个方法是一个活动被创建时要执行的。Android 程序设计讲究视图和逻辑分离,因此不推荐在 Activity 中直接写界面。通用的方式如代码所示通过 setContentView(),传入一个 layout 即可。 layout 有布局、设计之意,它既包含视图元素也包含布局信息。
- 接下来看一下 hello_world_layout.xml 这个 Layout 文件
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/hello_world_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.helloworld.HelloWorldActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
/>
</RelativeLayout>
这个文件在 res/layout 目录中,在这里可以看到界面展示的 HelloWorld!字样是在 TextView 控件中配置的。
1.3.5 项目中的核心资源解读
- res 中的目录资源
res/values/strings 用以配置项目中使用的字符串资源信息
<resources>
<string name="app_name">HelloWorld</string>
</resources>
使用场景有两种:
- 代码中:R.string.app_name 可获得该字符串引用
- XML中 :@string/app_name
string 部分是可替换的,如果要使用图片资源换成 drawable,图标就用 mipmap,布局文件是layout。
看一下 AndroidManifest.xml 文件,主要关注对资源的访问方式
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
...
</application>
1.3.6 详解 build.gradle 文件
Android Studio 是采用 Gradle 来创建项目的。Gradle是一个非常先进的项目构建工具,使用了一种基于 Groovy 的领域特定语言(DSL)来声明项目设置,摒弃了传统的基于 XML (如 Ant 和 Maven)的各种琐碎配置。
HelloWorld 项目中有两个 build.gradle 文件,一个是在最外层目录下,一个是在 app 目录下。两个文件都很重要,需要认真掌握
- 最外层目录下的 build.gradle 文件 代码如下:
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.2.0'
}
}
allprojects {
repositories {
jcenter()
}
}
首先,看一下 jcenter,它是一个代码托管仓库,很多开源项目会托管在 jcenter 上,声明了 jcenter() 后就可以在项目中轻松引用任何 jcenter 上的开源项目了。
然后,classpath 声明了一个 Gradle 插件。之所以声明该插件,是因为 Gradle 并非只为构建 Android 项目而开发,java、c++ 等很多项目都可使用 Gradle 来构建。
- app 目录下的 build.gradle 文件
代码如下:
apply plugin: 'com.android.application'
android {
compileSdkVersion 24
buildToolsVersion "24.0.2"
defaultConfig {
applicationId "com.example.helloworld"
minSdkVersion 15
targetSdkVersion 24
versionCode 1”
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'),
'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:24.2.1'
testCompile 'junit:junit:4.12'
}”
首先,看第一行 apply plugin 配置,该插件配置有两种值可选:
-
com.android.application
表示是一个应用程序模块,可运行
-
com.android.library
表示是一个库模块,不可运行只能作为代码库依附于某个应用程序模块来运行
接下来,是 Android 的闭包,该闭包中可配置项目构建的各种属性。
-
compileSdkVersion 用以指定项目的编译版本,24 表示使用 Android 7.0 系统的 SDK 编译。
-
buildToolsVersion 用于支付那个项目构建工具的版本
-
defaultConfig 闭包,可对项目更多细节进行配置:
applicationId 用于指定项目的包名
minSdkVersion 用于指定项目兼容的最低 Android 系统版本
targetSdkVersion 用于指定充分测试过的系统版本,高于该系统版本引入的新功能不会启用。
versionCode 用于指定版本号
versionName 用于指定版本名
-
buildTypes 闭包, 用于指定生成安装文件的相关配置,通常只会有两个子闭包:
-
debug 闭包,指定生成测试版安装文件的配置
该闭包,可忽略不写
-
release 闭包,指定生成正式版安装文件的配置
minifyEnabled 用于指定是否对项目代码进行混淆 proguardFiles 用于指定混淆使用的规则文件。proguard-android.txt 是在 Android SDK 目录下,是所有项目的通用混淆规则。proguard-rules.pro 是在当前项目的根目录下,可编写当前项目的混淆规则。
-
最后,还剩下一个 dependencies 闭包,它用于指定当前项目的所有依赖关系,通常 Android Studio 项目有以下3种依赖方式:
-
本地依赖
可对本地的 jar 包或目录添加依赖关系,第一行的 compile fileTree 就是一个本地依赖声明,表示将 libs 目录下所有的 .jar 后缀的文件都添加到项目的构建路径中。
-
库依赖
可对项目中的库模块添加依赖关系
-
远程依赖
可对 jcenter 库上的开源项目添加依赖关系,第二行的 compile 是远程依赖声明,com.android.support:appcompat-v7:24.2.1 是一个标准的远程依赖库格式,其中com.android.support 是域名部分,用于和其它公司的库作区分;appcompat-v7 是组名称,用于和同一个公司中不同的库做区分;24.2.1 是版本号,用于和同一个库的不同版本作区分。
testCompile 用于声明测试用例库,暂时忽略。
1.4 前行必备-掌握日志工具的使用
Log 工具类的五个重载方法:
- Log.v() 对应 verbose 级别,级别最低,用于打印最为琐碎、意义最小的日志信息
- Log.d() 对应 debug 级别,比 verbose 高一级,用于打印调试信息
- Log.i() 对应 info 级别,比 debug 高一级,用于打印一些比较重要的数据,这些数据是你非常想看到的、可以帮你分析用户行为的数据
- Log.w() 对应 warn 级别,比 info 高一级,用于打印一些警告信息,这些警告提示程序在某个地方会有潜在风险,最好去修复一些这些出现警告的地方
- Log.e() 对应 error 级别,比 warn 高一级,用于打印程序中的错误信息,比如程序进度到了 catch 语句中。当有 error 信息打印的时候,一般代表程序出现了严重问题,必须尽快修复
用法举例如下
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.hello_world_layout);
Log.d("HelloWorldActivity", "onCreate execute");
}
相关快捷键
- 方法中输入 logd ,按下 Tab 健,会补全一条完整打印语句,以此类推logi、loge、logw等均可
- Log的所有打印要求传入一个 tag 参数,可在方法外输入 logt,按下 Tab 健,这是会自动生成一个 Tag 常量,如下所示
public class HelloWorldActivity extends AppCompatActivity {
private static final String TAG = "HelloWorldActivity";
...
}
小结
在iOS开发中,首先要解决项目目录结构问题,日志的分级上报也需要自己开发,这些在 Android 开发中不需要考虑的,平台已经提供了合理的目录分组和便捷的日志系统。另外,视图分离问题 Android 也提供了优秀的 layout 设计,这种设计清晰且便于开发者使用。