Android应用程序建立在应用程序框架之上,所以Android编程就是面向应用程序框架API编程——这种开发方式与编写普通的Java或Kotlin应用程序并没有太大的区别,只是Android新增了一些API而已。
使用Android Studio开发Android应用非常方便,因为Android Studio会为我们自动完成许多工作。使用Android Studio开发Android应用大致需要如下3步。
- 创建一个Android项目或Android模块。
- 在XML布局文件中定义应用程序的用户界面。
- 在Java或Kotlin代码中编写业务实现。
第一步就不详细讲了,直接来看XML布局文件。
上面XML文档的根元素是RelativeLayout,它代表一个相对布局,在该界面布局里包含如下两个UI控件。
可能有读者感到奇怪: Android怎么采用XML文件来定义用户界面呢?或者有过Swing编程经验的读者感到不习惯:怎么不是在Java代码里定义用户界面,而是在XML文档里定义用户界面呢?
大家要接受Android的这种优秀设计。Android把用户界面放在XML文档中定义,就可以让XML文档专门负责用户UI设置,而Java程序则专门负责业务实现,这样可以降低程序的耦合性。对于不习惯这种方式的读者来说,其实可以近似地把activity_main.xml文件当成一个HTML页面―它们都通过标记语言来定义用户界面。区别在于HTML页面使用HTML标签,而activity_main.xml文件则使用Android标签。
Android Studio项目下的app\src目录是Android项目的源代码,该目录的main\java\org\crazyit\helloworld目录下有一个MainActivity.java文件,它就是Android项目的Java文件。打开该文件,将该文件编辑为如下形式。
public class MainActivity extends Activity
{
@Override
public void onCreate (Bundle savedInstanceState){
super.onCreate ( savedInstancestate) ;
//使用activity_main. xml文件定义的界面布局
setContentview(R.layout.activity_main) ;
}
public void clickHandler (View source){
//获取UI界面中ID为R.id.show的文本框
Textview tv =(Textview) findViewById (R.id.show) ;//改变文本框的文本内容
tv.setText( "Hello Android-" + new java.util.Date () ) ;
}
}
对于一个有不错的Java基础的读者来说,上面这个程序十分简单,它只做了如下两件事情。
- 设置该Activity使用activity_main.xml文件定义的界面布局作为用户界面。
- 定义了一个clickHandler()方法作为按钮的事件处理方法——在处理方法中改变ID为R.id.show的文本框的内容。
提示:
如果当前电脑不止连接一个Android设备,可以自行选择。不会像以前一样,弹出提示让你选择。
在HelloWorld目录下的app则代表一个模块,因此Android项目的全部内容其实就在该目录下。app目录结构如下:
app
┣━━build:存放编译后的class文件、资源的文件夹,该文件夹与src具有对应关系
┣━━libs:存放第三方JAR包的文件夹
┣━━src:分类存放各种源文件,资源文件
┃ ┣━━androidTest
┃ ┣━━main
┃ ┃ ┣━━java:存放与项目相关的Java或Kotlin源文件
┃ ┃ ┃ ┗━━org
┃ ┃ ┃ ┗━━crazyit
┃ ┃ ┃ ┗━━helloworld
┃ ┃ ┣━━res:
┃ ┃ ┃ ┣━━drawable
┃ ┃ ┃ ┣━━layout
┃ ┃ ┃ ┣━━mipmap-xxx
┃ ┃ ┃ ┗━━values
┃ ┃ ┗━━AndroidManifest.xml
┃ ┃
┃ ┗━━test:主要存放与 测试 相关的源文件和资源
┣━━build.gradle: Gradle构建文件
┗━━.gitignore (该文件配置Git工具忽略管理哪些文件)
app目录是一个典型的Gradle项目, 其中build.gradle是该项目的构建文件;build 存放项目的构建结果;libs目录存放着该项目所依赖的第三方类库;src是项目开发的重点,所有源代码和资源都放在该目录下。可见,Android Studio 使用Gradle作为项目构建工具。
打开build.gradle文件,可以看到开头的三行如下:
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
这三行指定了该构建文件应用的插件,所有的Android 项目构建都需要使用com.android.application插件,除非你打算自己来完成所有的构建工具。如果打算使用Kotlin来开发Android 项目,则需要第2行和第3行。
build.gradle文件的接下来部分则负责为该项目定义全局属性。
构建文件的最后部分定义项目依赖:
dependencies {
//implementation定义项目主源代码的依赖
//下面配置依赖libs目录下的所有JAR包
implementation fileTree(dir: 'libs',include: ['*.jar'])
//下面配置从中央仓库下载依赖JAR包
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
//testImplementation定义项目测试代码(test目录下的代码)的依赖
testImplementation 'junit:junit:4.13.2'
//androidTestImplementation定义androidTest目录下的代码依赖
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
//打包引用
api 'com.blankj:utilcode:1.23.7'
}
Gradle新版本里面依赖的写法支持implementation和api,下面简单解释两者的区别:
- implementation 表示依赖,即 只依赖不打包进来。
- api 表示打包,即 不仅依赖还打包进来,这样上层就不用重复依赖。
从上面的依赖配置来看,该Android 项目所使用的构建文件与前面介绍的 Gradle生成文件基本一致,只是 Android 项目额外增加了一个sourceSet: androidTest,因此 Android项目额外多出一组依赖。
上面依赖配置的第1行指定将libs目下的所有JAR包都添加成该项目的依赖包;接下来几行则指定需要从中央仓库下载JAR包一在默认情况下,Android Studio 将会从国外的中央仓库下载它们,如果网络不能顺畅地连接国外网络,Android Studio将会报错。
为了避免这个问题,我们可以在 build.gradle 文件中配置国内中央仓库,或者在企业内部服务器上配置本地中央仓库来解决该问题。
提示:
.gitignore是版本控制工具 Git所需要的文件,用于列出哪些文件不需要接受Git的管理。一般来说,只有项目源文件和各种配置文件才需要接受Git的管理。
正如前面关于Gradle 的介绍,src目录通常包含主源代码(main子目录)和测试代码(test子目录)。此外,Android项目额外多出一组测试代码: androidTest,代表了Android测试项目。如果暂时不理会测试代码,则可直接进入main目录。
main目录下的 java目录、res目录(对应于标准的 Gradle项目叫作 resources目录)、AndroidManifest.xml文件是 Android项目必需的。
- java目录:保存Java或Kotlin源文件。
- res目录:存放Android项目的各种资源文件。比如 layout子目录存放界面布局文件,values子目录存放各种 XML 格式的资源文件,如字符串资源文件 strings.xml、颜色资源文件colors.xml、尺寸资源文件dimens.xml; drawable子目录存放XML文件定义的Drawable资源,如 drawable-ldpi、drawable-mdpi、drawable-hdpi、drawable-xhdpi、drawable-xxhdpi等子目录分别用于存放低分辨率、中分辨率、高分辨率、超高分辨率、超超高分辨率的5种图片文件。
- AndroidManifest.xml文件是 Android项目的系统清单文件,它用于控制Android应用的名称、图标、访问权限等整体属性。除此之外,Andriod应用的Activity、 Service 、ContentProvider、BroadcastReceiver这4大组件都需要在该文件中配置。
对于Android开发者而言,重点关注的就是如下两部分。
- app\src\main\java目录下的各种 Java或Kotlin文件。
- app\src\main\res目录下的各种资源文件。
提示:
与drawable子目录对应的还有一个 mipmap子目录,这两个子目录都用于存放各种Drawable资源。其区别在于: mipmap子目录用于保存应用程序启动图标及系统保留的Drawable资源;而drawable子目录则用于保存与项目相关的各种 Drawable资源。
进入app\build\generated\source\r\debug\org\crazyit\helloworld目录,可以看到Android Studio自动生成的R.java文件(这是旧版的AS,新版的该目录下已经没有R.java文件了,后面再做解释)。
前面在编写Android程序代码时多次使用了R.layout.main、R.id.show、R.id.ok……现在读者应该明白这里的R是什么了,原来它是Android项目自动生成的一个 Java类。接下来将会详细介绍R.java文件。
R.java文件是由AAPT工具根据应用中的资源文件自动生成的,因此可以把R.java理解成Android应用的资源字典。
AAPT生成R.java文件的规则主要是如下两条。
- 每类资源都对应于R类的一个内部类。比如所有界面布局资源对应于layout内部类;所有字符串资源对应于string内部类;所有标识符资源对应于id内部类。
- 每个具体的资源项都对应于内部类的一个public static final int类型。例如,前面在界面布局文件中用到了show标识符,因此R.id类里就包含了这个字段;由于mipmap-xxx文件夹里包含了ic_launcher.png 图片,因此 R.mipmap类里就包含了ic_launcher字段。
随着我们不断地向Android项目中添加资源,R.java文件的内容也会越来越多。后面还会详细介绍Android资源访问的相关内容,因此后面还会进一步说明不同资源在R.java文件中的表现形式。
解释:新版Android Studio R.java丢失
AndroidGradle插件为了提高编译速度不直接生成R.java文件了,改为生成R类字节码。打包编译时处理该文件最终合到.dex文件中去!
查看的方法:
方法一:在主module的build/intermediates/runtime_symbol_list/debug/R.txt
方法二:
1.在output文件夹下面找到你的apk文件
2.把apk文件拖进分析区分析,点击dex文件,假如你的项目进行了分包的话这里的dex文件可能会有多个
3.找到你想查看R文件的包,比如我要查看QTextView这个类的R文件,就找到这个包
4.往下翻就能看到R$String,然后右键showByteCode即可方法三:
Android应用的res目录是一个特殊的项目,该项目里存放了Android应用所用的全部资源,包括图片资源、字符串资源、颜色资源、尺寸资源等—后面还会进一步介绍
Android应用中资源的用法,此处先对res目录的资源进行简单的归纳。
Android按照约定,将不同的资源放在不同的文件夹内,这样可以方便地让AAPT工具来扫描这些资源,并为它们生成对应的资源清单类:R.java。
以/res/value/strings.xml文件来说,该文件的内容十分简单,它只是定义了一个个的字符串常量,如以下代码所示。
Helloworld
上面的资源文件中定义了一个字符串常量,常量的值为HelloWorld,该字符串常量的名称为app_name。一旦定义了这份资源文件之后,Android项目就允许分别在Java代码、XML文件中使用这份资源文件中的字符串资源。
为了在Java代码中使用资源,AAPT会为Android项目自动生成一份R.java文件,R类里为每份资源分别定义了一个内部类,其中每个资源项对应于内部类里一个int类型的Field。如前图所示。
//对应于一份资源
public static final class string {
//对应于一个资源项
public static final int app name=0x7f040000;
}
借助于AAPT自动生成R类的帮助,在Java代码中可通过R.string.app_name引用到"HelloWorld"字符串常量。
在XML文件中使用资源更加简单,只要按如下格式来访问即可:
例如,我们要访问上面的字符串资源中定义的"HelloWorld"字符串常量,则使用如下形式来引用即可:
@string/app_name
但有一种情况例外,当我们在XML文件中使用标识符时—这些标识符无须使用专门的资源进行定义,直接在XML文档中按如下格式分配标识符即可:
@+id/<标识符代号>
例如,使用如下代码为一个组件分配标识符:
android:id="@+id/ok"
上面的代码为该组件分配了一个标识符,接下来就可以在程序中引用该组件了。
如果希望在Java代码中获取该组件,通过调用Activity的findViewByld ()方法即可实现。
如果希望在XML文件中获取该组件,则可通过资源引用的方式来引用它,语法如下:
@id/<标识符代号>
AndroidManifest.xml清单文件是每个Android项目所必需的,它是整个Android应用的全局描述文件。AndroidManifest.xml清单文件说明了该应用的名称、所使用的图标以及包含的组件等。
AndroidManifest.xml清单文件通常可以包含如下信息。
- 应用程序的包名,该包名将会作为该应用的唯—标识。
- 应用程序所包含的组件,如Activity、Service、BroadcastReceiver和ContentProvider等。
- 应用程序兼容的最低版本。
- 应用程序使用系统所需的权限声明。
- 其他程序访问该程序所需的权限声明。
不管是Android Studio工具还是android.bat命令,它们所创建的Android项目都有一个AndroidManifest.xml文件。但随着不断地进行开发,可能需要对AndroidManifest.xml清单文件进行适当的修改。
下面是一份简单的AndroidManifest.xml清单文件。
上面这份AndroidManifest.xml清单文件中的注释已经大致说明了各元素的作用,故不再详细说明每个元素。上面的清单文件中有两处用到了资源。
- android: label="@string/app_name",这说明该应用的标签(Label)为/res/value目录下strings.xml文件中名为app_name的字符串值。
- android: icon="@drawable/ic_launcher",这说明该应用的图标为/res/drawable-l/m/hdpi目录下主文件名为icon的图片。
一个Android应用可能需要权限才能调用Android系统的功能;一个Android应用也可能被其他应用调用,因此它也需要声明调用自身所需要的权限。
通过为
例如,在
通过上面的介绍可以看出,
权限 | 说明 |
ACCESS_NETWORK_STATE | 允许应用程序获取网络状态信息的权限 |
ACCESS_WlFI_STATE | 允许应用程序获取Wi-Fi 网络状态信息的权限 |
BATTERY_STATS | 允许应用程序获取电池状态信息的权限 |
BLUETOOTH | 允许应用程序连接匹配的蓝牙设备的权限 |
BLUETOOTH_ADMIN | 允许应用程序发现匹配的蓝牙设备的权限 |
BROADCAST_SMS | 允许应用程序广播收到短信提醒的权限 |
CALL_PHONE | 允许应用程序拨打电话的权限 |
CAMERA | 允许应用程序使用照相机的权限 |
CHANGE_NETWORK_STATE | 允许应用程序改变网络连接状态的权限 |
CHANGE_WIFI_STATE | 允许应用程序改变Wi-Fi网络连接状态的权限 |
DELETE_CACHE_FILES | 允许应用程序删除缓存文件的权限 |
DELETE_PACKAGES | 允许应用程序删除安装包的权限 |
FLASHLIGHT | 允许应用程序访问闪光灯的权限 |
INTERNET | 允许应用程序打开网络Socket 的权限 |
MODIFY_AUDIO_SETTINGS | 允许应用程序修改全局声音设置的权限 |
PROCESS_OUTGOING_CALLS | 允许应用程序监听、控制、取消呼出电话的权限 |
READ_CONTACTS | 允许应用程序读取用户的联系人数据的权限 |
READ_HISTORY_BOOKMARKS | 允许应用程序读取历史书签的权限 |
READ_OWNER_DATA | 允许应用程序读取用户数据的权限 |
READ_PHONE_STATE | 允许应用程序读取电话状态的权限 |
READ_PHONE_SMS | 允许应用程序读取短信的权限 |
REBOOT | 允许应用程序重启系统的权限 |
RECEIVE_MMS | 允许应用程序接收、监控、处理彩信的权限 |
RECEIVE_SMS | 允许应用程序接收、监控、处理短信的权限 |
RECORD_AUDIO | 允许应用程序录音的权限 |
SEND_SMS | 允许应用程序发送短信的权限 |
SET_ORIENTATION | 允许应用程序旋转屏幕的权限 |
SET_TIME | 允许应用程序设置时间的权限 |
SET_TIME_ZONE | 允许应用程序设置时区的权限 |
SET_WALLPAPER | 允许应用程序设置桌面壁纸的权限 |
VIBRATE | 允许应用程序控制振动器的权限 |
WRITE_CONTACTS | 允许应用程序写入用户联系人的权限 |
WRITE_HISTORY_BOOKMARKS | 允许应用程序写历史书签的权限 |
WRITE_OWNER_DATA | 允许应用程序写用户数据的权限 |
WRITE_SMS | 允许应用程序写短信的权限 |