目录
1.1了解全貌—Android王国简介
1.1.1Android系统框架
大致微分四层框架:Linux内核层、系统运行库层、应用框架层、应用层
- Linux内核层 Android系统是基于Linux内核的,这一层为Android设备的各种硬件提供了底层的驱动,如显示驱动、音频驱动、照相机驱动、蓝牙驱动、Wi-Fi驱动、电源管理等。
- 系统运行库层 这一层通过一些C/C++库来为Android系统提供主要的特性支持。如 SQLite提供数据库的支持,OpenGL|ES库:3D绘图,Webkit库:浏览器内核。同样,在这一层还有Android运行时库,他主要提供了一些核心库,能够允许开发者使用Java语言来编写Android应用。还包含Dalvik虚拟机(5.0系统以后改为ART运行环境),它使得每一个Android应用都能够运行在独立的进程当中,并且拥有一个自己的Dalvik虚拟机实例。相对于Java虚拟机,Dalvik是专门为移动设备定制的,他针对手机内存、Cpu性能有限等情况做了优化处理。
- 应用框架层 这一层主要提供了构建应用程序时可能用到的各种API,Android自带的一些核心应用就是使用这些API完成的,开发者也可以通过使用这些API来构建自己的应用程序。
- 应用层 所有安装在手机上的应用程序都是属于这一层的,比如系统自带的联系人、短信等程序,或者一些小游戏和自己开发的程序。
1.1.2Android应用开发特色
1.四大组件
活动(Activity)、服务(Service)、广播接收器(Broadcast Receiver)、内容提供器(Content Provider)。
活动是所有Android应用程序的门面,但凡在应用中你看到的东西,都当在活动中。
服务比较低调,你无法看到它,但它会一直在后台默默地运行,即使用户退出了应用,服务也可以继续运行
广播接收器允许你的应用接受来自各处的广播信息,比如电话、短信等。当然,你的应用也可以向外发出广播信息。
内容提供器则为应用程序之间共享数据提供了可能,比如你想要读取系统电话簿中的联系人,就需要通过内容提供器来实现。
2丰富的系统控件 提供了丰富的控件系统,可以轻松写出漂亮的界面
3 SQLite数据库 Android系统还自带了这种轻量级、运算熟读极快的嵌入式关系型数据库。它不仅支持标准的SQL语法,还可以通过ANdroid封装好的API进行操作,让存储和读取数据变得非常方便。
4 强大的多媒体 提供了丰富的多媒体服务,如音乐、视频、录音、拍照、闹铃,等等
5 地理位置定位 内置GPS
1.2 搭建开发环境
1.2.1 准备工具
- JDK。 JDK8及以上
- Android SDK。 谷歌提供的Android开发工具包,在开发Android程序时,我们需要引入改工具包,来使用相关的API
- Android Studio。IDE工具
1.2.2搭建开发环境
1.2.3第一个Android项目
Hello Word项目中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>
这段代码表示对Hello WorldActivity这个活动进行注册,没有在AndroidMainfest.xml里注册的活动是不能使用的。其中intent-filter里的两行代码非常重要,<action android:name="android.intent.action.MAIN" />和 <category android:name="android.intent.category.LAUNCHER" />表示HelloWorldActivity是这个项目的主活动,在手机上点击应用图标,首先启动的就是这个活动。
public class HelloWorldActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.hello_world_layout);
}
}
如上,我们可以看到HelloWorldActivity是继承自AppCompatActivity的,这是一种向下兼容的Activity,可以将Activity在各个系统版本中增加的特性和功能最低兼容到Android2.1系统。Activity是Android系统提供的一个活动基类,我们项目中所有的活动都必须继承它或者它的子类才能拥有活动的特性(AppcompatActivity是Activity的子类)。然后可以看到HelloWorldActivity中有一个onCreate()方法,这个方法是一个活动被创建是必定要执行的方法,其中只有两行代码,并且没有Hello World!字样。
其实,Android程序的设计讲究逻辑和试图分离,因此是不推荐在活动中直接编写界面的,更加通用的一种做法是,在布局文件中编写界面,然后在活动中引入进来。可以看到,在onCrate()方法的第二行调用了setContentView()方法,就是这个方法给当前的活动引入了一个hello_world_layout布局,那Hello world!一定就是在这里定义的。
布局文件都是定义在res/layout目录下的,展开文件,打开hello_world_layou.xml文件,并切换到text视图,代码如下:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
TextView,这是Android系统提供的一个控件,用于在布局中显示文字的。android:text="Hello World!"这句代码定义。
1.2.4 详解项目中的资源
在res目录中,drawable开头的文件夹都是用来存放图片的,mipmap开头的文件夹放应用图标,values开头的文件夹都是用来放字符串、央视、颜色等配置的,layout文件夹是用来放布局文件的。
之所以有很多的mipmap开头的文件夹,其实主要是为了让程序能够更好地兼容各种设备。drawable文件夹也是同理。虽然Android Studio没有帮我们自动生成,但是我们应该自己创建drawable-hdpi、drawable-xhdpi、drawable-xxhdpi等文件夹。在制作程序的时候最好能够给同一张图片提供几个不同分辨率的版本,分别放在这些文件夹下,然后当程序运行的时候,会自动根据当前运行设备分辨率的高低选择加载哪个文件夹下的图片。当然,这些只是理想情况下,更多的时候美工只会提供给我们一份图片,这是就放在drawable-xxhdpi文件夹下。
打开res/values/strings.xml文件,代码如下:
<resources>
<string name="app_name">Hello World</string>
</resources>
可以看到,这里定义了一个应用程序名的字符串,有两种方式来引用它。
- 在代码中方通过R.string.hello_world可以获得该字符串的引用
- 在XML中通过@String/hello_world可以获得该字符串的引用
基本语法就是这两种,其中String部分是可以替换的,如果是引用的图片资源就换成drawable,应用图标就为mipmap,布局文件就为layout。
1.2.5详解build.gradle文件
Android Studio采用Gradle来构建项目。Gradle是一个非常先进的项目构建工具,它使用了一种基于Groovy的领域特定语言(DSL)来声明项目设置,摒弃了传统基于XML(如Ant和Maven)的各种繁琐配置。
在HelloWorld项目中,有两个build.gradle文件,一个在最外层目录下,一个在app目录下。这两个文件对构建Android Studio项目都起到了至关重要的作用。
最外层代码如下所示
buildscript {
repositories {
jcenter()
}
dependencies {
classpath "com.android.tools.build:gradle:4.1.3"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
jcenter()
}
}
两处repositories的闭包中都声明了jcenter()这行配置,它是一个代码托管仓库,很多Android开源项目都会选择将代码托管到jcenter上,声明这行配置后,,可以在项目中引用任何jcenter上的开源项目了。
在dependencies闭包中使用了classpath声明了一个gradle插件。因为Gradle并不是专门为构建Android项目而开发的,Java、C++等很多项目都可以使用Gradle来构建按。因此如果我们想要使用它来构建Android项目,则需要声明com.android.tools.build:gradle:2.2.0这个插件。后面是版本号。
通常情况下,我们并不需要修改这个文件中的内容,除非想添加一些全局的项目构建配置。
app目录下的build.gradle文件代码
plugins {
id 'com.android.application'
}
android {
compileSdkVersion 30
buildToolsVersion "30.0.0"
defaultConfig {
applicationId "com.example.helloworld"
minSdkVersion 16
targetSdkVersion 30
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
dependencies {
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'com.google.android.material:material:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
testImplementation 'junit:junit:4.+'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
}
}
第一行应用了一个插件,一般有两种值可选:com.android.application表示这是一个应用程序模块,com.android.library表示这是一个库模块。应用程序模块和库模块最大的区别在于,一个是可以直接运行的,一个只能作为代码库依附于别的应用程序模块来运行。
接下来是一个大的Android闭包,在这个闭包中,我们可以配置项目构建的各种属性。其中,compileSdkVersion用于指定项目的编译版本,这里指定成24表示使用Android7.0系统的SDK编译。build Tools Version用于指定项目构建工具的版本,目前最新的版本就是24.0.2。
在android闭包中有嵌套了一个defaultConfig闭包,defaultConfig闭包中可以对项目的更多细节进行配置。其中,application用于指定项目的包名,前面我们在创建项目的时候十七已经指定过包名了,如果你想在后面对其进行修改,那么就在这里修改的。minSdkVersion用于指定项目最低兼容的Android系统版本,这里指定成15表示最低兼容到Android4.0系统。targetSdkVersion指定的值表示你在该目标版本上已经做过充分的测试,系统将会为你的应用程序启动一些最新的功能和特性。比如说Android6.0系统中引入了运行时权限这个功能,如果你将targetSdkVersion指定成23或者更高,那么系统就会为你的程序启用运行时权限功能,而如果你将targerSdkversion指定成22,那么就说明你的程序最高只在Android5.1上做过充分的测试,Android6.0系统中引入的新功能自然就不会启用了。versionCode用于指定项目的版本号,versionName 用于指定项目的版本名。
build Types闭包用于指定生成安装文件的相关配置,通常只会有两个子闭包,一个是debug,一个是release。debug闭包用于指定生成测试版安装文件的配置,release闭包用于指定生成正式版安装文件的配置。另外,debug闭包是可以忽略不写的。在release闭包中,minifyEnabled用于指定是否对项目的代码进行混淆,true表示混淆,false表示不混淆。prooguardFiles用于指定混淆时使用的规则文件,这里指定了两个文件,第一个proguard-android.txt是在Android SDK目录下的,里面是所有项目通用的混淆规则,第二个proguard-rules.pro实在当前项目的根目录下,里面可以编写当前项目特有的混淆规则。注意,通过Android studio直接运行项目生成的都是测试版安装文件,正式版安装文件见15章节。
dependencies闭包功能非常强大,它可以指定当前项目所有的依赖关系。通常Android Studio项目一共有3种依赖方式:本地依赖、库依赖、远程依赖。
- 本地依赖可以对本地的Jar包或目录添加依赖关系
- 库依赖可以对项目中的库模块添加依赖关系
- 远程依赖可以对Jcenter哭丧的开源项目添加依赖关系。
dependencies闭包中的配置,第一行的compile fileTree就是一个本地依赖声明,它表示将libs目录下所有的.jar后缀的文件都添加到项目的构建路径当中。而第二行的compile则是远程依赖声明,com.android.support:appcompat-v7:24.2.1就是一个标准的远程依赖库格式,其中com.android.suppoer是域名部分,用于和其他公司的库做区分;appcompat-v7是组名称,用于和同一个公司中不同的库做区分;24.2.1是版本号,用于和同一个库不同的版本做区分。加上这句声明后,Gradle在构建项目时会首先检查一下本地是否已经有这个库的缓存,如果没有的话,则会去自动联网下载,然后再添加到项目的构建路径当中。至于库依赖声明这里没有用到,它的基本格式是compile project后面加上要依赖的库名称,比如说有一个库模型名字叫helper,那么添加这个库的依赖关系只需要加入compile project(':helper')这句声明即可。另外剩下的一句testCompile是用于声明测试用例库的。
1.3前行准备—掌握日志工具的使用
1.3.1使用Android的日志工具Log
Android中的日志工具类是Log(android.util.Log),这个类中提供了5个方法来供我们打印日志。
- Log.v()。用于打印那些最为琐碎的、意义最小的日志信息。对应级别verbose,是Android日志里面级别最低的一种
- Log.d()。打印一些调试信息,这些信息对你调试程序和分析问题应该是有帮助的。对应级别debug,比verbose高一级
- Log.i()。打印一些比较重要的数据,这些数据应该是你非常想要看到的、可以帮你分析用户行为数据,对应级别info,比debug高一级
- Log.w()。用于打印一些警告信息,提示程序在这个地方可能会有潜在的风险,最好去修复一下这些出现警告的地方。对应级别warn,比info高一级
- Log.e()。打印程序中的错误信息,比如程序进入到了catch语句当中。当有错误信息打印出来的时候,一般都代表你的程序出现严重问题了,必须尽快修复。对应级别error,比warn高一级。
Log.d()方法传入了两个参数:第一个参数是tag,一般传入当前的类名就好,主要用于对打印信息进行过滤;第二个参数是msg,即想要打印的具体的内容。
1.3.2为什么使用Log而不使用System.out
System.out.println()的缺点:日志打印不可控制、打印时间无法确定、不能添加过滤器、日志没有级别区分等
Android Studio当中有快捷键输入,logd+Tab键,会自动补全一条完整的打印语句。输入logw,按下Tab键,会自动补全一条info级别的打印日志,一次类推。另外,由于Log的所有打印方法都要求传入一个tag参数,每次写一遍显得太过麻烦。这里有一个小技巧,我们在哦那Create()方法的外面输入logt,然后按下Tab键位,这是就会以当前的类名作为值自动生成一个TAG常量。
除了快捷键输入之外,logcat中还能很轻松地添加过滤器,如图:
目前只有3个过滤器,Show only selected application 表示只显示当前选中程序的日志,firebase是谷歌提供的一个分析工具,我们可以不用管它,No Filters 相当于没有过滤器,会把所有的日志都显示出来。
自定义过滤器:点击Edit Filter Configuration,会弹出一个过滤器配置界面。我们给过滤器起名叫data,并让他对名为data的tag进行过滤。
点击ok,就会发现多了一个data过滤器。当点击这个过滤器的时候,发现在onCreate()方法里打印的日志没了,这是因为data这个过滤器只会显示tag名称为data的日志。可以将语句Log.d("data","onCreate() execute");写入,然后运行程序,就可以在data过滤器下看大盘这行日志了。
logcat的日志级别控制。logcat中主要有5个级别,分别为verbose、debug、info、warn、error。
日志级别控制的好处就是,可以很快找到所关心的那些日志。
关键字过滤。如果不能使用过滤器加日志级别控制还是不能锁定想要查看的日志内容,可以通过关键字进行过滤。
在输入框输入关键字的内容,这样只有符合关键字条件的日志才会显示出来,从而快速定位到任何你想要查看的 日志。注意,关键字过滤是支持正则表达式的。