接着上一篇。
R.*这个资源文件是在你编译后Android SDK自动生成的文件,其中参数是来自于res/layout/main.xml文件。当layout建立时,Android就使用这些参数来填充layout。
下面解析这个layout的main.xml文件内容:
1: <xml version="1.0" encoding="utf-8">
2: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
3: android:orientation="vertical"
4: android:layout_width="fill_parent"
5: android:layout_height="fill_parent"
6: android:background="#ffc5d1d4"
7: >
8: <com.google.android.maps.MapView
9: android:id="@+id/mapmain"
10: android:layout_width="fill_parent"
11: android:layout_height="fill_parent"
12: android:clickable="true"
13: android:apiKey="0P18K0TAE0dO2GifdtbuScgEGLWe3p4CYUQngMg"
14: />
15: <TextView
16: android:id="@+id/lblMicroJobsToday"
17: android:layout_width="wrap_content"
18: android:layout_height="wrap_content"
19: android:text="MicroJobs for You Today Near:"
20: android:textSize="20dp"
21: android:textColor="#FF000000"
22: android:layout_centerHorizontal="true"
23: android:gravity="top"
24: />
25: <Spinner
26: android:id="@+id/spnLocations"
27: android:layout_width="250dp"
28: android:layout_height="wrap_content"
29: android:layout_centerHorizontal="true"
30: android:layout_marginTop="2dp"
31: android:layout_below="@+id/lblMicroJobsToday"
32: />
33: <Button
34: android:id="@+id/btnShowList"
35: android:layout_width="150dp"
36: android:layout_height="wrap_content"
37: android:text="List Jobs"
38: android:textSize="20sp"
39: android:gravity="center_vertical"
40: android:layout_centerInParent="true"
41: android:layout_alignParentBottom="true"
42: />
43: </RelativeLayout>
以上采用了一种相对的布局方式来布置android app界面。android提供了多种layout的方式,你也可以自定义你的layout类型。
android:orientation
决定屏幕布局的“重心”方向。
android:layout_width and android:layout_height
决定如何利用屏幕显示app的大小。
android:background
决定app的背景颜色。(当有map覆盖后,这个属性其实作用不大)
后面的代码定义了每一个虚拟的元素在屏幕的位置
Section starting <com.google.android.maps.MapView
这是这个活动的主视图。你可以发现大量的视图可以使用view的名字来在layout文件里描述,但是使用android的默认库才可以直接写view的名字。mapview不是默认库包含的内容,所以我们要为它创建一xml元素。mapview这个view是在maps库里定义的,所以整个路径名字是com.google.android.maps.MapView,我们对他指定下面的属性:
android:id
View的唯一的识别符,你将在java文件代码里使用这些id来和xml的view元素彼此交换。
android:layout_width and android:layout_height
这2个属性和他们的parent元素息息相关,代码里使用了“fill_parent”指明了mapview将把它的父元素大小填满。
android:clickable
用户是否可以使用触屏点击。
android:apiKey
这个属性是mapview独一无二的属性。你需要从google得到一个api钥匙,就好像你要添加一个google map到你的web页面。第7,9章会告诉你如何得到这个map api钥匙.
Section starting <TextView
此view就类似于一个Lable。告诉用户他在看什么。
android:text
label的内容。
android:textSize
字符的大小。
android:textColor
字符的颜色。
android:layout_centerHorizontal
字符的排列方向是否居中。
android:gravity
字符的“重心”,可以设置为top,center_vertical,bottom。要注意的是layout_centerHorizontal是针对parent而言,而center_vertical是针对在此label里面的字符的排列情况。
要看更多的textView属性就去查看sdk把。
Section starting <Spinner
这是一个标准的android控件用来让用户选择最近的位置或者其他记录在用户配置文件里的位置。
android:layout_below
这个属性控制了spinner的位置。表示了这个元素是位于某某id元素之后的。
Section starting <Button
一个按钮。用来触发显示工作信息列表。
android:layout_width and android:layout_height
按钮大小。
android:text
按钮上的名称。
android:textSize
text的字符大小。
android:layout_centerInParent
按钮位置是否居中。
android:layout_alignParentBottom
按钮在parent里的位置居下部。同样可以用另一个表达方法:
android:gravity=bottom.
android的尺寸规则:
在例子里我们使用了scaled pixels(sp),但是android使用了大量的尺寸可供选择。
px(pixels),
dip or dp(device-independent pixels),
pts(points),
in(inches),
mm(millimeters)
MicroJobs.java的更多初始化内容:
先前的文章里介绍了xml布局文件,这是大量的用户界面初始化发生的地方,是各种view元素定义并赋予属性的地方,是界面呈现给用户的地方,是描述如何布局界面的地方。然后,再看看下面JAVA文件初始化的代码。
1: db = new MicroJobsDatabase(this);
2:
3: // Get current position
4: final Location myLocation
5: = getCurrentLocation((LocationManager) getSystemService(Context.LOCATION_SERVICE));
6:
7: Spinner spnLocations = (Spinner) findViewById(R.id.spnLocations);
8: mvMap = (MapView) findViewById(R.id.mapmain);
9:
10: // get the map controller
11: final MapController mc = mvMap.getController();
12:
13: mMyLocationOverlay = new MyLocationOverlay(this, mvMap);
14: mMyLocationOverlay.runOnFirstFix(
15: new Runnable() {
16: public void run() {
17: mc.animateTo(mMyLocationOverlay.getMyLocation());
18: mc.setZoom(16);
19: }
20: });
Create the database object
我们使用了sqlite来存储job的数据。第一行就初始化了这个数据库对象,数据库的操作代码在MicroJobsDataBase.java文件里,后面会讲到。
Get our location
getCurrentLocation封装了获得地理位置的代码。此方法见后面。此方法接受了一个LocationManager作为他的参数。此类是android的类库类,你可以通过调用getSystemService来获得这个实例。
Initialize the Spinner
往Spinner里填充数据使用了findViewById方法,这个id就是我们在xml布局文件里定义的。
Initialize the MapView and MapController
先通过findViewById找到mapView,然后使用mapview的getController()获得MapController的实例,现在你就有了各种控制map的方法句柄。
Initialize the LocationOverlay
创建一个locationOverlay是为了绘制一个我们的本地区域的map并显示给用户。map的知识将在后面论述,但是在这里你会看见我们使用构造器让地图首先显示的是我们当前的位置(从locationmanager获得了我们的位置信息)。
再往下看Button和Spinner的初始化,代码如下:
1: // Create a button click listener for the List Jobs button.
2: Button btnList = (Button) findViewById(R.id.btnShowList);
3: btnList.setOnClickListener(new Button.OnClickListener() {
4: public void onClick(View v) {
5: Intent intent = new Intent(MicroJobs.this.getApplication(),
6: MicroJobsList.class);
7: startActivity(intent);
8: }
9: });
10:
11: // Load a HashMap with locations and positions
12: List<String> lsLocations = new ArrayList<String>();
13: final HashMap<String, GeoPoint> hmLocations = new HashMap<String, GeoPoint>();
14: hmLocations.put("Current Location", new GeoPoint((int) latitude, (int) longitude));
15: lsLocations.add("Current Location");
16:
17: // Add favorite locations from this user's record in workers table
18: worker = db.getWorker();
19: hmLocations.put(worker.getColLoc1Name(), new GeoPoint((int)worker.getColLoc1Lat(),
20: (int)worker.getColLoc1Long()));
21: lsLocations.add(worker.getColLoc1Name());
22: hmLocations.put(worker.getColLoc2Name(), new GeoPoint((int)worker.getColLoc2Lat(),
23: (int)worker.getColLoc2Long()));
24: lsLocations.add(worker.getColLoc2Name());
25: hmLocations.put(worker.getColLoc3Name(), new GeoPoint((int)worker.getColLoc3Lat(),
26: (int)worker.getColLoc3Long()));
27: lsLocations.add(worker.getColLoc3Name());
28:
29: ArrayAdapter<String> aspnLocations
30: = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item,
31: lsLocations);
32: aspnLocations.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
33: spnLocations.setAdapter(aspnLocations);
Create a callback for the btnList Button View
我们首先通过id获得了button的句柄,然后对button进行了行为设置,使用一个构造器来回应外部的事件(onClick)。
当用户点击了Button,android将发送一个事件到OnClicklistener。在这的代码里,我们通过设置button的OnclickListener来设Button的行为,即为onClick。
然后我们在用户点击按钮后显示可用的工作信息。为了实现这个功能,我们得启动一个新的活动,MicroJobsList.java。我们通过调用startActivity来启动新活动。
通过onClick事件我们可以清楚的看到,首先创建一个新的intent实例,构造这个Intent有2个参数,一个参数指向最近的地理位置,一个是新活动类的名称。
Initialize the list of entries in the Spinner View
我们将2种数据结构传到我们的Spinner:一是喜爱地址的列表List,二是一个hashMap用来连接地理名称和地理位置(经纬度)。然后我们放入第1个条目“本地位置”。这个条目总是返回用户最近的地址,因为被认定为是一个移动的目标。
然后我们将加入3个条目作为用户最喜欢的地点,这些数据在MJAndroid数据库里保存。worker = db.getWorker()来获得3个最喜欢的地点。
当worker把3个喜欢的地点填充进List和hashMap后,我们需要一个arrayAdapter来填充界面的list(在构造函数填充),填充后,在Spinner对象使用SetAdapter来绑定数据。
最后一步,就是要给Spinner里的每一条数据附加用户响应。
1: // Set up a callback for the spinner
2: spnLocations.setOnItemSelectedListener(
3: new OnItemSelectedListener() {
4: public void onNothingSelected(AdapterView<> arg0) { }
5:
6: public void onItemSelected(AdapterView<> parent, View v, int position,
7: long id) {
8: TextView vt = (TextView) v;
9: if ("Current Location".equals(vt.getText())) {
10: latitude = myLocation.getLatitude();
11: longitude = myLocation.getLongitude();
12: mc.animateTo(new GeoPoint((int) latitude, (int) longitude));
13: } else {
14: mc.animateTo(hmLocations.get(vt.getText()));
15: }
16: mvMap.invalidate();
17: }
18: });
Initialize the Spinner callback
就像button一样。我们创建了一个onItemSelected方法并设置为Spinner的用户响应。onNothingSelected方法也是必须的,但是我们不用他,留空。
If……else在这里是区分本地位置和喜欢位置的分割点。在最后,我们作废掉Map使它重新绘制。