安卓开发(1)——安卓概述
安卓开发(1)——安卓概述
安卓简介
安卓系统架构
也就是常说的四层架构:linux内核层(linux kernel),系统运行库层(Library)、应用框架层(Application Framewordk)和应用层(Applications)。
Linux kernel
Linux内核层:这一层是为硬件提供底层的驱动,例如蓝牙,Wi-Fi驱动等等。
Libraries
系统运行库层:这一层通过C/C++库来为Android系统提供了特性支持,来为上层提供支持。
Application Framework
主要提供了建构应用程序时可能用到的各种API。
Application
应用层,所以安装在安卓手机上的应用程序都是属于这一层的,比如手机上的一些联系人,QQ,微信等应用。
安卓开发的四大组件
Activity,Service,BroadcastReceiver和ContentProvider。
Activity(活动):包含了所有在APP中可以看到的东西。
Service:是在后台运行的部分。
BroadcastReciver:广播接受者,可以接受各处的广播(如:短信,电话等等),也可以向外发出广播。
ContentProvider:应用程序之间共享数据。(比如:微信通过读取手机的联系人来添加好友)
Android的开发环境
所需的工具:
JDK:用于处理java代码。
AndroidSDK:是Google提供的Android开发工具包,提供Android要使用的API。
Android Studio:一个开发Android 的IDE。
如何搭建Android开发环境不是本博客的重点,想了解的,可以自行百度搜索。
第一个Android项目
创建项目
这里选择一个Empty Activity
这里的Name就是app的名字,Package name是项目的包名,Android系统就是通过包名来区分不同的应用程序(application)的,所以包名必须得有唯一性。
Save Location表示项目保存地址。
Language这里可以选择Kotlin和Java
Minimum SDK这里可以设置项目的最低兼容版本,也就是兼容Android的最低版本为多少。
点击Finish就完成了第一个项目的创建
使用项目
创建虚拟机
Android系统开发的app,需要在Android系统上才能跑,Android Studio提供了Android的虚拟机,可以给我们用来测试APP。
在菜单中找到这三个案件,中间那个就是用来创建和启动模拟器的。
然后开始创建模拟器:
这里根据自己的喜好来选就好(我用的是Pixei2)
然后选择系统镜像,推荐选择最新版本,也就是第一个,如果没有下载过该镜像,需要点击Download后才能点击下一步。
使用虚拟机
单机想要启动的虚拟机,就可以启动该虚拟机了。
在虚拟机上运行写好的项目app
先开启虚拟机,开启后,在该菜单栏里面选择要启动的虚拟机和项目:
然后再点击右边的运行按钮就可以运行了。(左边那个锤子是编译项目的意思)
第一个Android项目就搞定了。
分析第一个Android程序
查看项目文件:
当一个项目创建的时候默认是采用Android模式的项目结构来查看,但是这个步数真正的目录结构,而是被Android Studio转换了的,单击Android转换为Project(项目)版本来查看(中英文可以能有出入)。
切换为project版本下的项目结构:
这个才是真实的项目结构。
分析项目文件:
.gradle和.idea | 存放的都是AS自动生成的文件,这个不用处理。 |
---|---|
app | 项目中的代码和资源等主要内容都是存放在这个目录的,开发工作也主要是在这个目录下面。 |
build | 包含了一些在编译时自动生成的文件。(不用关心) |
gradle | 这个目录包含了gradle wrapper的配置文件,使用gradle wrapper的方式不需要提前将gradle下载好,而是先根据有没有本地缓存的情况来决定要不要下载。可以点击File->Settings->Build,Execution,Deployment->Gradle。 整个安卓的项目都是采用gradle来全程把控 |
.gitignore | 用来将指定的目录或文件排除在版本控制之外。 |
.build.gradle | 全局的gradle构建脚本,通常是不用修改的。 |
gradle.properties | 全局gradle的构建脚本,通常不需要修改。有点类似于makefile |
gradlew和gradlew.bat | 这两个文件是用来在命令行界面执行gradle命令的,其中gradlew是在linux上使用,gradlew.bat是用在windows系统上的。 |
HelloWorld.iml | iml文件是所有的IDEA项目都会自动生成的一个文件(AS是基于IDEA开发的),该文件只是用来标识是IDEA的项目文件。 |
local.properties | 该文件用来指定Android 的SDK的路径,通常是自动生成的,除非Android SDK位置发生变化,不然是不用修改的。 |
setting.gradle | 用来指定项目中所有引入的模块,通常情况下模块的引入都是自动完成的,需要手动修改比较少。 |
分析app目录
经过前面分析的项目文件可以知道,除了app目录,大部分文件都是AS自动生成的,所以app文件下的内容才是重点。
build | 和外层的build一样,包含的是一些编译时自动生成的文件。 |
---|---|
libs | 如果项目中包含了第三方的jar包,就需要把这些jar包放到libs文件夹下 |
androidTest | 用来写Android Test测试用例的 |
java | 放置所有java(Kotlin)代码的,展开可以看到,AS自动生成了一个MainActivity文件 |
res | 在项目里使用的所有图片、布局、字符串等资源都要存放到该目录下。图片放到drawable目录下,布局放到layout目录下,字符串放到value目录下。 |
AndroidManifest.xml | 整个项目的配置文件,在程序中定义的所有四大组件都需要在这个文件里面注册,还可以在这里面给应用程序添加权限声明。 |
test | 用来编写Unit Test测试用例,对项目进行自动化测试的一种方式。 |
.gitignore | 用于将app模块内指定的目录或文件排除在版本控制之外。 |
app.iml | IDEA自动生成的文件,仅仅来标识是个IDEA文件。 |
build.gradle | app模块内部的gradle构建脚本,指定很多项目构建相关的配置。 |
proguard-rules.pro | 用于指定项目代码的混淆规则,当代码开发完成后,不希望被别人破解,通常会将代码进行混淆, |
详解app中的res
将res文件夹展开可以看到里面的文件还是挺多的,但是归纳一下就还好。
图片 | 所有以drawable开头的目录都是用来存放图片的 |
---|---|
应用图标 | 所有以mipmap开头的存放的都是应用图标 |
配置 | 所有以values开头的都是用来存放字符串、样式、颜色等配置的。 |
布局 | 所有以layout开头的目录都是用来存放布局文件的。 |
之所以有这么多mipmap开头的目录,主要是为了兼容各种设备,drawable也是一样,虽然AS没有自动生成,但是为了更好兼容,我们也应该自己创建drawable-hdpi ... drawable-xxxhdpi等目录。在写程序的时候最好对同一个图片能提供几个不同分辨率的版本,分别放在这些目录下面,但是大多数时候只会有一个图片,就把所有的图片放到drawable-xxxhdpi里面就好了,这个目录对应的是最主流的设备分辨率。
打开values下的string,xml:
<resources>
<string name="app_name">HelloWorld</string>
</resources>
可以看到这里定义了一个应用程序名字的字符串,有两种方式可以拿来引用它:
1:在代码里面通过R.string.app_name可以获得该字符串的引用
2:在X M L中通过 @string/app_name可以获得该字符串的引用
其中的string部分是可以替换的,如果用的是图片资源就可以替换成drawable,如果是应用图标就可以替换成mipmap,布局文件就可以替换成layout
例如:AndroidManifest.xml文件中的内容
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.HelloWorld">
....
</activity>
</application>
详解build.gradle文件
AS采用gradle来构建项目,gradle是一个比较先进的项目构建工具,基于Groovy领域特点语言来进行项目设置,抛弃了基于传统的XML的各种繁琐配置。(反正比较先进就行了。)
在我们这个HelloWorld项目中,有两个build.gradle文件,一个是整体的build.gradle,一个是app目录下的build.gradle文件。
详解整体项目的build.gradle文件
先看整体项目的build.gradle文件:
buildscript {
ext.kotlin_version = "1.3.72"
repositories {
google()
jcenter()
}
dependencies {
classpath "com.android.tools.build:gradle:4.1.1"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
allprojects {
repositories {
google()
jcenter()
}
}
这些代码都是自动生成的,看似复杂但是忽略语法查看关键代码还是挺简单的。
首先两处的repositories都声明了google()和jcenter(),这两个分别对应两个代码仓库,google()主要是包含谷歌自己的扩展依赖库,jcenter()主要是包含一些开源的第三方库,声明了之后就可以使用它们所包含的依赖库了。
在dependencies中声明了gradke和kotlin的两个插件,申明gradle是因为gradle并不是专门给Android开发出来的,如果要使用的话,肯定需要声明gradle的插件,gradle后面的版本通常是和AS的版本相对应的,申明kotlin是因为这个Android项目是用的kotlin语言,如果采用的是java的话就不会有这个了。
详解app下的build.gradle文件
查看app下的build.gradle源代码:
plugins {
id \'com.android.application\'
id \'kotlin-android\'
}
android {
compileSdkVersion 30
buildToolsVersion "30.0.3"
defaultConfig {
applicationId "com.example.helloworld"
minSdkVersion 21
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
}
kotlinOptions {
jvmTarget = \'1.8\'
}
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation \'androidx.core:core-ktx:1.2.0\'
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\'
}
第一个闭包plugins:
com.android.application:表示是一个应用程序模块。 kotlin-android:就是一个kotlin的插件,如果要用kotlin来开发,这个插件是必须要的。
第二个闭包是一个很大的闭包 Android,该闭包中嵌套了defaultConfig,buildTypes,compileOptions,kotlinOptions 四个闭包。在Android闭包里面可以配置项目构建的各自属性,其中compileSdkVersion用来指定项目的编译版本,指定Android项目的SDK版本,buildToolsVersion用来指定项目构建工具的版本。
Android闭包里的defaulltConfig闭包:
applicationId "com.example.helloworld" //每个应用的唯一标识符,也就是在创建项目时的包名
minSdkVersion 21 //项目最低兼容的Android版本
targetSdkVersion 30 //该字段指定的值用来表示在当前目标版本上已经做好了充分的测试
//指定的值表示在哪一个sdk版本以及之前已经做好了充分的测试。
versionCode 1 //指定项目的版本号
versionName "1.0" //指定项目的版本名
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
//用来在当前项目中七点JUnit测试
Android闭包里的buildTypes闭包:
buildTypes闭包里通常会有两个子闭包,release和debug,就相当于项目的两个版本,debug默认可以不用写。
buildTypes {
release {
minifyEnabled false //用来指定是否对项目的代码进行混淆
proguardFiles getDefaultProguardFile(\'proguard-android-optimize.txt\'), \'proguard-rules.pro\' //proguardFiles用来指定代码的混淆规则
//proguard-android-optimize.txt是在<AndroidSDK>/tools/proguard目录下的一个通用混淆规则
//proguard-rules.pro是在当前项目的根目录下的,里面可以编写当前项目特有的代码混淆规则
}
}
Android剩下的两个闭包:compileOptions,kotlinOptions都是用来指定java和jvm版本的,没啥影响。
最后一个闭包:dependencies,这个闭包指定了项目的所有依赖关系。
在Android中的依赖有三种方式:本地依赖,库依赖,远程依赖。本地依赖可以对本地的jar包添加,库依赖可以对项目中的库模块添加依赖,远程依赖则是对于jcenter仓库上的开源项目进行添加依赖。
implementation fileTree 是本地依赖申明
implementation 表示是一个远程依赖
implementation project 表明是一个库依赖
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation \'androidx.core:core-ktx:1.2.0\'
implementation \'androidx.appcompat:appcompat:1.1.0\'//一个标准的远程依赖
//androidx.appcomat是域名用来区分其他公司的库,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\'
}
分析一个项目的运行流程
分析一下,这里写的Helloworld项目是如何运行起来的。
首先查看AndroidManifest.xml文件,找到如图所示的代码:
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
这段代码表示对MainActivity的注册(没有再AndroidManifest.xml文件中注册的四大组件是无法使用的),其中intent-filter代码段里面的两行代码最为重要,其作用就是表示MainActivity是这个项目的主Activity,在手机上点击应用图标,首先启动的就是该Activity。
凡是在APP中可以看到的东西,都是Android中的四大组件的Activity中的内容,因此在该HelloWorld项目中看到的弹出来的界面就是MainActivity,查看MainActivity的代码:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
}
可以很清楚地看到MainActivity是继承了AppCompatActivity这个类的。AppCompatActivity是AndroidX提供的一个向下兼容的Activity,可以让Activity在不同系统版本中的功能保持一致性。而Activity是Android提供的一个Activity基类,所有自己自定义的Activity都需要继承于它或它的子类(AppCompatActivity就是它的子类)。然后可以看到该MainActivity类有一个onCreate()函数,这个方法是Activity组件创建时必须要执行的方法,而且只有两行代码,可以看到这里并没有我们使用该APP显示的HelloWorld字符串,那么显示的HelloWorld到底在哪里呢?
Android程序设计讲究逻辑和视图分离, 因此一般不要再Activity里面直接编写界面加逻辑的,更加通用的办法是:在布局文件中编写界面,然后再在Activity中引入进来。
在MainActivity类中的onCreate()方法中的第二行调用了setContentView()方法,就是这个方法给当前的Activity引入了一个activity_main布局,那么“Hello World!”就一定在该R.layout.activity_main里面定义的,前面有提到所有的资源在res下,所有的布局文件又在res下的layout里面,所以直接去查看布局文件:
切换成code(代码)视角:
<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:text=".....",就是这里我们想要的Hello World。
总结一个项目的运行流程:进入一个app首先是获取AndroidManifest.xml文件中注册的Activity组件,然后看到的是Activity里面的MainActivity,就好比一个C语言程序里面的main函数,然后根据MainActivity里面的代码逻辑获取得到布局文件最后展示出来。
如何使用日志工具
在Android里面的日志工具是非常重要的,特别是对于开发者来说,是非常重要的。
Android中的日志工具类是Log(android.util.Log),提供了5个方法来打印日志:
Log.v() | 打印最低级别的日志,对应级别是verbose |
---|---|
Log.d() | 打印一些调试信息,对应级别是debug,比verbose高一级 |
Log.i() | 打印一些比较重要的信息,可以分析用户行为的数据,对应级别为info,比debug高一级 |
Log.w() | 打印警告信息,对应级别为warn比info高一级 |
Log.e() | 打印错误信息,对应级别为error |
在helloworld项目中使用日志工具:在MainActivity.kt里面添加Log.d("MainActivity","onCreate execute")
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
Log.d("MainActivity","onCreate execute")
}
}
再在Logcat下面就可以看到日志信息了。
通过过滤器来查看不同的Log信息。
总结