在移动App程序中,有些情况下需要获取某一位置的经纬度信息。例如 当GPS定位不准确的时候,可以通过手工选取位置信息来修正一些错误信息。 特别对于一些找朋友类应用的时候,明明人在A地结果地图上显示的结果却在B地,误差有1KM,让人无法接受。
而使用谷嘀位置选择器就可以手工在地图上选择位置了,并且可以把所选位置的经纬度信息复制出来,选择好位置后,点击程序界面右下方?按钮傍边的复制按钮即可;而对于第三方开发者来说,可以直接调用谷嘀位置选择器来让用户选择位置,完成后把用户选择的经纬度信息返回给第三方App。
谷嘀位置选择器App的主界面,如右图 图中标记的信息都是可以有第三方App定制的信息,如何定制下面会介绍;
谷嘀位置选择
先来看看如何调用该程序来选择位置:
1. 第三方App通过Intent (goodev.intent.action.PICK_LOCATION) 来调用谷嘀位置选择器,然后在Intent中设置一些附加数据(通过函数 intent.putExtra(key, value)) 来定制谷嘀位置选择器的界面。
可定制元素的KEY如下:
- TITLE:自定义选择界面的标题;
- ENABLE_SEARCH:是否启用位置搜索,如果为false则隐藏搜索按钮和位置输入框,默认为true;
- SEARCH_HINT:自定义搜索位置输入框中的输入提示内容;
- SEARCH_TEXT:自定义搜索按钮的文本内容;
- OK_TEXT:自定义完成按钮的文本内容;
- LOCATION_TEXT:自定义显示用户所选位置前面的位置标签的文本;
- ZOOM_LEVEL:自定义地图的默认放大缩小级别(int型数字 范围为1-21);
- HELP_TEXT:自定义帮助界面的文本内容(用户点击界面右下角的?按钮打开帮助界面);
- LATITUDE:自定义默认选择位置的纬度坐标信息,该值为字符串,内容为纬度数值*1000000,例如 如果想设置默认位置为 (12.343,123.21) 则这个字符串为“12343000”;
- LONGITUDE:自定义默认经度信息,字符串 同上;
用户选择后返回的内容有3个,他们的KEY分别为:
- LATITUDE:内容为纬度坐标值*1000000, int型;
- LONGITUDE:内容为经度坐标值*1000000, int型;
- ADDRESS:返回的内容为android.location.Address 对象,如果没法获取位置(例如 无法访问网络),则返回NULL。
为了简化调用该程序,我们还提供了一个开发者集成库,下载goodevLocationPickCn.jar这个文件(或者下载源代码:Utils.java ),然后通过如下代码来调用即可:
如果用户手机中还没有安装谷嘀位置选择器则会弹出一个对话框告诉用户需要安装,可以通过网络下载安装也可以通过电子市场安装。如下图:
下载对话框
当用户完成后,需要在onActivityResult函数中处理用户选择的结果,示例代码如下:
介绍 Queue 接口
java.util 包为集合提供了一个新的基本接口: java.util.Queue 。虽然肯定可以在相对应的两端进行添加和删除而将 java.util.List 作为队列对待,但是这个新的 Queue 接口提供了支持添加、删除和检查集合的更多方法,如下所示:
public boolean offer(Object element) public Object remove() public Object poll() public Object element() public Object peek()
基本上,一个队列就是一个先入先出(FIFO)的数据结构。一些队列有大小限制,因此如果想在一个满的队列中加入一个新项,多出的项就会被拒绝。这时新的 offer 方法就可以起作用了。它不是对调用 add() 方法抛出一个 unchecked 异常,而只是得到由 offer() 返回的 false。 remove() 和 poll() 方法都是从队列中删除第一个元素(head)。 remove() 的行为与 Collection 接口的版本相似,但是新的 poll() 方法在用空集合调用时不是抛出异常,只是返回 null。因此新的方法更适合容易出现异常条件的情况。后两个方法 element() 和 peek() 用于在队列的头部查询元素。与 remove() 方法类似,在队列为空时, element() 抛出一个异常,而 peek() 返回 null。
使用基本队列
在 Tiger 中有两组 Queue 实现:实现了新 BlockingQueue 接口的和没有实现这个接口的。我将首先分析那些没有实现的。
在最简单的情况下,原来有的 java.util.LinkedList 实现已经改造成不仅实现 java.util.List 接口,而且还实现 java.util.Queue 接口。可以将集合看成这两者中的任何一种。清单 1 显示将 LinkedList 作为 Queue 使用的一种方法:
清单 1. 使用 Queue 实现
Queue queue = new LinkedList(); queue.offer("One"); queue.offer("Two"); queue.offer("Three"); queue.offer("Four"); // Head of queue should be One System.out.println("Head of queue is: " + queue.poll());
再复杂一点的是新的 java.util.AbstractQueue 类。这个类的工作方式类似于 java.util.AbstractList 和 java.util.AbstractSet 类。在创建自定义集合时,不用自己实现整个接口,只是继承抽象实现并填入细节。使用 AbstractQueue 时,必须为方法 offer() 、 poll() 和 peek() 提供实现。像 add() 和 addAll() 这样的方法修改为使用 offer() ,而 clear() 和 remove() 使用 poll() 。最后, element() 使用 peek() 。当然可以在子类中提供这些方法的优化实现,但是不是必须这么做。而且,不必创建自己的子类,可以使用几个内置的实现, 其中两个是不阻塞队列: PriorityQueue 和 ConcurrentLinkedQueue 。
PriorityQueue 和 ConcurrentLinkedQueue 类在 Collection Framework 中加入两个具体集合实现。 PriorityQueue 类实质上维护了一个有序列表。加入到 Queue 中的元素根据它们的天然排序(通过其 java.util.Comparable 实现)或者根据传递给构造函数的 java.util.Comparator 实现来定位。将清单 2 中的 LinkedList 改变为 PriorityQueue 将会打印出 Four 而不是 One,因为按字母排列 —— 字符串的天然顺序 —— Four 是第一个。 ConcurrentLinkedQueue 是基于链接节点的、线程安全的队列。并发访问不需要同步。因为它在队列的尾部添加元素并从头部删除它们,所以只要不需要知道队列的大小, ConcurrentLinkedQueue 对公共集合的共享访问就可以工作得很好。收集关于队列大小的信息会很慢,需要遍历队列。
使用阻塞队列
新的 java.util.concurrent 包在 Collection Framework 中可用的具体集合类中加入了 BlockingQueue 接口和五个阻塞队列类。假如不熟悉阻塞队列概念,它实质上就是一种带有一点扭曲的 FIFO 数据结构。不是立即从队列中添加或者删除元素,线程执行操作阻塞,直到有空间或者元素可用。 BlockingQueue 接口的 Javadoc 给出了阻塞队列的基本用法,如清单 2 所示。生产者中的 put() 操作会在没有空间可用时阻塞,而消费者的 take() 操作会在队列中没有任何东西时阻塞。
清单 2. 使用 BlockingQueue
class Producer implements Runnable { private final BlockingQueue queue; Producer(BlockingQueue q) { queue = q; } public void run() { try { while(true) { queue.put(produce()); } } catch (InterruptedException ex) { ... handle ...} } Object produce() { ... } } class Consumer implements Runnable { private final BlockingQueue queue; Consumer(BlockingQueue q) { queue = q; } public void run() { try { while(true) { consume(queue.take()); } } catch (InterruptedException ex) { ... handle ...} } void consume(Object x) { ... } } class Setup { void main() { BlockingQueue q = new SomeQueueImplementation(); Producer p = new Producer(q); Consumer c1 = new Consumer(q); Consumer c2 = new Consumer(q); new Thread(p).start(); new Thread(c1).start(); new Thread(c2).start(); } }
五个队列所提供的各有不同:
ArrayBlockingQueue :一个由数组支持的有界队列。
LinkedBlockingQueue :一个由链接节点支持的可选有界队列。
PriorityBlockingQueue :一个由优先级堆支持的无界优先级队列。
DelayQueue :一个由优先级堆支持的、基于时间的调度队列。
SynchronousQueue :一个利用 BlockingQueue 接口的简单聚集(rendezvous)机制。
前两个类 ArrayBlockingQueue 和 LinkedBlockingQueue 几乎相同,只是在后备存储器方面有所不同, LinkedBlockingQueue 并不总是有容量界限。无大小界限的 LinkedBlockingQueue 类在添加元素时永远不会有阻塞队列的等待(至少在其中有 Integer.MAX_VALUE 元素之前不会)。
PriorityBlockingQueue 是具有无界限容量的队列,它利用所包含元素的 Comparable 排序顺序来以逻辑顺序维护元素。可以将它看作 TreeSet 的可能替代物。例如,在队列中加入字符串 One、Two、Three 和 Four 会导致 Four 被第一个取出来。对于没有天然顺序的元素,可以为构造函数提供一个 Comparator 。不过对 PriorityBlockingQueue 有一个技巧。从 iterator() 返回的 Iterator 实例不需要以优先级顺序返回元素。如果必须以优先级顺序遍历所有元素,那么让它们都通过 toArray() 方法并自己对它们排序,像 Arrays.sort(pq.toArray()) 。
新的 DelayQueue 实现可能是其中最有意思(也是最复杂)的一个。加入到队列中的元素必须实现新的 Delayed 接口(只有一个方法 —— long getDelay(java.util.concurrent.TimeUnit unit) )。因为队列的大小没有界限,使得添加可以立即返回,但是在延迟时间过去之前,不能从队列中取出元素。如果多个元素完成了延迟,那么最早失效/失效时间最长的元素将第一个取出。实际上没有听上去这样复杂。清单 3 演示了这种新的阻塞队列集合的使用:
清单 3. 使用 DelayQueue 实现
import java.util.*; import java.util.concurrent.*; public class Delay { /** * Delayed implementation that actually delays */ static class NanoDelay implements Delayed { long trigger; NanoDelay(long i) { trigger = System.nanoTime() + i; } public int compareTo(Object y) { long i = trigger; long j = ((NanoDelay)y).trigger; if (i < j) return -1; if (i > j) return 1; return 0; } public boolean equals(Object other) { return ((NanoDelay)other).trigger == trigger; } public boolean equals(NanoDelay other) { return ((NanoDelay)other).trigger == trigger; } public long getDelay(TimeUnit unit) { long n = trigger - System.nanoTime(); return unit.convert(n, TimeUnit.NANOSECONDS); } public long getTriggerTime() { return trigger; } public String toString() { return String.valueOf(trigger); } } public static void main(String args[]) throws InterruptedException { Random random = new Random(); DelayQueue queue = new DelayQueue(); for (int i=0; i < 5; i++) { queue.add(new NanoDelay(random.nextInt(1000))); } long last = 0; for (int i=0; i < 5; i++) { NanoDelay delay = (NanoDelay)(queue.take()); long tt = delay.getTriggerTime(); System.out.println("Trigger time: " + tt); if (i != 0) { System.out.println("Delta: " + (tt - last)); } last = tt; } } }
这个例子首先是一个内部类 NanoDelay ,它实质上将暂停给定的任意纳秒(nanosecond)数,这里利用了 System 的新 nanoTime() 方法。然后 main() 方法只是将 NanoDelay 对象放到队列中并再次将它们取出来。如果希望队列项做一些其他事情,就需要在 Delayed 对象的实现中加入方法,并在从队列中取出后调用这个新方法。(请随意扩展 NanoDelay 以试验加入其他方法做一些有趣的事情。)显示从队列中取出元素的两次调用之间的时间差。如果时间差是负数,可以视为一个错误,因为永远不会在延迟时间结束后,在一个更早的触发时间从队列中取得项。
SynchronousQueue 类是最简单的。它没有内部容量。它就像线程之间的手递手机制。在队列中加入一个元素的生产者会等待另一个线程的消费者。当这个消费者出现时,这个元素就直接在消费者和生产者之间传递,永远不会加入到阻塞队列中。
使用 ConcurrentMap 实现
新的 java.util.concurrent.ConcurrentMap 接口和 ConcurrentHashMap 实现只能在键不存在时将元素加入到 map 中,只有在键存在并映射到特定值时才能从 map 中删除一个元素。
有一个新的 putIfAbsent() 方法用于在 map 中进行添加。这个方法以要添加到 ConcurrentMap 实现中的键的值为参数,就像普通的 put() 方法,但是只有在 map 不包含这个键时,才能将键加入到 map 中。如果 map 已经包含这个键,那么这个键的现有值就会保留。 putIfAbsent() 方法是原子的。如果不调用这个原子操作,就需要从适当的同步块中调用清单 4 中的代码:
清单 4. 等价的 putIfAbsent() 代码
if (!map.containsKey(key)) { return map.put(key, value); } else { return map.get(key); }
像 putIfAbsent() 方法一样,重载后的 remove() 方法有两个参数 —— 键和值。在调用时,只有当键映射到指定的值时才从 map 中删除这个键。如果不匹配,那么就不删除这个键,并返回 false。如果值匹配键的当前映射内容,那么就删除这个键。清单 5 显示了这种操作的等价源代码:
清单 5. 等价的 remove() 代码
if (map.get(key).equals(value)) { map.remove(key); return true; } else { return false; }
使用 CopyOnWriteArrayList 和 CopyOnWriteArraySet
在 Doug Lea 的 Concurrent Programming in Java一书的第 2 章第 2.4.4 节(请参阅 参考资料)中,对 copy-on-write 模式作了最好的描述。实质上,这个模式声明了,为了维护对象的一致性快照,要依靠不可变性(immutability)来消除在协调读取不同的但是相关的属性时需要的同步。对于集合,这意味着如果有大量的读(即 get() ) 和迭代,不必同步操作以照顾偶尔的写(即 add() )调用。对于新的 CopyOnWriteArrayList 和 CopyOnWriteArraySet 类,所有可变的(mutable)操作都首先取得后台数组的副本,对副本进行更改,然后替换副本。这种做法保证了在遍历自身更改的集合时,永远不会抛出 ConcurrentModificationException 。遍历集合会用原来的集合完成,而在以后的操作中使用更新后的集合。
这些新的集合, CopyOnWriteArrayList 和 CopyOnWriteArraySet ,最适合于读操作通常大大超过写操作的情况。一个最常提到的例子是使用监听器列表。已经说过,Swing 组件还没有改为使用新的集合。相反,它们继续使用 javax.swing.event.EventListenerList 来维护它们的监听器列表。
如清单 6 所示,集合的使用与它们的非 copy-on-write 替代物完全一样。只是创建集合并在其中加入或者删除元素。即使对象加入到了集合中,原来的 Iterator 也可以进行,继续遍历原来集合中的项。
清单 6. 展示一个 copy-on-write 集合
import java.util.*; import java.util.concurrent.*; public class CopyOnWrite { public static void main(String args[]) { List list1 = new CopyOnWriteArrayList(Arrays.asList(args)); List list2 = new ArrayList(Arrays.asList(args)); Iterator itor1 = list1.iterator(); Iterator itor2 = list2.iterator(); list1.add("New"); list2.add("New"); try { printAll(itor1); } catch (ConcurrentModificationException e) { System.err.println("Shouldn't get here"); } try { printAll(itor2); } catch (ConcurrentModificationException e) { System.err.println("Will get here."); } } private static void printAll(Iterator itor) { while (itor.hasNext()) { System.out.println(itor.next()); } } }
这个示例程序用命令行参数创建 CopyOnWriteArrayList 和 ArrayList 这两个实例。在得到每一个实例的 Iterator 后,分别在其中加入一个元素。当 ArrayList 迭代因一个 ConcurrentModificationException 问题而立即停止时, CopyOnWriteArrayList 迭代可以继续,不会抛出异常,因为原来的集合是在得到 iterator 之后改变的。如果这种行为(比如通知原来一组事件监听器中的所有元素)是您需要的,那么最好使用 copy-on-write 集合。如果不使用的话,就还用原来的,并保证在出现异常时对它进行处理。
结束语
在 J2SE 平台的 Tiger 版中有许多重要的增加。除了语言级别的改变,如一般性支持,这个库也许是最重要的增加了,因为它会被最广泛的用户使用。不要忽视加入到平台中的其他包,像 Java Management Extensions (JMX),但是大多数其他重要的库增强只针对范围很窄的开发人员。但是这个库不是。除了用于锁定和原子操作的其他并发实用程序,这些类也会经常使用。尽早学习它们并利用它们所提供的功能。
【翻译】(65)uses-configuration元素
see
http://developer.android.com/guide/topics/manifest/uses-configuration-element.html
原文见
http://developer.android.com/guide/topics/manifest/uses-configuration-element.html
-------------------------------
<uses-configuration>
uses-configuration元素
-------------------------------
* syntax:
* 语法:
-------------------------------
<uses-configuration android:reqFiveWayNav=["true" | "false"]
android:reqHardKeyboard=["true" | "false"]
android:reqKeyboardType=["undefined" | "nokeys" | "qwerty" |
"twelvekey"]
android:reqNavigation=["undefined" | "nonav" | "dpad" |
"trackball" | "wheel"]
android:reqTouchScreen=["undefined" | "notouch" | "stylus" |
"finger"] />
-------------------------------
* contained in:
* 被包含在:
<manifest>
* description:
* 描述:
Indicates what hardware and software features the application requires. For example, an application might specify that it requires a physical keyboard or a particular navigation device, like a trackball. The specification is used to avoid installing the application on devices where it will not work.
指示该应用程序需要什么硬件和软件特性。例如,一个应用程序可能指定它需要一个物理键盘或一个特殊的导航设备,像一个轨迹球。使用此规范来避免在它不能运行在的设备上安装该应用程序。
If an application can work with different device configurations, it should include separate <uses-configuration> declarations for each one. Each declaration must be complete. For example, if an application requires a five-way navigation control, a touch screen that can be operated with a finger, and either a standard QWERTY keyboard or a numeric 12-key keypad like those found on most phones, it would specify these requirements with two <uses-configuration> elements as follows:
如果一个应用程序可以应付不同设备配置,那么它应该为每个配置包含分离的<uses-configuration>声明。每个声明必须是完整的。例如,如果一个应用程序需要一个五方向的导航控制,一个可以用手指操作的触摸屏,以及一个标准QWERTY键盘(注:就是指平时PC机用的那种键盘)或一个像在大多数电话上找到的那种数字12键的数字键盘,那么它会用两个<uses-configuration>元素指定这些需求,如下:
-------------------------------
<uses-configuration android:reqFiveWayNav="true" android:reqTouchScreen="finger"
android:reqKeyboardType="qwerty" />
<uses-configuration android:reqFiveWayNav="true" android:reqTouchScreen="finger"
android:reqKeyboardType="twelvekey" />
-------------------------------
* attributes:
* 属性:
* android:reqFiveWayNav
Whether or not the application requires a five-way navigation control — "true" if it does, and "false" if not. A five-way control is one that can move the selection up, down, right, or left, and also provides a way of invoking the current selection. It could be a D-pad (directional pad), trackball, or other device.
应用程序是否需要一个五方向导航控制——"true"如果它需要,而"false"如果它不需要。一个五方向控制是指可以把选择向上,向下,向右,或向左移动,并且还提供一种方式调用当前的选择。它可以是一个D-pad(方向板),轨迹球,或其它设备。
If an application requires a directional control, but not a control of a particular type, it can set this attribute to "true" and ignore the reqNavigation attribute. However, if it requires a particular type of directional control, it can ignore this attribute and set reqNavigation instead.
如果一个应用程序需要一个方向控制,但不是一种特定类型的控制,那么它可以设置这个属性为"true"并且忽略reqNavigation属性。然而,如果它需要一种方向控制的特定类型,那么可以忽略此属性并且改为设置reqNavigation属性。
* android:reqHardKeyboard
Whether or not the application requires a hardware keyboard — "true" if it does, and "false" if not.
应用程序是否需要一个硬件键盘——"true"如果它需要,而"false"如果不需要。
* android:reqKeyboardType
The type of keyboard the application requires, if any at all. This attribute does not distinguish between hardware and software keyboards. If a hardware keyboard of a certain type is required, specify the type here and also set the reqHardKeyboard attribute to "true".
应用程序必需的键盘的类型,如果有的话。这个属性没有区分硬键盘和软键盘。如果某类型的硬键盘是必需的,在这里指定该类型,同时还也设置reqHardKeyboard为"true"。
The value must be one of the following strings:
值必须是以下字符串之一:
-------------------------------
* Value Description
* 值 描述
* "undefined" The application does not require a keyboard. (A keyboard requirement is not defined.) This is the default value.
* "undefined" 应用程序不需要键盘。(键盘要求没有被定义。)这是默认值。
* "nokeys" The application does not require a keyboard.
* "nokeys" 应用程序不需要键盘。
* "qwerty" The application requires a standard QWERTY keyboard.
* "qwerty" 应用程序需要一个标准QWERTY键盘。
* "twelvekey" The application requires a twelve-key keypad, like those on most phones — with keys for the digits from 0 through 9 plus star (*) and pound (#) keys.
* "twelvekey" 应用程序需要一个12键键盘,像大多数电话上的那样——带有表示从0到9的数字加上星号(*)和井号(#)键的按键。
-------------------------------
* android:reqNavigation
The navigation device required by the application, if any. The value must be one of the following strings:
应用程序必需的导航设备,如果有的话。值必须是以下字符串之一:
-------------------------------
* Value Description
* 值 描述
* "undefined" The application does not require any type of navigation control. (The navigation requirement is not defined.) This is the default value.
* "undefined" 应用程序不需要任意导航控制类型。(导航要求没有被定义。)这是默认值。
* "nonav" The application does not require a navigation control.
* "nonav" 应用程序不需要一个导航控制。
* "dpad" The application requires a D-pad (directional pad) for navigation.
* "dpad" 应用程序需要一个D-pad(方向板)用于导航。
* "trackball" The application requires a trackball for navigation.
* "trackball" 应用程序需要一个轨迹球用于导航
* "wheel" The application requires a navigation wheel.
* "wheel" 应用程序需要一个导航滚轮。
-------------------------------
If an application requires a navigational control, but the exact type of control doesn't matter, it can set the reqFiveWayNav attribute to "true" rather than set this one.
如果一个应用程序需要一个导航控制,但具体的控制类型不要紧,那么可以设置reqFiveWayNav属性为"true"而非设置这个属性。
* android:reqTouchScreen
The type of touch screen the application requires, if any at all. The value must be one of the following strings:
应用程序需要的触摸屏的类型,如果有的话。该值必须是以下字符串之一:
-------------------------------
* Value Description
* 值 描述
* "undefined" The application doesn't require a touch screen. (The touch screen requirement is undefined.) This is the default value.
* "undefined" 应用程序不需要一个触摸屏。(触摸屏要求是未定义的。)这是默认值。
* "notouch" The application doesn't require a touch screen.
* "notouch" 应用程序不需要一个触摸屏。
* "stylus" The application requires a touch screen that's operated with a stylus.
* "stylus" 应用程序需要一个触摸屏,它用手写笔来操作。
* "finger" The application requires a touch screen that can be operated with a finger.
* "finger" 应用程序需要一个触摸屏,它可以用手指来操作。
-------------------------------
* introduced in:
* 引入:
API Level 3
API级别3
* see also:
* 另见:
* configChanges attribute of the <activity> element <activity>元素的configChanges属性
* ConfigurationInfo
Except as noted, this content is licensed under Apache 2.0. For details and restrictions, see the Content License.
除特别说明外,本文在Apache 2.0下许可。细节和限制请参考内容许可证。
Android 4.0 r1 - 14 Feb 2012 21:12
-------------------------------
Portions of this page are modifications based on work created and shared by the Android Open Source Project and used according to terms described in the Creative Commons 2.5 Attribution License.
(此页部分内容基于Android开源项目,以及使用根据创作公共2.5来源许可证描述的条款进行修改)
(本人翻译质量欠佳,请以官方最新内容为准,或者参考其它翻译版本:
* ソフトウェア技術ドキュメントを勝手に翻訳
http://www.techdoctranslator.com/android
* Ley's Blog
http://leybreeze.com/blog/
* 农民伯伯
http://www.cnblogs.com/over140/
* Android中文翻译组
http://androidbox.sinaapp.com/
)