《第一行代码》读书笔记——第一章:开启行程

1.1 开启行程

其实该书中的知识点都是一些基础的知识, 并不是很难, 许多知识点自己也知道,但是总感觉自己掌握的知识点比较零碎,不是很系统,所以想通过这本书系统的学习以下android的基础知识。

自己将阅读过程中的所感所想总结成博客的目的是什么呢? 虽然这本书的许多知识点比较基础,但是如果让自己写一本书讲让别人看,恐怕自己也写不出来? 如何能像作者写的那样通俗易懂呢,除了对知识点有深入的理解之外, 还需要有很好的写作能力与表达能力,这也是自己需要提高的一个方面。

1.1 Android发展史

1.1.1 Android发展史及已发布的版本号

Android系统最早是由安迪·鲁宾等人创立,该系统最早的目标是为了利用Android创建一个能够与PC联网的“智能相机”世界,公司的名字就叫做Android。 谷歌公司在2005收购了这个仅成立22月的公司。

2007年11月5日,谷歌公司正式向外界展示了这款名为Android的操作系统,并且在这天谷歌宣布建立一个全球性的联盟组织,该组织由34家 手机制造商、软件开发商、电信运营商以及芯片制造商共同组成,这其中就有我们熟悉的HTC 、中国移动、高通、三星等企业。这一联盟将支持该操作系统,共同开发Android系统的开源代码。 因此,htc是最早一批使用android系统的手机( 2008 年 9 月 23 发布了第一款Android手机),当时htc也是相当的火,但是好好的一副牌,最后也被打烂了。

2008年9月,谷歌正式发布了Android1.0系统,这也是Android系统最早的版本。那时自己上大一,自己使用的还是诺基亚6300,算是一个半智能的手机,只能后台播放音乐,玩个qq,如果想看个电子书就得先把qq退出。那时所所称的智能手机就是塞班系统的诺基亚手机,一个都概需要两千元左右,自己清楚的记得那一年诺基亚主推的旗舰机是N97。彼时, 满大街都是诺基亚的招牌,不是专卖点就是维修店,自己和朋友逛街的时候也感叹诺基亚太强大,估计谁也无法将它干趴下。但是事实证明,再牛逼的企业,如果不懂创新、拥抱时代潮流, 一味盲目的自大,迟早会被时代所抛弃。

随后的几年,谷歌以惊人的速度,不断更新Android系统,2.1、2.3、4.0等版本相继发布。其中有几个关键版本是需要我们记住的。

  • 1.5 第一个普及开来的安卓版本
  • 2.3 最长寿的安卓手机版本之一,和4.X 共处了很长的时间被淘汰,它是第一个支持前置摄像头的安卓版本,也是第一个支持 NFC 无线支付的安卓版本,看来我们现在天天使用你的自拍和无线金支付,十年前谷歌就在替我们准备好了。
  • 3.0 专门为平板设计的,但也是为数不多的比较失败的版本,没有存在感,在4.0版本上已经不区分平板和手机了。
  • 4.4 极为成功的一个版本,引入了扁平化图标和明亮的色泽,系统底层引入了实验版本的ART模式。
  • 5.0 号称改动最大的一个版本, 全新的MaterialDesign设计风格,还推出了Android Wear、Android Auto、AnroidTV, 同时使用ART抛弃了Dalvik Java虚拟机。
  • 6.0 添加了运行时权限。

下图是Android系统版本号和对应的api版本号。
继Android 9之后2019年5月发布最新的版本Android 10, 即 Android Q。

1.2-版本号

1.1.2 Android 的系统架构

1.5 Android系统架构

有些android面试会让我们手绘这张架构图, 因此我们有必要对android的系统架构做一个简单的了解。 如果别人问你什么是framwork层开发,如果你都不了解什么是framwork层的话,那么你是肯定回答不上来的。具体可以参考博客Android系统架构 五层结构

  • Linux 内核层

  • 系统运行库层

  • 应用框架层

  • 应用层

1.1.3 Android应用开发的特色

Android系统为我们提供了哪些东西让我们开发出一款应用程序? 这也是我们进行android开发要学习知识。

1. 四大组件

Android四大组件分别为 活动(Activity) 、服务(Service)、广播接受器(BroadCast Receiver)和内容提供器(Content Provider)。
其中Activity是用来展示内容的, 可以称为页面, 我们在应用中看到的文字,图片等,都是放在它里边。 服务我们无法看到,但是它会一直在后台运行,即时用户退出了应用,它依然可以继续运行。 广播接收器允许我们的应用接受来自各处的广播消息,例如电话、短信等,当然我们也可以发送广播。 内容提供器主要是为了不同程序之间共享数据提供的一种方案,例如我们的应用可以通过内容提供者来访问系统的通讯录。

2. 各种系统控件

我们在开发中将控件称为View, 系统为我们提供了一些常用的控件,如常见的布局文件RelativeLayoutLinearLayoutFrameLayout,以及TextViewImageView等等。当然我们也可以继承系统提供的控件来开发一些自定义的控件。

3. SQLite数据库

这是Android自带的数据库,它支持标准的SQL语法。

4. 强大的多媒体

系统还未我们提供了一些多媒体服务,例如音乐、视频、拍照、闹铃等,我们可以在自己的应用中使用他们。

5. 地理定位

这个功能算是Android系统,也可以说是移动应用中一个很大的两点, 通过它可以实现一些pc无法实现的功能,例如外卖、地图导航等等,极大的方便了我们的生活。

本书也是按照上边的顺序来一一展开讲解的。

1.2 搭建开发环境

什么是开发环境呢?开发环境就是一个集成环境,用来编译、运行你编写程序的。
刚开始学习java的时候使用的是editPlus或者notePad++ 等工具来学习,这些工具没有提示信息,作为初学编程的同学来说建议使用这些工具。但是开发android这些工具肯定不能满足我们的要求, 我们需要使用更高级的开发工具来提高开发效率,这个软件就是Android Studio(简称AS)。

AS的下载和Android的相关动态可以在官方中文网获取。

1.2.1 准备工作

搭建开发环境都需要哪些准备工作呢? 主要准备的有三个,分别是:JDK , AndroidSdk, Android Studio .

  • 因为Android程序都是使用java来编写的,所以首先我们要配置好java环境,因此首先要做的就是安装jdk。
  • AndroidSdk 是谷歌提供的开发工具包, 在开发Android程序时,需要引入该工具包,来使用对应版本的API。有的AndroidStdio安装包中已经包含了sdk。
  • Android Studio ,早期开发Android都是基于eclipse的, 2013年的时候谷歌推出了Android Studio,目前市场的android开发几乎都使用的是Android Studio,简称AS。

扩展

SDk中集成了许多常用的工具,例如 adb命令 、ProGuard、traceview 、zipalign, 具体可以参考博客:Android SDK工具介绍.

Android DDMS全称: Dalvik Debug Monitor Service。它提供了截屏、查看线程和堆信息、logcat、进程、广播状态信息、模拟来电呼叫和短信、虚拟地理坐标等等。
什么是DDMS呢? DDMS介绍介绍的比较好,DDMS的使用可参考博客:DDMS+MAT使用与博客: Android SDK中的强大工具-Monitor(三)

打开DDMS有两种方式:

  • 1.进入sdk的tools目录(/Android/Sdk/tools),关闭as和模拟器, 然后执行 sudo ./monitor 即可打开ddms
  • 2.点击 Tools —> Android —> Android Device Monitor,也可打开ddms

1.2.2 JDK 安装和环境变量的配置

平时我们使用的都是jdk,但是自己在编译Android 6.0源码的时候必须要使用openJdk,那么这两这之间的关系与区别是什么呢? 这个可以参考博客: 【JDK和Open JDK】平常使用的JDK和Open JDK有什么区别

jdk的安装可以参考博主的博客ubuntu16.04安装Jdk1.6与多版本jdk切换

ubuntu下的环境变量配置可以参考博主的博客: 记环境变量配置错误引发的血的教训, 之前自己配置环境变量的时候使用的是root账户,差点导致开不了机,所以配置环境变量的时候一定要认真仔细,尽量不要在root用户下操作。

1.2.3 AS的安装和使用

AS的安装比较简单,可以参考郭婶《第一行代码》中的步骤来安装。

AS的使用就比较复杂了,包括软件面板的熟悉、快捷键的使用、字体大小设置等等,这个需要时间的积累。

1.3 创建第一个Android项目

新建Android项目和创建模拟器就不做总结了。 目前基本上都是用真机来测试,这里主要学习Android项目的目录结构。

1.3.1 android项目目录结构分析

创建好的Android项目后第一次展现在我们面前的画面如图1.3,

1.3-Android视图

其中1表示目录结构视图的类型,常用的有Android模式和Project模式。 2是目录结构区域,这里默认显示的是Android模式,但是这不是真正的项目结构,而是AS转换过的,它将不同类型的文件归纳起来,开发的时候方便快速查找, 但是这对于新手来说不便理解。 3是代码编辑区域。 点击图1.3中1区域右边向下的小箭头,切换项目结构视图为Project,如图1.4所示。

1.4-project视图

如果一个一个目录点开看的话会发现非常复杂,不过没关系,只要我们静下心来学习,发现用不了多久就可以将他们一一攻破。
在project视图中,首先展示的是目录, 目录中先展示以.开头的,然后展示的文件,文件也是先展示以.开头的, 每个种类的排序是按照英文字母有a-z依次排序的, 掌握了这些规律就可以快速查找到自己想看的文件。

1..gradle.idea
这两个文件都是AS自动生成的文件, 我们不用理睬,也不需要编辑,但是注意:在进行版本控制的时候需要将他们添加到忽略文件中,否则每次提交时本地变化的文件列表中总会有它们的身影,后边学习Git的时候会学习Android项目在进行版本控制的时候有哪些文件是需要忽略,哪些文件是需要添加到版本控制的。

2.app
这个目录比较重要,它是项目的主module,主要存放了项目的代码、第三方jar包、资源文件等等, 后边会重点学习这个目录。

3.build
这个是项目的编译生成的一些文件,我们也不需要关注, 将这些文件删除掉后,重新编译项目就会重新生成,这个目录以及所有的build目录都要添加到忽略文件中。

4.gradle
这个目录中包含了gradle-warpper的配置文件,里边配置我们项目中使用哪个版本的gradle。
什么是gradle,gralde插件,以及如何配置项目的gradle文件后边会有专门的文章来介绍。

5..gitigore
这是项目的git忽略配置文件, 如果project使用git进行版本控制,那就需要在这个文件中配置忽略文件,也就是有哪些文件是不需要进行版本控制的,这个后边也是需要写一篇博客进行单独总结。另外需要注意的是.gitignore文件的作用域,如果一个项目中有多个module,我们会发现每个module中都有一个.gitignore文件, 那么他们对应的作用域是什么呢? 这些一定要好好思考。 后边也会进行专门的总结的。

6.build.gradle
这个文件是整个项目的gralde编译脚本文件,后边也是会学习到的。

7.gradle.properties
这时全局gralde脚本,也就是整个项目的gradle编译脚本,我们发现经常无法下载app module的grale文件中的一些远程依赖库, 在这里可以配置gralde的代理,然后快速下载对应的依赖库,会为我们节省不少时间。

8.gradlewgradlew.bat
这两文件是用来在命令行执行gradle命令的, gradlew是在linux和mac系统中使用, gradlew.bat是windows系统中使用的。

9.HellowWorld.iml
这也是IDEA AndroidStudio 生成的临时文件,主要用来表示这时一个IDEA项目,需要添加到忽略文件中,我们不需要做任何修改。

11.local.properties
这个文件指定了项目使用的sdk的路径,我们一般也不用做处理,另外需要注意,这个文件也是需要添加到忽略文件中的。

12.setting.gradle
这个文件指定项目中所有引入的模块,每添加一个新的module,就需要在这里配置。如果不想使用该module,直接在该文件中将对应模块删掉即可。

整个项目的外层目录看完了,发现许多都是idea自动生成的目录,我们需要关注的并不多,其中app目录比较复杂,需要重点学习。app目录展开后如图1.2所示。

1.3-app目录下的结构

1.build目录
这个目录和最外层的build目录一样, 都是编译时自动产生的文件,我们不用管,删掉之后重新编译项目它会再次生成。

2.libs目录
这个目录主要用来存放一些第三方jar包,也可以放so文件,但是需要在app的gradle文件中进行声明。

3.src目录
src即源码的意思, 这个目录中主要存放源码, 她包含了三个目录 androidTestmaintest目录。
androidTest :用来编写Android Test测试用例的。
test:也是用来编写 Unit Test 测试用例的, 是对项目进行自动化测试的另一种方式。 测试用例自己基本上没有写过,一些公司要求写,但是如果有时间的话还是需要了解一下。

main:中主要有javares目录。
java目录就是存放项目源码的地方。
res目录存放项目的资源文件,这里边也比较复杂。 项目的资源文件有图片、文字、布局文件等,所以这个目录也是按照不同的类别进行分类,我们将不同类型的文件存放的不同的目录中。 drawablemipmap都可以存放图片,但是app的启动图标一定要放在mimap中。layout存放布局文件,valus文件存放不同的xml文件,例如存放颜色值的colors.xml, 存放字符串的strings.xml和存放样式的style.xml等。
AndroidMainfest.xml:清单文件,主要配置android需要的权限和四大组件,只要是四大组件都需要在这个文件中进行注册。

4..gitignore:git进行版本控制时的忽略文件。
这个文件的作用是声明app目录中哪些文件需要忽略的, 和外层的.gitignore的作用一样的,但是他们的作用范围是不一样的,这个一定要注意。

5.build.gradle
这个是文件是用来做什么的呢? 它是apo模块的gradle构建脚本,这个文件中主要声明了app的最低兼容本本, 版本号,最高支持的版本,远程依赖等等,后边会详细介绍。

6.app.iml
这个是 IDEA 自动生成文件, 需要添加到忽略文件中。

7.proguard-rules.pro
这个文件中声明了代码的混淆规则,
整个android 工程可能有多个module,每个module可能都有一个混淆文件,我们可以将所有的规则都放到 app 目录中的混淆文件中,也可以将将每个module的混淆规则配置在自己模块的混淆文件中。我们建议第二种方式,什么是混淆,怎么配置混淆规则,这个后边会讲到。

这样整个app目录就学完了,一个项目可以包含多个module,默认情况下app是主module,它的gralde文件中的第一行中有如下声明。

1
apply plugin: 'com.android.application'

再创建的新的module都是子module。 当然app也可以也可以转换为一个子module。只需要将apply plugin: 'com.android.application'注释掉,然后在第一行添加下边一行代码。

1
apply plugin: 'com.android.library'

接下来学习res目录。

1.3.2 res目录详解

res目录中的各个目录又有什么作用呢? 以及他们是如何创建的呢? 这一小节介绍一下res目录。

1.3-res目录

res目录主要存放项目的资源文件,例如图片、布局文件、colors.xml等。

drawable : 主要存放图片资源文件。
layout : 主要用来存放布局文件,也就是layout文件。
mipmap : 主要用来存放应用图标的。
values : 主要用来存放项目的字符串、样式、颜色等配置信息的.

从图示1.3中可以看到有多个drawable和miamap目录,这主要是为了让程序更好的兼容不同的设备,虽然可能idea没有为我们生成对应的目录,但是我们也应该自己创建 drawable-hdpi 、drawable-xhdpi、drawable-xxhdpi\drawable-xxxhdpi,在开发中最好为一张图片提供不同分辨的版本, 分别放在对应的文件夹中,这样当程序运行的时候就会根据当前设备分辨率选择对应的图片,但是一般为了缩小apk的体积,ui都只会提供一套图片,我们将它放在xxhdpi中即可。

注意: 如上图所示, 使用3.0.1版本的AndroidStudio创建的项目中会多出 drawable-v24mipmap-anydpi-v26 这两个目录。

drawable-v24的作用可以参考博客: 关于drawable和drawable-v24
mipmap-anydpi-v26 这个目录主要是为了8.0系统应用图标的适配而创建的,可以参考郭霖的博客:Android应用图标微技巧,8.0系统中应用图标的适配.

如何引用资源文件? strings.xml文件的内容如下:

1
2
3
<resources>
<string name="app_name">HelloWorld</string>
</resources>

可以通过两种方式来引用:

  • 在代码中可以通过 R.string.app_name 来引用字符串 HelloWorld
  • 在xml文件中可以通过 @string/app_name 来引用字符串 HelloWorld

资源文件的创建可以参考如下链接:

如何创建drawable目录可以参考博客:https://blog.csdn.net/u014440968/article/details/50843719
如何创建selector.xml可以参考博客:Android Studio中创建Selector文件的方法

1.3.3 build.gradle 文件

Gradle是一个非常先进的项目构建工具,它使用了一种基于Groovy的领域特定语言(DSL)来声明项目的配置,摒弃了传统的基于XML(Ant和Maven)的各种繁琐配置, 使用它可以简化项目的编译、打包、测试的过程。

在新建的项目中有两个build.gradle文件,分别位于项目的根目录和app模块中,项目根目录的build.gradle文件如下所示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

buildscript {

repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.0.1'
}
}

allprojects {
repositories {
google()
jcenter()
}
}

task clean(type: Delete) {
delete rootProject.buildDir
}

`

这些代码是创建工程时自动生成的, 可以看到两处repositories都声明了google()、jcenter(), 那么分别是什么意思呢?
google()和jcenter()表示的是远程代码仓库的意思, 我们项目中用到的许多开源库都托管在远程仓库上,声明了这两行配置后,编译项目的时候点击同步gradle文件的按钮,就会将远程依赖库缓存到本地。

dependencies中使用classpath声明了一个gradle插件,这样我们就可以从远程仓库中下载gradle插件。
什么是gradle插件呢?因为gradle并不是专门为了android而开发的,许多java、C++项目都可以使用,因此google的程序员就为我们开发了gradle插件,方便我们构建android项目, 2.2.0表示的是插件的版本号。

app目录下的build.gradl文件中的代码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
apply plugin: 'com.android.application'

android {
compileSdkVersion 26
defaultConfig {
applicationId "com.syc.activity.startmode.helloworld"
minSdkVersion 19
targetSdkVersion 26
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}

dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:26.1.0'
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}

configurations.all {
resolutionStrategy.force 'com.android.support:support-annotations:26.1.0'
}

`

第一行代码apply plugin: 'com.android.application'表示该文件所在的模块(module)是一个应用程序模块,也称为主模块,它是可以直接打包生成apk,还有一种可选值为apply plugin: 'com.android.library',表示这个模块是一个库模块,库模块可以依附于主模块,也可以将库模块打包成一个aar包放在工程中来使用。

在gradle文件中一个{ }表示的是一个闭包, 例如 android{} 、 release{} 、dependencies{}都表示一个闭包。

接下来学习android闭包, applicationId用于指定项目的包名,在申请百度地图、极光推送的时候都需要用到它,同样的源码,如果id不一样,应用商店会视为两个不同的应用,所以这个不可以随便更改。 compileSdkVersion、minSdkVersion 、targetSdkVersion这三个配置是最基本的,也是最常见的版本。 虽然经常看到,但是要完全理解还是不容易的。 前两个比较好理解,第一个表示编译的sdk的版本,第二个表示应用最低兼容版本,低于它的话应用就无法安装, 第三个最难理解, 表示目标设备sdk版本。 关于这三个属性的理解可以参考博客Android targetSdkVersion你真的了解吗?Android之targetSdkVersion详解, 这两篇博客写的非常好,尤其第二篇通过列举源码来帮助我们理解。

1.3.4 gradle相关知识

1. 基础知识
下方的三篇博客写的不错:
彻底搞懂Gradle、Gradle Wrapper与Android Plugin for Gradle的区别和联系
Android Studio之maven Central 和 JCenter
java – google()和maven之间的区别{url’https://maven.google.com’}

2. 使用阿里云镜像仓库
由于国内防火墙的缘故,经常出现无法下载远程依赖的情况,我们有两种解决方案:一、科学上网, 二、使用阿里云镜像仓库。
第一种方案比较复杂,首先需要使用vpn来科学上网,其次还需要对AS设置代理,而且经常会出现ip被封的情况,所以建议使用第二种方案。

自己的系统是ubuntu系统, 可能是之前自己使用了apt源安装过maven,所以在当前用户的家目录中有一个隐藏文件夹.m2,该目录中有一个配置文件settings.xml,我们可以在这里配置阿里的镜像。 配置之前需要了解一些知识, 在这个文件中有下方的这段代码

1
2
3
4
5
6
<!-- localRepository
| The path to the local repository maven will use to store artifacts.
|
| Default: ${user.home}/.m2/repository
<localRepository>/path/to/local/repo</localRepository>
-->

可以看到默认仓库路径为${user.home}/.m2/repository, 也就是当前用户家目录中的.m2/repository。 后来自己参考博客ubuntu16.04安装maven下载deb包来手动安装, 进入到安装路径/opt/maven/apache-maven-3.6.3中,发现conf目录中也有一个settings.xml,该文件也有上边的这段代码,说明两个配置文件的默认仓库路径是一样的。这篇文章中介绍了通过配置localRepository标签的值将仓库路径修改到其它位置, 那么这两个文件有什么区别呢? 在Maven安装目录的conf子目录下面的settings.xml才是真正的全局的配置。而用户目录的.m2子目录下面的settings.xml的配置只是针对当前用户的。当这两个文件同时存在的时候,那么对于相同的配置信息用户目录下面的settings.xml中定义的会覆盖Maven安装目录下面的settings.xml中的定义, 这个和linux中多个环境变量配置文件道理是类似的,可以类比来理解。

接下来看如何配置阿里镜像, 找到用户家目录中的那个setttings.xml文件, 在mirrors标签中添加如下代码

1
2
3
4
5
6
	<mirror>
<id>nexus-aliyun</id>
<mirrorOf>*</mirrorOf>
<name>Nexus aliyun</name>
<url>http://maven.aliyun.com/nexus/content/groups/public</url>
</mirror>

然后打开android项目根目录中的build.gradle文件, 参考博客阿里云gradle镜像库配置自己做如下修改后就可以飞快的下载远程依赖库了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
  repositories {
// 以下四行代码为阿里gradle 源
maven{ url 'http://maven.aliyun.com/nexus/content/groups/public/'}
maven{ url 'https://maven.aliyun.com/repository/google'}
maven{ url 'https://maven.aliyun.com/repository/gradle-plugin'}
maven{ url 'https://maven.aliyun.com/repository/jcenter'}
maven { url "https://jitpack.io" }
google()
jcenter()
}
...
}

allprojects {
repositories {
// 所有的model 都优先使用阿里源
maven{ url 'http://maven.aliyun.com/nexus/content/groups/public/'}
maven{ url 'https://maven.aliyun.com/repository/google'}
maven{ url 'https://maven.aliyun.com/repository/gradle-plugin'}
maven{ url 'https://maven.aliyun.com/repository/jcenter'}
maven { url "https://jitpack.io" }
google()
jcenter()
}

3. 其它知识点

3.1 、 gradle缓存路径
AndroidStudio的gradle缓存路径为/.gradle/caches/modules-2/files-2.1, 也就是gradle文件中的一些远程库基本都是下载到了这个目录中。 有关.gradle目录中没给文件夹的作用可以参考博客:【我的Android进阶之旅】Linux下学习.gradle目录组织结构以及修改Gradle缓存文件夹路径,写的非常不错。

3.2 、gradle目录结构和maven目录结构
公司进行安全测试的时候需要在无法连接互联网的情况下对项目进行编译,所以就需要提前将一些第三方依赖下载到对应的缓存目录中, 大部分的情况第三方库都会缓存在/.gradle/caches/modules-2/files-2.1中, 但是自己发现有些库在该目录中没有,但是项目仍然可以编译过, 后来在Android的sdk中发现一些库,原来android-studio使用了这里边的一些库, 这些库的路径为/Android/Sdk/extras/android/m2repository/com/android/support,但是它们的目录结构和gradle缓存的库的格式不一样。后来才发现这时两种目录结构,一种是gradle目录结构,一种是maven目录结构, 可以参考博客Gradle 使用Maven的本地仓库(坑),这个知识点要注意以下。

以自己开发环境中appcompat-v7库为例:

gradle的目录结构如下(路径为:/home/shaoyance/.gradle/caches/modules-2/files-2.1):

1
2
3
4
files-2.1
├── com.android.support
│   ├── animated-vector-drawable
│   ├── appcompat-v7

maven库的结构(路径:/home/shaoyance/Android/Sdk/extras/android/m2repository):

1
2
3
4
5
└── com
└── android
└── support
├── animated-vector-drawable
├── appcompat-v7

1.3.5 gradle依赖错误解决

1、v7包版本号不一致导致的冲突

1
2
3
compile 'com.android.support:appcompat-v7:27.1.1'
compile 'com.android.support:design:27.+'
compile 'com.android.support:cardview-v7:27.+'

在gradle中采用了上边的配置后报了如下错误

1
2
3
All com.android.support libraries must use the exact same version specification (mixing versions can lead to runtime crashes). Found versions 27.1.1, 25.3.0. Examples include com.android.support:animated-vector-drawable:27.1.1 and com.android.support:design:25.3.0 less... (Ctrl+F1)
There are some combinations of libraries, or tools and libraries, that are incompatible, or can lead to bugs. One such incompatibility is compiling with a version of the Android support libraries that is not the latest version (or in particular, a version lower than your targetSdkVersion.)
————————————————

这个错误的意思是v7包和desgin、cardview冲突了. 首先我们要明白 + 表示采用最新的版本,因此上边的代码表示design和cardview采用了最新版本的库,他们与27.1.1的appcompat-v7库发生冲突了。

我们在开发中经常会使用一些开源库,假如作者在开发某个库的时候依赖了desgin、cardview这两个库 ,而且他使用了+的方式进行依赖, 这两个库当时与27.1.1的appcompat-v7库并没有冲突,但是当我们使用作者的这个开源库并且远程依赖这两个库的时候, 它们已经更新了许多版本,如果这时我们仍然使用+的方式去依赖, 此时我们依赖的最新的desgin、cardview库可能就与27.1.1的appcompat-v7库起冲突了, 所以在开发中最好不要使用+的方式来依赖,直接具体到某个版本号最好。

1.4 日志工具使用

项目开发过程中必然会遇到很多bug,靠猜是肯定无法解决问题的, 查看log是最科学的解决方案。无论是gradle编译错误日志还是logcat中的错误日志, 遇到问题首先要想到的就是要查看log,根据报错的log寻找解决方案,然后才是去询问他人帮助。一个有经验的程序员是非常善于通过log来解决编程中遇到的问题。

1.4.1 Android 中的日志工具 Log

Android中提供了日志工具类Log, 使用它我们可以打印五个级别的log。他们级别以及使用场景如下:

  • Log.v() 打印一些最为琐碎的、意义最小的Log, 对应的级别是verbose, 是级别最低的一中。
  • Log.d() 打印一些调试的信息,我们在调试程序的时候打印的调试信息可以使用该方法, 对应的级别是 debug, 比verbose高一级
  • Log.i() 打印一些比较重要的数据, 例如网络请求成功后返回的数据等, 对应的级别是 info, 比debug高一级
  • Log.w() 打印一些警告的信息, 指的是可能会存在潜在风险, 但是不会是程序崩溃, 但是我们最好要修复一下, 对应的级别是 warn, 比info高一级。
  • Log.e() 打印程序中的错误信息, 这些错误可能会使程序直接崩溃,代表程序出现严重的问题。 对应的级别是 error, 比warn高一级。

1.4.2 为什么不使用 System.out而使用Log

在开始学习编程的时候,我们都是通过System.out.println()的方式来打印log,但是在真正开发android的项目我们很少使用这种方式,而是采用Android SDk提供的日志工具类Log来打印日志。

那么为什么不采用System.out而采用Log来打印呢?

这是因为刚开始学习Android的时候,都是使用Eclipse开发android项目,只要输入syso就可以方便的输入代码System.out,所以很多Java开发人员对它情有独钟,但是后来使用AndroidStudio, 一方面它不支持了这种快捷方式,另一方面也是因为Android SDK提供了Log类来打印日志。 当然更重要的是使用Log类可以打印出不同级别的Log, 配合logcat可以说是非常强大,能够很方便的输出我们想要查看的log。

1.4.3 Android-studio中Log常见使用技巧

  1. 在当前类文件中输入Logt,然后按下 Tab 键,就会自动生成一个TAG常量。
  2. 如果想要输入info级别的log,只要输入logi,然后按下 Tab键就可以自动补全一条完整的打印语句
  3. 可以使用 tag来过滤出该tag对应的log, 可以是一个tag,也可以是多个tag, 每个tag之间用|间隔,然后选中复选框Regex,就可以看到这几个tag对应的log。 也可以使用关键字过滤log。
  4. 除了根据TAG来过滤log, 也可以自定义过滤器, 我们只需要选中自定义的过滤器就可以过滤出自己想要的log。
  5. 默认的logcat每个级别的log区分的不太明显,我们可以自己设置不同级别log对应的颜色,参考博客: Android-Studio使用技巧(一)中的设置花式LogCat/)
  6. 有时候我们在使用AS调试apk的时候,崩溃日志会被下方的日志迅速冲没了,这时可以将log打印到指定的文件中。输入命令adb logcat -v time > /home/桌面/log.txt (将log打印到桌面的log.txt文件中)

1.4.4 有关Log的思考

关于Android的日志还有许多需要学习思考的地方。 自己暂时归纳如下:

  1. Android的Log类源码自己看过吗, 它具体是如何实现的,使用了哪种设计模式呢?
  2. 我们可以通过对系统提供的Log类进行封装,配置一个统一的开关,在项目上线的时候将其关掉,这个可以参考博客:Android快速开发系列 10个常用工具类 中提供的一个LogUtils。 当然还有一些开源的打印log的第三方库。
  3. 除了自定义LogUitls的方式控制Log的开关,还有别的方式吗? 我们可以通过在gradle文件中进行配置是否允许打印Log, 如果不了解这个知识点,有时候命名自己的LogUtils已经开启了却无论如何不打引日志,这时就要去检查是否在gradle文件中配置了不允许打印Log。
  4. 当打印的数据非常长的时候如何将完整的数据打印的logcat,Log打印的log的是有长度限制的,这一点也要注意。
  5. 有时在logcat查看log的时候会被一些无用的log冲没了, 这是如何将log打印到桌面的txt文中呢? 这时我们可以通过执行adb相关命令实现。
  6. 对于有的机型可以通过在手机上录取相关的log,(在甘肃出差时,厂家采用的是联发科的处理器,他们的开发就是使用这种方式来获取应用的日志,最终解决anr的错误。 )

小结

这一章主要学习了哪些知识点呢?

首先我们了解了Android系统的发展史、已经发布的版本号、Andorid的系统架构,以及Android为我们提供了哪些服务(注意:本书的学习也是根据这个顺序一一展开的)。

然后学习了如何搭建Android开发环境,这其中包括了 jdk的安装与环境变量的配置、AndroidStudio安装包的下载与安装。

接着学习如何创建第一个Android项目,并对Android项目目录结构和gradle文件的一些配置进行了分析。

最后学习Android 日志工具类Log的使用。

博客编号:30

参考书籍《第一行代码》