赞
踩
本系列文章主要针对Android 10(Q)进行介绍。
Android大致可以分为4层架构:
Android系统是基于Linux内核的,这一层为Android设备的各种硬件提供了底层的驱动,如显示驱动,音频驱动,相机驱动,蓝牙驱动,Wi-Fi驱动,电源管理等。
这一层通过一层C/C++库为Android系统提供了主要的特性支持。如SQLite库提供了数据库的支持,OpenGL|ES提供了3D绘图的支持,Webkit库提供了浏览器内核的支持等。
这一层还有Android运行时库,其主要提供了一些核心库,允许开发者使用Java语言来编写Android应用。另外,Android运行时库中还包含了Dalvik虚拟机(5.0系统之后改为ART运行环境),其使得每一个Android应用都能运行在独立的进程中,并且拥有一个自己的虚拟机示例。相较于Java虚拟机,Dalvik和ART都是专门针对移动设备定制的,它针对手机内存,CPU性能有限等情况做了优化处理。
这一层主要提供了构建应用程序时可能用到的各种API,Android自带的一些核心应用就是使用这些API完成的,开发者可以使用这些API来构建自己的应用程序。
所有安装在手机上的应用程序都是属于这一层的,比如系统自带的联系人,短信等程序,或者是从Google Play上下载的软件,自己开发的程序等。
Android系统为开发优秀的应用程序提供了很多便利的功能。
Android系统四大组件分别是Activity,Service,BroadcastReceiver和ContentProvider。
Android系统为开发者提供了丰富的系统空间,使得用户可以方便地编写漂亮的界面。同时用户还可以定制自己的控件。
Android系统还自带了这种轻量型,运算速度极快的嵌入式关系型数据库。其不仅支持标准的SQL语法,还可以通过Android封装好的API进行操作,让存储和读取数据变得非常方便。
Android系统还提供了丰富的多媒体服务,如音乐,视频,录音,拍照等,这些功能都可以在程序中使用代码进行控制,从而丰富应用的功能。
开发Android程序所需要准备的工具主要有以下3个:
JDK:JDK是Java语言的软件开发工具包,它包含了Java的运行环境,工具集合,基础类库等内容
Android SDK:Android SDK是Google提供的Android开发工具包,在开发Android程序时,需要通过引入该工具包来使用Android相关的API
Android Studio:之前Android项目都是使用Eclipse开发的,通过安装ADT插件就可以用来开发Android程序了。而Android Studio则是Google推出的一款官方的IDE工具,使用更为方便
Google将开发环境的搭建进行了集成,下载最新的开发工具就可以完成整个环境的搭建。工具的下载站点是:
Download Android Studio & App Tools - Android Developers
Android Studio 应用社区-安卓应用下载中心:安卓游戏/安卓软件/游戏合集/软件合集/安卓游戏下载/安卓软件下载
在环境搭建完成之后,当然是编写HelloWorld了。
首先创建一个新的项目:
从上面的项目创建可以看出,能够选择创建手机,平板,可穿戴设备,TV等类型项目,但这里只关注手机和平板。
项目创建中的各项字段含义为:
之后,项目创建成功。
Android Studio自动生成了很多东西,此时不需要编写任何代码,该项目即可运行。不过在此之前,还需要有一个运行的载体,可以是一个真正的手机,也可以是Android模拟器。这里先使用模拟器运行程序。
模拟器可以在Android Studio的界面上创建,选择设备,下载对应的镜像,然后启动。之后模拟器就会像一个真正的手机一样,有一个开机过程,启动完成后的模拟器如下:
现在模拟器已经启动了,之后就可以将该项目运行到模拟器上。
各项图标的含义为:
项目运行之后,在模拟器上的显示如下:
之后,在启动器列表中也可以看到多了一个HelloWorld应用:
其实整个过程中并没有编写任何代码,但是项目还是可以运行的,这是因为Android Studio已经自动生成的。这里看一下整个项目代码结构:
这里看一下上面显示的内容含义。
.gradle和.idle
这两个目录下放置的都是Android Studio自动生成的一些文件,无须关心,无须手动编辑。
app
项目中的代码,资源等内容都是放置在这个目录下的。
build
这个目录主要包含了一些在编译时自动生成的文件,也无须关心。
gradle
这个目录下包含了gradle wrapper的配置文件,使用gradle wrapper的方式不需要提前将gradle下载好,而是会自动根据本地的缓存情况决定是否需要联网下载gradle。Android Studio默认就是启动gradle wrapper方式的,如果需要更改成离线模式,可以在Settings中进行配置更改。
.gitignore
该文件是用来将指定的目录或文件排除在版本控制之外的。
build.gradle
这是项目全局的gradle构建脚本,通常这个文件中的内容是不需要更改的。
gradle.properties
该文件是全局的gradle配置文件,在这里配置的属性将会影响到项目中所有的gradle编译脚本。
gradles和gradlew.bat
这两个文件是用来在命令行界面中执行gradle命令的,其中gradlew是在Linux或Mac系统中使用的,gradlew.bat是在Windows系统中使用的。
local.properties
该文件用于指定本机中的Android SDK路径,通常内容是自动生成的,无需更改。如果本机中的Android SDK位置发生了变化,将该文件中的路径更改为新的位置即可。
settings.gradle
该文件用于指定项目中所有引入的模块。由于HelloWorld项目中只有一个app模块,因此该文件中也就只引入了app这一个模块。通常情况下,模块的引入是自动完成的。
上面提到的文件和目录大部分都是自动生成的,无需更改,而app目录下内容才是项目中的重点,其结构为:
这里看一下上面显示的内容含义。
build
该目录和之前的build目录类似,也包含了一些在编译时自动生成的文件,其内容也更加复杂,不过也无须关心。
libs
如果项目中包含了第三方jar包,就需要把这些jar包都放在libs目录下,放在这个目录下的jar包会被自动添加到项目的构建路径中。
androidTest
这里是用来编写Android Test测试用例的,可以对项目进行一些自动化测试。
java
该目录是放置所有Java代码的地方,也包含Kotlin的代码,在该目录下,系统已经主动生成了一个MainActivity文件。
res
该目录下的内容包含项目中使用到的所有图片,布局,字符串等资源。该目录还包含很多子目录,图片放在drawable目录下,布局放在layout目录下,字符串放在values目录下。
AndroidManifest.xml
这是整个项目的配置文件,程序中定义的所有四大组件都需要在该文件中注册,另外还可以在该文件中给应用程序添加权限声明。
test
这里用来编写Unit Test测试用例,是对项目进行自动化测试的另一种形式。
.gitignore
该文件用于将app模块内指定的目录或文件排除在版本控制之外,作用和外层的.gitignore
文件类似。
build.gradle
这里app模块的gradle构建脚本,该文件中指定了很多项目构建相关的配置。
proguard-rules.pro
该文件用于指定项目代码的混淆规则,当代码开发完成后打包成安装包文件,如果不希望代码被别人破解,通常会将代码进行混淆。
这里看一下HelloWorld项目是如何运行的。首先是AndroidManifest.xml文件:
- <?xml version="1.0" encoding="utf-8"?>
- <manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.example.helloworld">
-
- <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
- android:name=".MainActivity"
- android:exported="true">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- </application>
-
- </manifest>
上边的文件中,activity节点中的代码段表示对MainActivity的注册,没有在AndroidManifest.xml文件中注册的Activity是不能够使用的。其中intent-filter中的两行代码比较重要,表示MainActivity是该项目的主Activity,在手机上点击应用图标,首先启动的就是该Activity。
而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是Activity的子类)。
同时上面的代码中还有一个onCreate()方法,该方法是一个Activity被创建时必定要执行的方法,其中只有两行代码,并且没有“Hello World!”的字样。那么其显示又是从何而来的?
其实Android程序设计讲究逻辑与视图分离,因此更一般的做法是在布局文件中编写界面,然后在Activity中引入进来。可以看到onCreate()方法的第二行调用了setContentView()方法,就是该方法给当前的Activity引入了一个activity_main布局:
- <?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>
之前提到图片,布局,字符串等内容都放置在res目录下,同样上面的文件也位于res/layout目录下,上边的TextView中的内容正是"Hello World!"。
既然所有的资源都是在res目录下的,那么看一下其目录结构:
上边显示的内容中:
而之所以有很多mipmap开头的目录,其实是为了使程序能够更好地兼容各种设备,其它目录也有类似的作用,虽然Android Studio没有自动生成,但是用户也可以手动创建drawable-hdpi,drawable-xhdpi,drawable-xxhdpi等目录。在应用开发时,最好能够为同一张图片准备不同分辨率的版本,放置在对应目录下,程序在运行的时候,会自动根据当前运行设备分辨率的高低选择加载哪个目录下的图片。只不过这是最好的情况,更多的时候只会存在一份图片,此时只要将所有图片都放在drawable-xxhdpi目录下就好了,因为这是最主流的设备分辨率目录。
比如res/values/strings.xml文件:
- <resources>
- <string name="app_name">HelloWorld</string>
- </resources>
上面文件中定义了app_name,这对应应用程序名的字符串,可以通过两种方式进行应用:
上边提到的是基本的语法,其中string部分可以替换为drawable,以引用图片资源,替换为mipmap,以引用应用图标,替换为layout,以引用布局文件。
比如之前提到的AndroidManifest.xml文件中的icon,lable,roundIcon等都是采用了上面的引用形式:
- <?xml version="1.0" encoding="utf-8"?>
- <manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.example.helloworld">
-
- <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
- android:name=".MainActivity"
- android:exported="true">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- </application>
-
- </manifest>
Android Studio是通过Gradle进行项目构建的,该工具基于Groovy的领域特定语言(DSL)来进行项目设置,而不同于基于XML的繁琐配置。
在之前的目录结构中,提到存在两个build.gradle文件,一个在最外层的项目目录下,另一个在app目录下,这两个文件都对项目构建起到了重要的作用。这里看一下这两个文件,首先是最外层的build.gradle文件:
// Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { repositories { google() mavenCentral() } dependencies { classpath "com.android.tools.build:gradle:7.0.0" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.20" // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } } task clean(type: Delete) { delete rootProject.buildDir }
上面的代码都是自动生成的:
而内层app下的build.gradle文件为:
plugins { id 'com.android.application' id 'kotlin-android' } android { compileSdk 33 defaultConfig { applicationId "com.example.helloworld" minSdk 21 targetSdk 33 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 'androidx.core:core-ktx:1.3.2' implementation 'androidx.appcompat:appcompat:1.2.0' implementation 'com.google.android.material:material:1.3.0' implementation 'androidx.constraintlayout:constraintlayout:2.0.4' testImplementation 'junit:junit:4.+' androidTestImplementation 'androidx.test.ext:junit:1.1.2' androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' }
上面的内容中:
sourceCompatibility:指定编译编译.java文件的jdk版本
targetCompatibility:确保class文件与targetCompatibility指定版本,或者更新的Java虚拟机兼容
kotlinOptions:指定Kotlin的相关选项
jvmTarget:指定kotlin相关的编译配置
dependencies:指定当前项目的所有依赖关系,通常项目中可能存在三种依赖关系:本地依赖,库依赖和远程依赖。本地依赖可以对本地的jar包或目录添加依赖关系,库依赖可以对项目中的库模块添加依赖关系,远程依赖则可以对之前提到的仓库上的开源项目添加依赖关系
implementation fileTree():表示本地依赖声明,这里没有用到
implementation:表示远程依赖,如 androidx.appcompat:appcompat:1.2.0就是一个标准的远程依赖库格式, androidx.appcompat表示域名部分,用于和其它公司的库做区分,appcompat表示工程名部分,用于和同一个公司中不同的库工程做区分,1.2.0表示版本号,用于和同一个库不同的版本做区分。加上这句声明后,Gradle在项目构建时会首先检查一下本地是否已经有该库的缓存,如果没有的话则会自动联网下载,然后再添加到项目的构建路径中。
implementation project():表示库依赖声明,这里没有用到
testImplementation:用于声明测试用例库
androidTestImplementation:用于声明测试用例库
Android中的日志工具类是Log(Android.util.log),该类中提供了5种方法来打印日志:
为了验证打印内容,可以将之前的MainActivity修改为:
- package com.example.helloworld
-
- import androidx.appcompat.app.AppCompatActivity
- import android.os.Bundle
- import android.util.Log
-
- class MainActivity : AppCompatActivity() {
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_main)
- Log.d("MainActivity","Hello World")
- }
- }
在Log.d()中存在两个参数:
之后运行项目,在Logcat中就可以看到打印信息:
2022-09-04 20:05:49.382 11550-11550/com.example.helloworld D/MainActivity: Hello World
打印的内容包含日期,时间,进程号,包名,日志等级,类名,打印信息,可以说是很详细了。
其实从上面的内容看,Log类的作用就是进行信息的打印,其功能和println差不多,这里将上边的代码进行修改,对比一下:
- package com.example.helloworld
-
- import androidx.appcompat.app.AppCompatActivity
- import android.os.Bundle
- import android.util.Log
-
- class MainActivity : AppCompatActivity() {
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_main)
- Log.d("MainActivity","Hello World")
- println("MainActivity" + " " + "Hello World")
- }
- }
其相关打印结果为:
- 2022-09-04 20:17:06.043 11854-11854/com.example.helloworld D/MainActivity: Hello World
- 2022-09-04 20:17:06.043 11854-11854/com.example.helloworld I/System.out: MainActivity Hello World
从上面打印结果来看,虽然都能够定位到是MainActivity这个类,但是其形式并没有使用Log类方便。同时使用Log类还有两个好处,一个是可以对打印内容的重要性进行分级,另一个是可以在调试的时候对打印内容进行过滤。
上图显示的内容为:
比如添加如下的过滤器:
这样就能够在Logcat中过滤tag为MainActivity的所有日志。
而Logcat还可以进行日志级别控制:
上图显示的内容为:
同时Logcat中还支持关键字搜索,其功能类似文本编辑器中的内容搜索,不过Logcat中的关键字搜索支持正则表达式。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。