Facebook Twitter LinkedIn E-mail
magnify
Home 2011 三月

Android简明开发教程十:数据绑定Data Binding

前面提到AndroidGraphics2DTutorial说过它是ListActivity派生出来的。ListActivity中显示的是ListView,ListView和Gallery ,Spinner有一个共同点:它们都是AdapterView的子类。AdapterView的显示可以通过数据绑定来实现,数据源可以是数组或是数据库记录,数据源和AdapterView是通过Adapter作为桥梁。通过Adapter,AdatperView可以显示数据源或处理用户选取时间,如:选择列表中某项。

AndroidGraphics2DTutorial读取AndroidManifest.xml中Intent-Filter为

<action android:name=”android.intent.action.MAIN” />
<category android:name=”com.pstreets.graphics2d.SAMPLE_CODE” />

的所有Activity,以列表方式显示。使用了Android API 自带的SimpleAdapter。 来看看AndroidGraphics2DTutorial.java 中相关代码:

public class AndroidGraphics2DTutorial extends ListActivity {

 private static final String SAMPLE_CATEGORY
          ="com.pstreets.graphics2d.SAMPLE_CODE";
 
 @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);

  setListAdapter(new SimpleAdapter(this, getData(),
    android.R.layout.simple_list_item_1, new String[] { "title" },
    new int[] { android.R.id.text1 }));
  getListView().setTextFilterEnabled(true);

 }

 protected List getData() {
  List<Map> myData = new ArrayList<Map>();

  Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
  mainIntent.addCategory(SAMPLE_CATEGORY);

  PackageManager pm = getPackageManager();
  List<ResolveInfo> list = pm.queryIntentActivities(mainIntent, 0);

  if (null == list)
   return myData;

  String[] prefixPath;

  prefixPath = null;

  int len = list.size();

  Map<String, Boolean> entries = new HashMap<String, Boolean>();

  for (int i = 0; i < len; i++) {
   ResolveInfo info = list.get(i);
   CharSequence labelSeq = info.loadLabel(pm);
   String label = labelSeq != null ? labelSeq.toString()
     : info.activityInfo.name;

   String[] labelPath = label.split("/");

   String nextLabel = prefixPath == null ? labelPath[0]
     : labelPath[prefixPath.length];

   if ((prefixPath != null ? prefixPath.length : 0) 
== labelPath.length - 1) {
    addItem(myData,
      nextLabel,
      activityIntent(
        info.activityInfo.applicationInfo.packageName,
        info.activityInfo.name));
   } else {
    if (entries.get(nextLabel) == null) {
     addItem(myData, nextLabel, browseIntent(nextLabel));
     entries.put(nextLabel, true);
    }
   }

  }

  Collections.sort(myData, sDisplayNameComparator);

  return myData;
 }

 private final static Comparator<Map> sDisplayNameComparator 
= new Comparator<Map>() {
  private final Collator collator = Collator.getInstance();

  public int compare(Map map1, Map map2) {
   return collator.compare(map1.get("title"), map2.get("title"));
  }
 };

 protected Intent activityIntent(String pkg, String componentName) {
  Intent result = new Intent();
  result.setClassName(pkg, componentName);
  return result;
 }

 protected Intent browseIntent(String path) {
  Intent result = new Intent();
  result.setClass(this, AndroidGraphics2DTutorial.class);
  return result;
 }

 protected void addItem(List<Map> data, String name, Intent intent) {
  Map<String, Object> temp = new HashMap<String, Object>();
  temp.put("title", name);
  temp.put("intent", intent);
  data.add(temp);
 }

 @Override
 protected void onListItemClick(ListView l, View v, 
    int position, long id) {
  Map map = (Map) l.getItemAtPosition(position);
  Intent intent = (Intent) map.get("intent");
  startActivity(intent);
 }
}

使用数据显示Layout,上面代码中

setListAdapter(new SimpleAdapter(this, getData(),
    android.R.layout.simple_list_item_1, new String[] { “title” },
    new int[] { android.R.id.text1 }));

为ListActivity中ListView 指定Adapter,这个Adapter的数据源为getData(),getData()从Manifest.xml中查找出所有符合条件的示例Activity列表。 这里DataSource是静态的从文件中读取,如果DataSource为数组或是其它数据源,如果程序中修改数值的内容,则你应该notifyDataSetChanged()来通知UI数据有变动。UI则会刷新显示以反映数据变化。简单的说Android数据绑定和.Net WinForm ,WPF 中数据绑定类似。

处理用户选取事件,AdapterView.OnItemClickListener()可以用来处理选取事件,对于ListActivity,可以用protected void onListItemClick(ListView l, View v, int position, long id)。AndroidGraphics2DTutorial中的实现是用户选取Activity名称好,则启动对应的Activity。

上面代码中使用SimpleAdapter,并使用Android提供的android.R.layout.simple_list_item_1来显示数据,Andrid也允许使用自定义的Layout来显示数据,对这个例子来说,可以使用图片加说明来显示列表,将在后面介绍如果使用自定义Adapter和自定义Layout来显示绑定的数据。

 

Android简明开发教程九:创建应用程序框架

Android简明开发教程八说明了程序需要实现的功能,就可以创建Android项目了。请参见Android简明开发教程三:第一个应用Hello World ,创建一个新项目AndroidGraphics2DTutorial。今天先介绍创建的程序的框架。然后再项目添加如下类定义:

添加第三方库文件

AndroidGraphics2DTutorial调用了引路蜂二维图形库,因此需要在项目中添加第三方库引用(libgisengine.jar),打开Android属性窗口,添加External JARs。把libgisengine.jar 添加到项目中,引路蜂二维图形库是引路蜂地图开发包的一部分。添加库引用可以参见 Android引路蜂地图开发示例:基本知识

类说明,下表列出了项目中定义的类的简要说明:

说明
AndroidGraphics2DApplication 应用程序类,为Application子类
AndroidGraphics2DTutorial 主Activity,为ListActivity子类,用于列出其它示例。
GuidebeeGraphics2DSurfaceView SurfaceView子类用于显示图形
GuidebeeGraphics2DView View子类用于显示图形,与GuidebeeGraphics2DSurfaceView 功能一样,在程序中可以互换。
SharedGraphics2DInstance 定义了共享类对象,主要包含Graphics2D
Graphics2DActivity Activity子类,为所有示例基类,定义一些所有示例共享的类变量和函数。
Bezier,Brush,Colors,Font,Image,Path,Pen,Shape,Transform 为Graphics2DActivity的子类,为二维图形演示各个功能

AndroidGraphics2DApplication ,其实在一般的Android应用中,无需定义Application的派生类,比如在Hello World中就没有定义,当是如果想在多个Activity中共享变量,或是想初始化一些全局变量,可以定义Application的派生类,然后可以在Activity或Service中调用 getApplication() 或 getApplicationContext()来取得Application 对象,可以访问定义在Application中的一些共享变量。在这个例子中AndroidGraphics2DApplication严格些也可不定义,为了说明问题,还是定义了用来初始化Graphics2D实例,Graphics2D实例可以被所有示例Activity,如Colors,Font访问。如果定义了Application的派生类,就需要在AndroidManifest.xml中说明Application派生类的位置。

<manifest xmlns:android=”http://schemas.android.com/apk/res/android
      package=”com.pstreets.graphics2d
      android:versionCode=”1″
      android:versionName=”1.0″>
    <application android:name=”AndroidGraphics2DApplication
         android:icon=”@drawable/icon” android:label=”@string/app_name”>
        <activity android:name=”.AndroidGraphics2DTutorial”
                  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>
    <uses-sdk android:minSdkVersion=”4″ />

</manifest>   

Application 可以重载 onCreate()和 onTerminate() ,onCreate()在应用启动时执行一次,onTerminate()在应用推出执行一次。AndroidGraphics2DApplication 的onCreate() 中初始化Graphics2D实例:

public void onCreate() {
  SharedGraphics2DInstance.graphics2d=
      new Graphics2D(SharedGraphics2DInstance.CANVAS_WIDTH,
        SharedGraphics2DInstance.CANVAS_HEIGHT);
 }

AndroidGraphics2DTutorial 为ListActivity子类,直接从AndroidManifest.xml中读取Intent-Filter Catetory 为 com.pstreets.graphics2d.SAMPLE_CODE 的所有Activity。

private static final String SAMPLE_CATEGORY="com.pstreets.graphics2d.SAMPLE_CODE";

Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
mainIntent.addCategory(SAMPLE_CATEGORY);
...

GuidebeeGraphics2DSurfaceView 和 GuidebeeGraphics2DView 分别为SurfaceView 和View的子类,都可以用来显示图形结果。在程序中可以互换。

package com.pstreets.graphics2d;

import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.View;

public class GuidebeeGraphics2DView extends View {

 public GuidebeeGraphics2DView(Context context, AttributeSet attrs,
   int defStyle) {
  super(context, attrs, defStyle);

 }

 public GuidebeeGraphics2DView(Context context, AttributeSet attrs) {
  super(context, attrs);

 }

 public GuidebeeGraphics2DView(Context context) {
  super(context);

 }

 public void onDraw(Canvas canvas) {
  super.onDraw(canvas);
  canvas.drawColor(0xFFFFFFFF);
  if (SharedGraphics2DInstance.graphics2d != null) {
   int offsetX = (getWidth() -
     SharedGraphics2DInstance.CANVAS_WIDTH) / 2;
   int offsetY = (getHeight()
     - SharedGraphics2DInstance.CANVAS_HEIGHT) / 2;
   canvas.drawBitmap(SharedGraphics2DInstance.graphics2d.getRGB(), 0,
     SharedGraphics2DInstance.CANVAS_WIDTH,
     offsetX, offsetY,
     SharedGraphics2DInstance.CANVAS_WIDTH,
     SharedGraphics2DInstance.CANVAS_HEIGHT,
     true, null);
  }
 }

}
package com.pstreets.graphics2d;

import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class GuidebeeGraphics2DSurfaceView extends
   SurfaceView implements SurfaceHolder.Callback {

 SurfaceHolder holder;

 private void initHolder() {
  holder = this.getHolder();
  holder.addCallback(this);
 }

 public GuidebeeGraphics2DSurfaceView(Context context,
   AttributeSet attrs,
   int defStyle) {
  super(context, attrs, defStyle);
  initHolder();

 }

 public GuidebeeGraphics2DSurfaceView(Context context,
   AttributeSet attrs) {
  super(context, attrs);
  initHolder();

 }

 public GuidebeeGraphics2DSurfaceView(Context context) {
  super(context);
  initHolder();

 }

 @Override
 public void surfaceChanged(SurfaceHolder arg0,
   int arg1, int arg2, int arg3) {
  // TODO Auto-generated method stub

 }

 @Override
 public void surfaceCreated(SurfaceHolder arg0) {
  new Thread(new MyThread()).start();

 }

 @Override
 public void surfaceDestroyed(SurfaceHolder arg0) {
  // TODO Auto-generated method stub

 }

 class MyThread implements Runnable {

  @Override
  public void run() {
   Canvas canvas = holder.lockCanvas(null);
   canvas.drawColor(0xFFFFFFFF);
   if (SharedGraphics2DInstance.graphics2d != null) {
    int offsetX = (getWidth() -
      SharedGraphics2DInstance.CANVAS_WIDTH) / 2;
    int offsetY = (getHeight() -
      SharedGraphics2DInstance.CANVAS_HEIGHT) / 2;
    canvas.drawBitmap
      (SharedGraphics2DInstance.graphics2d.getRGB(),
      0, SharedGraphics2DInstance.CANVAS_WIDTH,
      offsetX,
      offsetY,
      SharedGraphics2DInstance.CANVAS_WIDTH,
      SharedGraphics2DInstance.CANVAS_HEIGHT,
      true, null);
   }
   holder.unlockCanvasAndPost(canvas);

  }

 }

}

SurfaceView 动态显示性能比较好,一般用在游戏画面的显示。图形的绘制可以在单独的线程中完成。

修改 res\layout\main.xml

<?xml version=”1.0″ encoding=”utf-8″?>
<LinearLayout xmlns:android=”http://schemas.android.com/apk/res/android
    android:orientation=”vertical”
    android:layout_width=”fill_parent”
    android:layout_height=”fill_parent”
    >
<com.pstreets.graphics2d.GuidebeeGraphics2DSurfaceView
     android:id=”@+id/graphics2dview”
  
     android:layout_width=”fill_parent”
     android:layout_height=”fill_parent” />
</LinearLayout>

如果使用 GuidebeeGraphics2DView作为显示,则只需将上面红色部分该成GuidebeeGraphics2DView即可。

为了能在AndroidGraphics2DTutorial 列表中列出,对项目中的示例Activity的都定义下列intent-filter

<activity android:name=”.example.Colors” android:label=”@string/activity_colors”>
            <intent-filter>
                <action android:name=”android.intent.action.MAIN” />
                <category android:name=”com.pstreets.graphics2d.SAMPLE_CODE” />
            </intent-filter>
        </activity>

这样就完成了程序框架的设计,起始界面如下:

 

Android简明开发教程八:引路蜂二维图形绘制实例功能定义

有了前面对Android平台的介绍,基本上可以开始编写Android应用了,这里将以绘制二维图形为例,对Android开发的一般方法做过介绍,其中涉及到自定义Application类,扩展View,Intent定义,发送消息,Data Binding(Adapter),和基本UI设计。示例没有使用Android平台自带的二维图形API,而是调用了引路蜂二维图形库,引路蜂二维图形库Graphics 2D API实现了移动平台上图形引擎,它能够以一种统一的方式处理各种基本图形(Shape),路径(Path),文本(Texts),适量字体及图像。基本类定义类同Windows GDI+库。
所有示例和Silverlight二维图形库类似 Silverlight 引路蜂二维图形库下载
实例将提供源码,内含引路蜂二维图形库(免费使用)。

二维图形按功能分成下表所示:

功能 示例
Color Colors
Brush Pattern ,Gradients
Pen Lines, Dashes, LineCap,LineJoin
Path Polys, Paths
Shape Oval ,Pear ,Shape2DDemo
Image DrawMap, JumbleImage, SeeThroughImage
Font FontDemo, FontTypes
Transform Transform
Dynamic Shape Bezier

每个功能设计成一个Activity,包含在AndroidGraphics2DApplication中。

 

Android简明开发教程七:Intents和Intent Filters

Android应用中的三个核心组件:Activities,Services和broadcast receivers都是通过称为“Intent”的消息来激活的。Android应用一个特点是“低耦合”,各个Activities,Services和broadcast receivers相当独立,可以看成是一个个“迷你应用”,而Intent是这些“迷你应用”的粘合剂,Intent不但可以用于同一个Application之间Activities,Services和broadcast receivers的交互,也可以用于不同Application之间Activities,Services和broadcast receivers的交互。
Intent本身为一个数据载体,可以描述想要执行的操作以及用于这个操作的数据和其它属性。用个容易理解的概念,在访问网站时,我们需要提供网站的URL,有时还需要通过URL参数,在Android世界里,Intent 的功能类似于URL,Android操作系统根据Intent来触发对于的Activitives,Services或是Broadcast Receivers。

Android应用中的三个核心组件:Activities,Services和broadcast receivers都是通过Intent来触发的,当它们触发的机制各不相同,而且不会有重叠,也就是说发给Activity的Intent不会激活Service或是broadcast receivers,发给broadcast receivers的Intent也不会触发Activity和Service。

  1. Activity 通过方法 Context.startActivity() 和 Activity.startActivityForResult()来调用。以函数调用为参考startActivity() 相当于调用无返回值的函数,startActivityForResult()调用的Activity有返回值,可以通过Activity.setResult()来返回结果。
  2.  Context.startService()用来初始化Service,Context.bindService()可以用来建立与目标Service之间的连接,如果Service没有运行,则会启动该Service。
  3. Broadcast Receiver是通过  Context.sendBroadcast(), Context.sendOrderedBroadcast(), 和Context.sendStickyBroadcast()来触发的。大部分的Broadcast消息来自于Android操作系统,如电池状态,来电,短消息等。

和URL不太一样的是,URL和网站一般是一一对应的,而一个Intent可以用来触发某个指定的Activity,Service或是Broadcast Receiver,或是触发多个满足Intent条件的Activities,Services或是Broadcast Receivers。

下面来看看Android OS如何根据Intent来找到满足触发条件的Activity,Service或是Broadcast Receiver.  借用SQL 数据库的概念可以更好的理解。

     SELECT (Activitives|Services|Broadcast Receivers) AS Target
     FROM  (List in AndroidManifest.xml)
     WHERE Intent Meet Target’s (Intent Filter)

意思就是从AndroidManifest.xml中定义的Activities,Services和Broadcast Receiver列表中查找符合Intent 条件的Activities,Services,或是Broadcast Receivers。所有能活被激活的Activity,Service和Broadcast Receiver都必须在AndroidManifest.xml有定义,否则Android OS无法查询到该目标,相当于数据库中无记录,即使你在代码中定义了该Activity,Service或Broadcast Receiver。

Intent
Intent本身为一个数据载体,可以描述想要执行的操作以及用于这个操作的数据和其它属性。它主要包含下列信息:
Component name:可以处理该Intent的组件名称,组件名称指定义Activity,Service的包和类的全名称。比如类名为com.pstreets.gisengine.AndroidGISEngineTutorial ,包名为com.pstreets.gisengine。 组件名称为可选项,如果指定了,意味明确指定用来响应该Intent的Activity,Service。
Action: 列出需要执行的操作名称。或者在Broadcast Intents的情况下给出发生的事件名称。

Constant Target component Action
ACTION_CALL activity 开始打电话.
ACTION_EDIT activity 显示编辑对话框.
ACTION_MAIN activity 作为一个任务(应用)的起始Activity,对于可以从Android应用列表的应用来说,都需要在AndroidManifest.xml 中设置ACTION_MAIN的Intent-Filter属性。
ACTION_SYNC activity 同步数据.
ACTION_BATTERY_LOW broadcast receiver 电池电量低告警.
ACTION_HEADSET_PLUG broadcast receiver 耳机插入或拔出.
ACTION_SCREEN_ON broadcast receiver 屏幕打开或关闭.
ACTION_TIMEZONE_CHANGED broadcast receiver 时区变动.

Data:定义不数据的URL以及数据的MIME类型。不同的Action能够处理的Data类型也不一样,比如 ACTION_CALL,它处理的数据格式为tel: URI,URI为电话号码。
Category: 定义了可以响应Intent的附加信息,一个Intent可以指定多个Category类型。和Action类似,Android 预定义了一些Category类型:

Constant  Meaning 
CATEGORY_BROWSABLE 表示目标Activity可以使用浏览器安全显示指定连接,比如说一个图片或是Email消息.
CATEGORY_GADGET 表示该Activity可以当作一个Gadget嵌入到其它可以放置Gadget的Activity中。
CATEGORY_HOME 表示还Activity是Home Screen,可以设置这个属性来替换Android自带的Home Screen。
CATEGORY_LAUNCHER 该Activity可以显示在Android程序管理器中。一般应用的主Activity都会在AndroidManifest.xml 定义该属性。

Extra:  附加Key-Value列表,可以向目标Activity传送附加参数。可以理解成函数调用时的参数。
Flags:指出Android启动目标Activity时的一些选项(比如目标Activity隶属于那个应用等)。

除非是Intent明确指定目标(Explicitly)Activity的类和包名称,这是Activity无需在AndroidManifest.xml定义intent-filter,其它情况也叫隐含(Implicit)方式启动目标Activity,在这种情况下Android 操作系统查找目标Activity,Service或是Broadcast Receiver时主要根据Intent 的Action,Data 和Category属性来匹配定义在AndroidManifest.xml 中 Activity,Service或是Broadcast Receiver的 Intent Filters。

Intent Filters

Android中没个有效的Activity,Service,Broadcast Receiver都必须在AndroidManifest.xml有对应的定义。除非只使用明确调用发生来启动目标Activity,每个Activity都需要定义一个intent-filter。下面是是明确指定目标Activity的示例代码:

  Intent intent=new Intent(SplashActivity.this,GNavigator.class);
  startActivity(intent);
  

而更一般的情况,Activity在AndroidManifest.xml具有如下定义:

<activity android:name=”.AndroidGISEngineTutorial”
    android:label=”@string/app_name”>
 <intent-filter>
  <action android:name=”android.intent.action.MAIN” />
  <action android:name=”com.example.project.SHOW_CURRENT” />   
  <action android:name=”com.example.project.SHOW_RECENT” />   
  <action android:name=”com.example.project.SHOW_PENDING” />
  
  ….
  <category android:name=”android.intent.category.DEFAULT” />   
  <category android:name=”android.intent.category.BROWSABLE” />
  …
   <data android:mimeType=”video/mpeg” android:scheme=”http” . . . />    
   <data android:mimeType=”audio/mpeg” android:scheme=”http” . . . />
   ….
 </intent-filter>
</activity>

Activity的intent-filter可以包含action,category,data 子元素,给出了该Activity能够处理的Intent的Action,Category和数据类型。Android 操作系统就是根据Activity的intent-filter来匹配Intent,从而触发目标Activity,或是Service,Broadcast Receiver。

最常见的一个Intent Filter组合如下:

<intent-filter . . . >   
   <action android:name=”code android.intent.action.MAIN” />   
   <category android:name=”code android.intent.category.LAUNCHER” />
  </intent-filter>

表示用户可以从Android设备的应用程序管理器启动该Activity,这个Activity为应用的主Activity,主Activity可以再使用Intent触发或是启动其它Activity。

 

Android简明开发教程六:用户界面设计

Activity是Android应用用户界面的基本组成部件。但Activity本身并不提供用户界面(User Interface)。从程序结构层次上来说,一个Android应用是类android.app.Application的一个实例, Application中可以包含多个android.app.Activity实例。每个Activity 带一个Window类,这个类在Android平台上没有提供太多功能,主要可以用来控制标题栏(屏幕顶端)。比如设置UI全屏显示可以使用如下代码:

requestWindowFeature(Window.FEATURE_NO_TITLE);  
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,   
                                WindowManager.LayoutParams.FLAG_FULLSCREEN);

Activty缺省是不含用户界面,如需显示用户界面,则可以调用setContentView()来设置Activity的ContentView。 ConentView描述了具体的UI组件,如文本框,标签,列表框,图片框的。

Android的用户界面其实就是指ContentView的设计。“View”开始会使人产生误解,在其它平台“View”一般指类似Form的概念。而在Android平台上View是UI组件,相当于其他平台的Component,ViewGroup相当于其它平台的Container,如下图所示:

有了这个对应关系就很容易将你已有的用户界面设计知识用在Android的用户界面设计上来。

此外Android用户界面设计一个推荐的方法是使用XML来描述UI,这也不是Android平台的首创,Java ME Polish,WPF,Silverlight等都采用XML来描述UI,使用XML来描述的好处是将用户界面和程序逻辑分开,可以做到用户界面的改变不影响程序逻辑,程序逻辑的变动也可以不影响用户界面,实际上是采用了MVC模式的设计。Activity 是MVC中的Controller,Activity的ContentView则是MVC中的View。如果你不想使用XML来描述UI,也可以使用代码来创建UI,不过这种方法既麻烦,也增加了模块之间的耦合度。

理解了Android的View和ViewGroup之后,具体设计用户界面并不复杂,一般来说ViewGroup定义它的子View的布局Layout,也就是其它View (文本框,标签等控件或是其它ViewGroup)在用户界面的位置安排。如上图所示,这个层次关系可以嵌套。通过嵌套,你可以定义出任意用户界面。

Android中的基本布局如下:

FrameLayout
 最简单的布局对象
 在屏幕上故意保留的空白空间,你可以之后填充一个单独的对象
 例如:一个你要更换的图片
 所有子元素都钉到屏幕的左上角
 不能为子元素指定位置
LinearLayout
 在一个方向上(垂直或水平)对齐所有子元素
 所有子元素一个跟一个地堆放
 一个垂直列表每行将只有一个子元素(无论它们有多宽)
 一个水平列表只是一列的高度(最高子元素的高度来填充)
TableLayout
 把子元素放入到行与列中
 不显示行、列或是单元格边界线
 单元格不能横跨行,如HTML 中一样
AbsoluteLayout
 使子元素能够指明确切的X / Y 坐标显示在屏幕上
 (0,0)是左上角
 当你下移或右移时,坐标值增加
 允许元素重叠(但是不推荐)
 注意:
 一般建议不使用AbsoluteLayout 除非你有很好的理由来使用它
 因为它相当严格并且在不同的设备显示中不能很好地工作


RelativeLayout
 让子元素指定它们相对于其他元素的位置(通过ID 来指定)或相对于父布局对象

如果不喜欢Eclipse IDE自带的UI设计工具,可以使用免费Android UI设计软件DroidDraw,下载DroidDraw

Android SDK的 ApiDemo中也介绍Android提供的各个UI组件(Menu,Dialog,TextView,Button,List等以及各个Layout)的用法。这里就不一一介绍了。

 

Android简明开发教程五:Activities

Android应用中的Activity指具有屏幕显示支持用户交互的基本模块,类似于Java ME中的MIDlet, Windows 应用中的Form。比如可以是拨号,发送邮件的UI。每个Activity都可以含有一个Windows用于绘制用户界面。这个Windows提出占据整个屏幕,但也可以只占据部分屏幕或说现在在其它UI上面。

一个Android应用通常由多个Activity组成,其中有一个“主Activity”,为用户启动应用时第一个显示的UI。Activity可以启动其它Activity来实现其它功能。新的Activity又可以再启动新的Activity。新启动的Activity的UI将覆盖之前的UI。从而形成一个“UI栈”。新启动的Activity将暂停上一个Activity的运行。当用户按“BACK”按键时,“UI栈”最上的Activity出栈,之前的UI重新显示在屏幕上并恢复该UI对应的Activity的运行。这意味着Activiy具有一个“生命周期”。

写过MIDlet或是Windows Mobile应用的对以上“生命周期”不会陌生。MIDlet 也有类似的生命周期。Windows Form 也有Load, Unload , Active 等事件。和桌面系统不太一样的说,一般来说移动应用的生命周期不受应用本身控制,而是有手机操作系统来决定。Activity则实现对每个生命周期事件的处理来完成某个功能。比如在onCreate()事件中调用setContentView()来设置UI布局。在onPause()事件中暂停下载,使用GPS等,在onResume()事件中恢复下载,重连GPS设备等。