前言:我学了一年多的C#(从学编程算起,也没有两年,我现在大二下),中间也一直在学WP开发,虽然技术不咋地,很渣渣,但微软在Build大会上宣布的策略让我觉得有必要学习一下安卓开发了。关于微软的策略,没什么好说的,只有平台强大了,开发者才能存活,对于微软和.NET开发者来说,这是一荣俱荣,一毁都毁的事。目前来看WP开发者或许内心有一点受伤,不过在个人看来这都没什么,我们还是多学一门技术来丰富一下自己好了。我在学习安卓的同时还是会继续学习.NET方面的技术,对于Java,大二上学期上过这门课,学的内容很浅显,而且当时也没怎么学,现在看来还是得补补了,趁着大二下刚好有安卓这么课好好学习一下了。
安卓的开发环境之前已经搭建好,现在直接来了解一下安卓应用程序结构以及运行的原理。
1.Android工程的文件系统结构
src: java源代码存放的目录。在src文件夹里面可以建立若干个包,用以分类存放Java源程序(.java文件)
gen: 自动生成目录 gen目录中存放所有由Andriod开发工具自动生成的文件。目录中最重要的就是R.java文件(gen\包名\R.java)。开发工具会自动根据你放入res目录的资源,同步更新修改R.java文件。由于R.java文件是由开发工具自动生成,应避免手工修改R.java。R.java在应用中起到了字典的作用,它包含了各种资源的id,通过R.java,应用可以很方便地找到对应资源。
assets: 资源目录,Andriod除了提供/res目录存放资源文件外,在/assets目录也可以存放资源文件,而且/assets目录下的资源文件不会再R.java自动生成id,所以读取/assets目录下的文件必须指定文件的路径,而assets中的资源文件不会被编译,直接打包到应用中,assets文件夹支持任意深度的子目录。
bin:用于存放编译后的应用程序
libs:存放应用程序用到的第三方JAR。
res: 资源(Resource)目录 在这个目录中可以找到应用使用到的各种资源。如xml界面文件,图片或数据等。res文件夹内的资源文件最终会被打包到编译后的.java文件中,res文件夹不支持深度的子目录。
res/layout:存放拓展名为.xml的布局文件,每一个布局文件对应一个Activity。
res/values:strings.xml是这个文件夹最重要的文件,存放着布局文件中控件对象的属性值,与应用程序的国际化相关。
res/drawable:图片文件夹
res/raw:存放音频资源文件等
AndriodManifest.xml:项目清单文件 这个文件列出了应用程序所提供的功能,开发好的各种组件(Activity、ContentProvider、Broadcast、Service)需要在该文件中进行配置,如果应用使用到了系统内置的应用(如电话服务、互联网服务、短信服务、GPS服务等等),还需在该文件中声明使用权限。(安装的时候被操作系统读取)
2.编译结果
.java--》.class--》.dx--》.dex--打包(签名)--》.apk
编译结果放在项目根目录下的bin文件夹下
bin/classes:存放编译后的Java类文件
bin/classes.dex:存放基于编译后的Java类创建的可执行文件
bin/resources.ap_:存放应用程序的资源
bin/XXX.apk:实际的Android应用程序。.apk文件其实是一个ZIP压缩文件,包含.dex、资源的编译版(resources.arsc)、其他未编译的资源以及AndriodManifest.xml文件。
3.AndriodManifest.xml文件详解
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.dialogdemo" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="21" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name=".MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
根节点<manifest>中的package属性指明清单文件所对应的应用程序包,android:versionName是应用程序的版本名或编号,可以是任意合适的值,android:versionCode则必须是一个整数,表明应用程序的版本号。系统可以根据这个特性来确定应用程序是不是另一个版本的更新。
<uses-sdk>:表示当前应用程序基于哪个版本的SDK构建。
<application>:定义与当前描述文件对应的应用程序的细节信息。
<activity>:相当于Windows编程里面的一个窗体(Form)。android:name表示实现Activity的类,android:label表示用于显示的Activity的名字。 <intent-filter>子元素用于描述显示当前Activity在什么情况下被调用。 它里面的
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
这两项参数将我们的应用程序显示在手机应用程序的启动列表上,表示应用程序的入口,使用的时候应该注意它们仅能够出现在一个Activity里面,这个Activity就是应用程序的主Activity。
在这个清单文件里面还有一些没有出现,但以后会经常使用的元素:
<uses-permission>:指出应用程序正常运行所需的权限。
<permission>:为活动和服务声明权限,表示其他应用程序要使用当前应用程序的数据或逻辑必须具有的权限。
<instrumentation>:表示需要在关键系统事件中需要调用的代码。
<uses-library>:引入可选的Android组件,例如地图服务。
4.Android应用程序生命周期
与大部分传统应用程序平台不同,Android应用程序不能控制它们自己的生命周期。应用程序组件必须监听应用程序状态的变化并做出适当的反应,还要为随时被终止做好准备。默认情况下,每个Android应用程序都是通过它们自己的进程运行的,每一个进程都运行在独立的Dalvik实例中。每一个应用程序的内存和进程管理都是由运行时专门进行处理的。
Android会主动管理它的资源,它会采取任何措施来保证稳定流畅的用户体验。这就意味着在必要的时候,进程(以及它们的应用程序)有时候会在没有警告的情况下被终止,为高优先级的应用程序释放资源。
活动进程:正在和用户进行交互的应用程序进程。
可见进程:驻留“可见”Activity的进程。
启动服务进程:已经启动的Service进程。
后台进程:不可见、并且没有任何正在运行的Service的Activity的进程。
空进程:应用程序的生命周期已经结束,但仍保留在内存中的进程。Android通过维护这个缓存来减少应用程序再次启动时的启动时间。
5.一个简单的Android应用程序
先New一个Android Application Project,在工程对应的src文件夹的最内层找到生成的.java文件,添加如下代码:
public class MainActivity extends ActionBarActivity implements View.OnClickListener{ Button btn; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); btn=new Button(this); btn.setOnClickListener(this); updateTime(); setContentView(btn); } private void updateTime() { // TODO Auto-generated method stub btn.setText(new Date().toString()); } @Override public void onClick(View arg0) { updateTime(); } }
这个类里面的OnCreate方法会在应用程序启动的时候自动被系统调用,它传入参数是savedInstanceState,类型是Bundle,Bundle是一个数据参数,一般用于Activity之间的数据传送。在这个方法里面,首先做的是与超类联系起来,以完成整个Activity的初始化。随后又创建了一个按钮实例,并为按钮设置事件监听器,接着调用updateTime()方法,最后把按钮设置为内容视图。
这个程序最终的效果就是页面内只有一个按钮,用于显示最后一次按下它的时间(如果没有按就显示应用程序启动的时间)。
我们知道Android将用户界面和资源从业务逻辑中分离出来,并使用XML文件来进行界面布局,而复杂的业务逻辑交给java代码来完成,所以我们一般很少采用上面的方法来构建我们的应用程序。接下来我们把上面的应用程序来改动一下。
res/layout/activity_main.xml:
<Button xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/btn" android:layout_width="fill_parent" android:layout_height="fill_parent" android:text="" />
xmlns:android="http://schemas.android.com/apk/res/android"这个只能出现在布局文件的顶层元素里面,而顶层元素一般是一个布局容器。我们这里只有一个Button元素就直接放Button里了。
android:id属性为Button指定一个唯一标识符,我们在.java文件里获取布局文件里的元素时就需要这个属性。
android:text指示按钮上显示的文本。
android:layout_width和android:layout_height指示按钮的宽度和高度与父元素的关系,我们这个实例中按钮会占据整个屏幕。
.java文件:
public class MainActivity extends ActionBarActivity implements View.OnClickListener{ Button btn; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); btn=(Button)findViewById(R.id.btn); btn.setOnClickListener(this); updateTime(); } private void updateTime() { // TODO Auto-generated method stub btn.setText(new Date().toString()); } @Override public void onClick(View arg0) { updateTime(); } }
setContentView(R.layout.activity_main);这个和我们之前传入一个View的子类(即Button)的实例是一样的。布局中的所有资源都可以通过R.layout加上布局文件的名字来访问;例如:R.layout.activity_main访问的就是res/layout/activity_main.xml
btn=(Button)findViewById(R.id.btn);//通过findViewById方法来获取布局文件中标识为@+id/btn的Button元素
运行效果与原来的一样。
至此已经了解了安卓开发的一些基础知识,包括Android工程的文件系统结构、编译的结果、还有Manifest清单文件以及应用程序的生命周期和简单Android应用程序的详解。感觉写得还是比较乱,由于是新手,错误不足请大家多多指教。
之前一头扎进C#,用着VS的确很舒服,现在用Eclipse很不习惯,感觉安卓写起来也确实比WP复杂很多,加油吧!