Android开发之“hello World”的实现
扫描二维码
随时随地手机看文章
按照惯例,同时也是为了更好地引导读者进入精彩的Android世界,我们接下来要实现一个简单的“hello World”例子。这里以Android SDK 2.1为基础基于Eclipse Galileo(Eclipse 3.5)作为IDE来完成开发。
通过“File”→“New”→“Project”创建Android工程,如图1所示。设置“Project name:”为“helloWorld”,设置“Build Target”为“Android 2.1”,设置“Application name:”为“helloWorld”,设置“Package name:”为“com.miaozl.helloWorld”,设置“Create Activity:”为“helloWorld”。然后单击“Finish”按钮即可完成工程的创建。
图1 创建Android工程
需要说明的是,在Android的设计中,Android 1.0的SDK版本为“1”、Android 1.1的SDK版本为“2”、Android 1.5的SDK版本为“3”、 Android 1.5的SDK版本为“3”、 Android 1.6的SDK版本为“4”、 Android 2.0的SDK版本为“5”、 Android 2.0.1的SDK版本为“6”、 Android 2.1的SDK版本为“7”,Android 2.2的SDK版本为“8”,Android 2.3的SDK版本为“9”,Android 3.0的SDK版本为“Honeycomb”。在具体SDK版本的选择上,应在考虑技术实现可行性的前提下,选择尽量小的版本,这有利于扩大兼容的物理设备。
在创建Android工程的过程中。由于Eclipse的原因,系统可能会提示“no classfiles specified,Conversion to Dalvik format failed with error 1”,如果出现该错误信息,按“F5”键刷新一次工程即可。需要说明的是,在Foryo后,该问题已经很少出现。对于复制过来的工程,可能会引起工程属性方面的问题,这一问题可以通过Android工程的右键菜单选择“Android Tools”→“Fix Project Properties”修复系统属性解决。
另外如果是第一次创建工程, Eclipse会提示用户“Failed to find an AVD compatible with target”。这是由于Android在稍后的版本中不再提供默认的Android虚拟设备(AVD,Android Virtual Device),需要用户自行创建。在Linux中,AVD相关的文件包括userdata.img映像文件,默认情况下存于/root/.android目录中,AVD描述了当前模拟器的设备配置信息。当工程创建完成后,即可在Eclipse的“Package Explorer”中看到Android的工程布局。Eclipse对于所辖工程的维护默认情况下位于/root/workspace/.metedata目录中。如果期望获得一个干净的运行环境,直接删除/root/.android和/root/workspace/.metedata目录即可。
如图2所示为所生成的Android的“helloWorld”工程布局,其中“.settings”描述了Eclipse和采用的JDT包的若干信息;“.assets”为空目录,描述了工程的断言信息,断言并不常用,常见的用法是维护一些工程的资源文件,但断言对于单个文件有1MB的大小限制。
“bin”为输出文件目录,包含了各源文件对应的CLASS字节码文件、“ap_”格式的资源文件、DEX字节码文件和最终利用“aapt”工具打包的APK格式的Android安装包。需要说明的是APK格式的Android安装包本质上为ZIP格式的压缩包,包含了资源、DEX字节码文件和AndroidManifest.xml等,当系统检测到APK格式的文件时,系统会把它当做一个应用看待。
“gen”为资源数据目录。包含了“aapt”工具在工程内所发现的所有资源数据。
“res”为描述资源的XML文件目录,通常包括“drawable”、“layout”、“values”等子目录,描述了工程涉及的图标、字符串和布局等信息,复杂的应用还涉及“menu”、“color”、“style”等目录。其中布局资源文件为main.xml,字符串资源文件为strings.xml。
“src”为工程源文件目录,包含了开发者创建的Java文件。
“.classpath”文件描述了工程涉及的路径信息。
“.project”文件描述了工程名、所需的编译命令等工程信息。
“AndroidManifest.xml”则描述了工程实现细节如“manifest”、“application”、“activity”、“intent-filter”、“action”、“category”、SDK版本信息等信息、应用程序的权限等,是Android工程中最重要的文件。
“default.properties”描述了SDK的版本信息。
图2 Android工程布局
对于基于原生代码的应用,在工程下可能还存在“jni”目录用于存放原生源代码,存在“libs”目录,用于存放编译原生源代码生成的动态共享库等。
下面为主要文件的实现细节:
1.srccommiaozlhelloWorldhelloWorld.java
代码1为“hello World”工程的helloWorld.java文件的内容,在该文件中定义了一个名为“helloWorld”的Activity,并通过setContentView()函数加载该Activity的布局资源文件。
代码1 helloWorld.java
package com.miaozl.helloWorld;
import android.app.Activity;
import android.os.Bundle;
public class helloWorld extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); //创建Activity
setContentView(R.layout.main); //加载布局资源
}
}
利用setContentView ()函数还可以直接加载View类,View是用来构建应用程序的UI控件系统的,包括列表(Lists)、网格(Grids)、文本框(Text Boxs)、按钮(Buttons)等扩展类。图3显示了Android系统的View子系统的类图。其中android.view.View类为UI控件的基类,android.view.ViewGroup为布局类的基类。
图3 View子系统类图
Activity与窗口管理器有着密切的关系。View子系统是Android整个UI框架的基础。
2.reslayoutmain.xml
代码2为“helloWorld”工程的main.xml文件,在该文件中定义了该Activity的布局属性,定义了该Activity的根布局为LinearLayout,设置该Activity为竖向的全屏窗口,并定义了一个TextView 控件。
代码2 main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android=http://schemas.android.com/apk/res/android //定义根布局,定义xmlns的名字空间
android:orientation="vertical" // Activity为竖向
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
android:layout_width="fill_parent" //与父对象一样宽
android:layout_height="wrap_content" //依据内容设置宽度
android:text="@string/hello" //设置显示字符串
/>
</LinearLayout>
在Android中,布局管理器决定了Activity中的UI接口的布局, UI的布局具有两种方式,一种是基于XML文件实现,另一种是基于代码实现。其中基于XML文件的方式主要用于针对不同屏幕旋转度、不同显示分辨率和不同本地化语言的默认方式的布局,有利于解耦应用的行为和显示,可以帮助用户在不修改代码的情况下改变应用的布局;基于代码的方式则侧重于实时修改布局,性能上略占优势,但不利于应用的本地化和适应不同的硬件设备。尤其是随着平板电脑的目标环境引入,硬件环境更趋复杂。
在XML布局文件中,必须存在一个类型为View和ViewGroup的根元素(main.xml文件中的根元素为LinearLayout)。只有在定义了根元素之后,用户才能添加随后的布局对象或者UI控件(如main.xml文件中的TextView等)。
需要说明的是,对于UI控件而言,其“android:layout_width”和“android:layout_height”属性在较高版本中通常有三个属性值即"fill_parent"、"match_parent"、"wrap_content"可以选择。其中"fill_parent"和"match_parent"属性值的定义均为“-1”。其实际意义相同。"match_parent"属性值具有更明确的字面含义,受到Google的推荐。
如果在不同的屏幕方向或者硬件配置、语言环境下,布局文件稍有不同,可以将同名布局文件放置在不同的布局文件夹下,如在简体中文环境下的布局文件夹为“layout-zh-rCN”。
在构建布局文件时,很自然会涉及到像素的问题,在Android中,有dp、px、dip等几种单位,其中dip独立于物理设备,是Android为了适应多种不同分辨率而设计的像素单位,最常用的也是dip。
需要注意的是dip的设置与分辨率无关,但与屏幕密度(density)有关,默认情况下,QVGA的密度为120,系数为0.75,HVGA的密度为160,系数为1.0,WVGA的密度为240,系数为1.5。需要说明的是,目前Android支持的密度包括xhdpi、hdpi、mdpi、ldpi。其中hdpi通常适用于高分辨率的智能终端,mdpi则通常用于高分辨率的平板电脑。而ldpi则适用于入门级的智能终端。另外,在Foryo中,还引入了xhdpi的概念,其密度定义为320,适用于拥有高分屏的高端智能终端,针对不同密度,Android对其采用的菜单图标、应用图标等的大小做了明确的定义。针对hdpi的密度,其菜单图标和应用图标的大小为72*72,针对mdpi的密度,其菜单图标和应用图标的大小为48*48,针对ldpi的密度,其菜单图标和应用图标的大小为36*36。
另外还有一个nodpi的概念需要注意,这个概念是为避免像素伸缩的图片资源而设计的。
px与dip的关系如下:
px = (int) (dip*density+0.5f) //一个dip在hdpi下,相当于1.5个物理像素
在实际实现中,屏幕密度称为scale,px和dip的转换过程如下:
public void scale(float scale) {
x = (int) (x * scale + 0.5f);
y = (int) (y * scale + 0.5f);
if (width > 0) {
width = (int) (width * scale + 0.5f);
}
if (height > 0) {
height = (int) (height * scale + 0.5f);
}
}
同时,在描述字体的大小时,涉及的单位为sp。在实际开发中,很多初学者容易胡乱的使用这些单位。这会引起许多潜在的问题。
在设置控件的填充时,需要注意到Android提供了两种填充类型:内填充和外填充,对于内填充即填充占用的空间属于该控件的一部分,对于外填充即填充占用的空间属于该控件的父控件的一部分。
其中内填充的属性设置方式为:
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello"
android:paddingTop="5dip"/> //控件顶部内填充5dip
外填充的属性设置方式为:
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello"
android:layout_marginTop="5dip"/> //控件顶部外填充5dip
布局文件在实际的开发者有很多的技巧需要揣摩,如何使做的设计更加灵活,能够适应多种设备,不是一言能蔽之的。希望读者多加体会。
3.resvaluesstrings.xml
代码3为“helloWorld”工程的strings.xml文件,在该文件中,定义了Activity所涉及的字符串资源。为了进行软件的本地化,Android采用了ISO命名规范来设置不同语言的资源目录名,对于简体中文,资源目录为“values-zh-rCN”;对于繁体中文,资源目录为“values-zh-rTW”。
代码3 strings.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="hello">Hello World, helloWorld!</string> //“hello”字符串
<string name="app_name">helloWorld</string> //“app_name”字符串
</resources>
在更复杂的情况下,可能会遇到字符串数组的情况,其定义方式如下:
<string-array name="imAddressTypes">
<item>Home</item>
<item>Work</item>
<item>Other</item>
<item>Custom</item>
</string-array>
其他类型的数组还包括颜色数组、图片数组、整数数组等,其定义方式可以参考frameworks/base/core/res/res/values/arrays.xml文件。
4.. AndroidManifest.xml
代码4为“helloWorld”工程的AndroidManifest.xml文件。对于每个应用而言,该文件唯一
AndroidManifest.xml文件定义了应用的activity、intent、uses-sdk、uses-permission、service、uses-library、Content provider、Broadcast Receiver等信息。
代码4 AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.miaozl.helloWorld" //包名
android:versionCode="1" //版本号,必须为整数,用于判断是否升级等
android:versionName="1.0"> //版本名
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".helloWorld" //定义activity
android:label="@string/app_name">
<intent-filter> //定义intent过滤器
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
<uses-sdk android:minSdkVersion="7" /> //定义采用的Android版本信息
</manifest>
在“uses-sdk”元素中,开发者可以根据应用的情况指定3种Android的版本信息。android:minSdkVersion属性描述了该应用正常运行要求的最低Android版本信息,默认值为“1”;android:maxSdkVersion属性描述了该应用正常运行要求的最高Android版本信息,如果该属性没有声明,则系统假定其默认值为无限大;android:targetSdkVersion属性描述了该应用正常运行的最佳Android版本信息,声明android:targetSdkVersion属性,可使应用调用特定平台的行为,而不是局限于最低版本的平台支持能力。
除了Activity外,在实际开发中,构建的服务(service)、接收器(receiver)、提供器(provider)、用到的库(uses-library)等都必须在AndroidManifest.xml中声明,否则会引发异常。其中服务和提供器可以被其他应用调用。
“android:versionCode”属性定义了该应用的当前版本号,配合数字签名证书可以用于应用的升级。“android:versionName”属性通常指定显示给最终用户的版本信息。
在Foryo中,Android增加了“android:installLocation”属性,可以使开发者指定应用安装的位置,其值包括:"auto"、"internalOnly"、"preferExternal"。这有利于入门级Android终端的市场拓展。