安卓开发 第1章 开始启程——你的第一行Android代码


1.3 创建第一个Android项目

1.3.1 创建HelloWorld项目

欢迎界面点击Start a new Android Studio project,打开创建新项目页面:

选择Empty Activity模板,应用名HelloWorld,兼容最低版本安卓4.0.3.

1.3.2 启动模拟器

1.3.4 分析你的第一个Android应用

将Android结构切换为Project结构易于理解:

1. .gradle和.idea

Android Studio自动生成文件,无需关心,也不用手动编辑。

2.app

项目中的代码,资源等内容几乎都是放置在这个目录下的,我们的后续开发工作也基本上是在这个目录下进行的。

3.build

主要包含了在编译时自动生成的文件,不用多加关心。

4.gradle

这个目录下包含了gradle wrapper的配置文件。

5. .gitignore

这个文件用来将指定的文件或目录排除在版本控制之外。

6.build.gradle

这是项目全局的gradle构建脚本,通常这个里面的内容是不用修改的。

7.gradle.properties

这个文件是全局的gradle配置文件,在这里的属性将会影响到项目中所有的gradle编译。

8.gradlew和gradlew.bat

这两个文件是为了在命令行界面执行gradle命令的,其中gradlew是在Linux或者Mac上使用的,.bat是在Windows上使用的。

9. HelloWorld.iml

iml文件是IntelliJ IDEA项目都会自动生成的一个文件,用于标识这是一个IntelliJ IDEA项目,我们不需要改变这个文件的任何内容。

10.local.properties

这个文件用来指定本机中的SDK路径,通常都是自动生成的,不用修改。除非我们的SDK位置发生变化,那么只需要改成新的位置就可以了。

11.settings.gradle

用于指定文件项目中引入的模块。这里面只引入一个模块app。通常情况下模块引入都是自动引入的,我们需要修改的情况较小。

除了app目录之外,大部分都是自动生成的,因此我们要对app模块有更加深入的了解:

1. build

主要包含编译自动生成的文件,里面的内容比外层更复杂,不需要过多关心。

2.libs

项目中使用的第三方jar包,就需要放在libs下,这个目录下的包都会被自动添加到构建目录中去。

3.androidTest

此处是用来编写Android Test测试用例的,可以对项目做一些自动化测试。

4. java

这里是你所有Java代码的地方,打开后MainActivity文件就在里面。

5.res

项目中使用的图片,布局,字符串等资源都必须放在这个目录下。图片放在drawable,布局文件放在layout下,字符串放在values下。

6.AndroidManifest.xml

这是你整个Android项目的配置文件。你在程序中定义的四大组件都需要在这个文件注册。另外还可以在这个文件中给应用程序添加权限声明。由于这个文件以后会经常用到,用到时会做详细说明。

7.test

编写Unit Test用例,另一种自动化测试方式。

8. .gitignore

用于将app模块指定的目录排除在版本控制之外,和外层的ignore文件相似。

9.app.xml

IntelliJ IDEA自动生成的文件,不需要关心或者修改这个文件的内容。

10. build.gradle

app模块中的gradle构建脚本,会指定许多项目构建相关的配置。

11.proguard-rules.pro

用来指定代码的混淆规则,当代码开发完成后,不希望别人破解代码,就会对代码进行混淆。

首先了解HelloWorld项目是怎么运行的,下面是AndroidManifest.xml文件,里面有以下代码:

 
            
                
                
            
        

这段代码表示对MainActivity这个活动的注册,没有在AndroidManifest.xml注册的活动是不能使用的。3和4行代码表示的是手机上点击应用图标,打开的就是这个活动。

四大组件:

活动(Activity),服务(Service),广播接收器(Broadcast Receiver),内容提供器(Content Provider)。活动是所有Android应用程序的门面,凡是应用中看得到的东西,都放在活动中。服务比较低调,无法看到他,但是会在后台静默运行。广播接收器允许你的应用接受来自各处的广播消息,例如电话,短信等,你的应用也可以向外广播。内容提供器为应用程序共享提供了可能,比如读取联系人信息。

看一下活动代码:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}

MainActivity是从AppCompatActivity继承来的,这是向下兼容的Activity,最低兼容到Android 2.1.Activity是安卓系统提供的一个活动基类,我们所有活动都必须继承它或者它的子类才能拥有活动特性(AppCompatActivity是Activity的子类)。可以看到onCreate方法,这是活动要被创建必须执行的一个方法。

Android讲究逻辑和视图分离,因此是不推荐活动中直接编写界面。第6行的setContentView引入了activity_main布局。布局文件都在res/layout下,打开后切换到Text视图:

<?xml version="1.0" encoding="utf-8"?>


    


android:text="Hello World!"提供了我们的字符串。

1.3.5 详解项目中的资源

  • drawable——图片
  • mipmap——图标
  • values——字符串,颜色,样式
  • layout——布局

mipmap这么多是为了应对不同的分辨率。

如何使用这些资源?

打开res/values/strings.xml


    HelloWorld

这里定义了一个应用名字的引用,你有两种引用方式:

  • 代码中通过R.string.app_name可以获得该字符串的引用
  • XML中通过@string/app_name即可获得引用

string的部分是可以更换的,例如drawable,mipmap或者layout。

1.3.6 详解build.gradle文件

Android Studio是通过Gradle构建项目的,是一个非常先进的项目构建语言。先看外层目录下的:

// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    repositories {
        google()
        jcenter()
        
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.5.3'
        
        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

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

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

两处repositories闭包里面都声明了jcenter,这是一个托管仓库,声明这行配置之后,我们就可以在项目中引用jcenter上面的开源项目。

dependcies闭包里面使用classpath声明了一个Gradle插件。声明的原因是Gradle不是专门为Android开发的,因此需要声明。

下面是内层的build.gradle文件:

apply plugin: 'com.android.application'

android {
    compileSdkVersion 29
    buildToolsVersion "29.0.3"
    defaultConfig {
        applicationId "com.example.helloworld"
        minSdkVersion 15
        targetSdkVersion 29
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'androidx.appcompat:appcompat:1.0.2'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test.ext:junit:1.1.0'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
}

第一行应用了一个插件,有两种值可选:com.android.application表示是一个应用程序模块,com.android.library表示是一个库模块。区别在于,应用模块可以直接运行,库模块作为代码库需要依附于别的应用模块运行。

接下来是大的android闭包,可以配置安卓信息。

  • compileSdkVersion——SDK版本

  • buildToolsVersion——项目构建工具版本

  • defaultConfig闭包:

    • applicationId——包名,后期在这里修改包名
    • minSdkVersion——最低兼容版本
    • targetSdkVersion——已在该目标版本做过充分测试
    • versionCode——版本号
    • versionName——版本名
  • buildTypes闭包:

    • debug闭包:指定生成测试文件的配置,可以不写
    • release闭包:
      • minifyEnabled——是否对代码进行混淆
      • proguardFiles——混淆规则
      • proguard-android-optimize.txt——在Android SDK下,是所有项目通用混淆规则
      • proguard-rules.pro——当前根目录下特有混淆规则
  • dependencies闭包:指定当前项目所有依赖关系

    通常有3种依赖方式:

    1. 本地依赖——通过jar包或者目录
    2. 库依赖——对项目的库模块添加依赖关系
    3. 远程依赖——对jcenter的开源项目进行依赖
    • implementation fileTree——本地依赖声明,把libs目录下所有.jar文件加入构建路径
    • implementation——远程依赖格式
    • 库依赖没有用到,声明格式为compile project(':helper'),如果库名是helper。

1.4 日志工具的使用

1.4.1 使用Android的日志工具Log

  • Log.v——打印琐碎的,意义最小的日志信息。对应级别verbose,是级别最低的一种。
  • Log.d——打印调试信息,对调试程序和分析程序有帮助。对应级别debug。
  • Log.i——打印比较重要的数据,这是很想看到的,分析用户行为,级别info。
  • Log.w——打印警告信息,有潜在的风险,最好去修复这些地方,级别warn。
  • Log.e——打印错误信息,比如程序进入catch语句中,必须修复,对应级别error。

在onCreate里面加入这么一行语句:

import android.util.Log;    //一定要导入否则会出错

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d("MainActivity","onCreate execute");
    }
}

第一个参数是tag,一般传入当前类名,第二个是msg,是具体要打印的内容。

运行结果:

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

快捷输入:

  • logi+Tab打下info级别的日志
  • onCreate方法外输入logt+Tab自动生成TAG常量
  • 还可以自定义Filter