Android学习笔记2 - 分析第一个应用
上一章已经创建了一个应用程序,这一节我们需要了解和分析下这个应用。
项目视图界面
在Android Studio中(后面简称AS,当然不是Flex的ActionScript,也是AS,:)),在左侧界面Project里默认是Android视图(如下图),这不是真正的目录结构,类似于VS的类视图一样,我们切换成Project视图就是目录结构了。
我们对Project文件结构先找几个能理解的说明一下,其他的后面又机会再详细研究。
- app目录最日后我们编写代码资源等都放在这里的。
- build是编译时自动生成的。
我们重点先看看app目录。
- build和外面的一样,也是编译时产生的。
- libs用到的第三方jar包。
- androidTest是用来编写测试用例的。
- java存放java代码和Kotilin代码的地方。里面有一个MainActivity文件。
- res存放图片drawable、布局layout、字符串values等资源。
- AndroidManifest.xml是整个项目的配置文件,程序中定义的4大组件需要再这里注册,还有应用程序添加的权限声明。
- test编写单元测试的。
- build.gradle是app模块的gradle构建脚本,和项目相关的。
- proguard-rules.pro代码的混淆规则。
从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就是主Activity,没有在这里注册的acivity是不能使用的。我们打开java里的MainActivity.kt代码。
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
}
他继承自AppCompatActivity,所有的Activity都必须继承自他。
AS的设计讲究逻辑和视图分离,所以一般不在activity中编写界面。
布局Layout
第二行的setContentView(R.layout.activity_main)调用了一个布局方法,我们打开layout目录里面有activity_main.xml。
<?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="@string/app_name"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
布局看起来和HTML和CSS有点相似,有一个TextView组件,应该就是显示Hello的组件了。
引用values
android:text="@string/app_name"
上面这行代码,就是显示Hello World。我修改过,增加了@进行了引用string
我们打开values\strings.xml
<resources>
<string name="app_name">HelloWorld!!!</string>
</resources>
在代码中引用values可以使用R.string.app_name,在xml中可以使用上面@的方法。
如果是引用图片可以把string替换成drawable。如果是引用应用图标mipmap,我们可以把string换成mipmap。
mipmap
在res目录下有很多的mipmap,目的是为了兼容各种设备,不同的设备会有不同的分辨率,这是最理想的情况,一般我们直接把图片放在drawable-xxhdpi下就可以了,这是主流的分辨率目录。(不知道其他的能不能删除掉?看着烦)
其他参数
应用的图标和应用名称是通过下面两行设定的。
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
Build.gradle
AS是通过Gradle来构建项目的。他采用了给予Groovy的DSL语言来进行项目设置。
项目中有一个app里面的,一个外面的gradle文件。
最外层的setting.gradle
这个目前的版本和书中讲的是不一样的,可能版本更新了。书中说是build.gradle,但是我的项目里settings.gradle文件和书中的基本一致。
pluginManagement {
repositories {
gradlePluginPortal()
google()
mavenCentral()
}
}
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
}
}
rootProject.name = "HelloWorld"
include ':app'
repositories 里 引用了google的扩展依赖库和jcenter的第三方开源库。
而在最外层的build.gradle里
// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
id 'com.android.application' version '7.1.2' apply false
id 'com.android.library' version '7.1.2' apply false
id 'org.jetbrains.kotlin.android' version '1.5.30' apply false
}
task clean(type: Delete) {
delete rootProject.buildDir
}
引用的插件格式变为了上面的格式
id ‘name’ version ‘0.0’ apply false
这里是全局的配置,影响所有的子项目模块。
项目里app下的gradle
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
}
android {
compileSdk 32
defaultConfig {
applicationId "com.example.helloworld"
minSdk 21
targetSdk 32
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.7.0'
implementation 'androidx.appcompat:appcompat:1.4.1'
implementation 'com.google.android.material:material:1.5.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}
第一行 id ‘com.android.application’
表示是一个应用模块,如果是库就是com.android.library。
第二行 id ‘org.jetbrains.kotlin.android’
应该是使用Kotlin来开发Android必须的。
接下来android大括号里的
compileSdk 使用的编译版本
defaultConfig
- applicationId 是唯一的ID
- List item
- minSdk 支持最低的版本21就是android 5.0
- versionCode 版本号
- versionName 版本名称
- testInstrumentationRunner 用于JUnit测试。
buildTypes
用于指定生成安装文件的配置,一会只会有debug、release。
- minifyEnabled 是否混淆
- proguardFiles 混淆时使用的规则文件
proguard-android-optimize.txt是在/tools/proguard目录下。
proguard-rules.pro在app目录下的规则文件。
dependencies
这个是项目的所有依赖关系。通常分为3种依赖方式:本地依赖、库依赖、远程依赖。
- 本地依赖对本地的jar包或者目录添加依赖关系。
- 库依赖可以对项目种的库模块添加依赖关系。
- 远程依赖可以对jcenter仓库上的开源项目添加依赖关系。
implementation是远程的依赖声明,前4个。项目在构建时会检查本地是否已经有这些库的缓存,如果没有会线自动下载。
日志工具
安卓的日志工具类是Log(android.util.Log),他又5个方法。
- Log.v() - 用于打印最琐碎的,verbose级别,最低级。
- Log.d() - 用于打印调试信息,debug级别。
- Log.i() - 用于打印比较重要的数据,通常是你要看的,info级别。
- Log.w() - 用于打印警告信息,可能又潜在风险需要修复。warn级别。
- Log.e() - 用于打印错误信息,例如catch里,一般是严重错误,error级别。
我们来测试一下,我们编辑MainActivity.kt
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.v("test","日志v");
Log.d("test","日志d");
Log.i("test","日志i");
Log.w("test","日志w");
Log.e("test","日志e");
}
}
我们Shift+F10运行,在Logcat视图里我们可以看到有Log输出了。
运行起来以后,Logcat里大量的信息刷屏,我们需要在第二个下拉框,选择com.example.helloworld项目,这样只会看到本项目的信息了,在第四个下来框我输入了刚才我们的tag,可以过滤出含有test关键字的。第三个下来框是过滤重要信息的,如果选择了Verbose就是所有信息,如果选择到Info,只会看Info及以上等级的日志了。
很多Java新手会使用system.out.println()来打印日志,在Kotlin种对应的是println方法,日志开关不可控,所以滥用会被骂的。
最后的下拉框是过滤器,默认是Show only select application
这里我们可以自定义过滤器,我刚才在搜索框里输入的test只能过滤含有test关键字的,如果程序里还有大量的其他test单词组合的也是无法过滤掉的。那么自定义过滤器可以设定tag,等级其他信息。
我们选择了test过滤器,看看是不是很方便,工作中规范使用Log,给调试会带来很多方便之处。
本章到这里了,我们基本了解了项目大致文件目录分类和作用。
下一章我会大概记录下Kotlin语法和其他语法差异之处。
参考
《第一行代码》Android第三版