Android 线程消息循环机制

android.os.Looper:

Looper用于封装了android线程中的消息循环,默认情况下一个线程是不存在消息循环(message loop)的,需要调用Looper.prepare()来给线程创建一个消息循环,调用Looper.loop()来使消息循环起作用,从消息队列里取消息,处理消息。
注:写在Looper.loop()之后的代码不会被立即执行,当调用后mHandler.getLooper().quit()后,loop才会中止,其后的代码才能得以运行。Looper对象通过MessageQueue来存放消息和事件。一个线程只能有一个Looper,对应一个MessageQueue。

以下是Android API中的一个典型的Looper thread实现:
//Handler不带参数的默认构造函数:new Handler(),实际上是通过Looper.myLooper()来获取当前线程中的消息循环, //而默认情况下,线程是没有消息循环的,所以要调用 Looper.prepare()来给线程创建消息循环,然后再通过,Looper.loop()来使消息循环起作用。
class LooperThread extends Thread {
public Handler mHandler;

public void run() {
Looper.prepare();

mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};

Looper.loop();
}
}
另,Activity的MainUI线程默认是有消息队列的。所以在Activity中新建Handler时,不需要先调用Looper.prepare()。

android.os.Handler:

Handler用于跟线程绑定,来向线程的消息循环里面发送消息、接受消息并处理消息。

以下是不带参数的Handler构造器:

public Handler() {

if (FIND_POTENTIAL_LEAKS) {
final Class klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, “The following Handler class should be static or leaks might occur: ” +
klass.getCanonicalName());
}
}

mLooper = Looper.myLooper();
if (mLooper == null) {

//如果当前线程里面没有消息循环的时候,系统抛出异常。即在一个线程里如果想用Handler来处理消息,是需要调用Looer.prepare()来创建消息循环的,而MainUI线程不需要。

throw new RuntimeException(
“Can’t create handler inside thread that has not called Looper.prepare()”);
}
mQueue = mLooper.mQueue;
mCallback = null;
}

通过以下函数来向线程发送消息或Runnable:
1、post(Runnable), postAtTime(Runnable, long), postDelayed(Runnable, long);
当线程接收到Runnable对象后即立即或一定延迟调用。
2、sendEmptyMessage(int), sendMessage(Message), sendMessageAtTime(Message, long), and sendMessageDelayed(Message, long)。
当线程接受到这些消息后,根据你的Handler重构的handleMessage(Message)根据接收到的消息来进行处理。
另,一个Activity主线程中可以有多个Handler对象,但MessageQueueLooper是只有一个,对应的Looper也是只有一个。

转:自定义Activity栈来管理android的Activity

import java.util.Stack;
import android.app.Activity;

public class ScreenManager {
private static Stack activityStack;
private static ScreenManager instance;
private ScreenManager(){
}

public static ScreenManager getScreenManager(){
if(instance==null){
instance=new ScreenManager();
}
return instance;
}

public void popActivity(){
Activity activity=activityStack.lastElement();
if(activity!=null){
activity.finish();
activity=null;
}
}

public void popActivity(Activity activity){
if(activity!=null){
activity.finish();
activityStack.remove(activity);
activity=null;
}
}

public Activity currentActivity(){
Activity activity=activityStack.lastElement();
return activity;
}

public void pushActivity(Activity activity){
if(activityStack==null){
activityStack=new Stack();
}
activityStack.add(activity);
}

public void popAllActivityExceptOne(Class cls){
while(true){
Activity activity=currentActivity();
if(activity==null){
break;
}
if(activity.getClass().equals(cls) ){
break;
}
popActivity(activity);
}
}
}

只能在一个Activity的对象里面调用finish来关闭自己,不能关闭其他的Activity。比如我们想实现一个功能从屏幕A—>屏幕B—>屏幕C—>屏幕D,然后在在转到屏幕D之前将屏幕B和C关闭,在屏幕B和屏幕C界面点击会退按钮都可以回退到上一个屏幕,但是在屏幕D上点击会退按钮让其回退到A,此外在一些循环跳转的界面上如果不在合适的地方将一些不需要的屏幕关闭,那么经过多次跳转后回导致内存溢出。对此我们可以设计一个全局的Activity栈,使用这个栈来管理Activity

ps:代码只是个思路的参考,实际使用需要自己进行调整

Intent.FLAG…

intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT)

如果task中已经有这个activity A,那么就把A拿到task的最顶层,而不是创建一个新的activity。
所以不加flag也不会影响界面的切过去,只是会影响task的顺序而已。

i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)

清除该进程空间的所有Activity

在A窗口中使用下面的代码调用B窗口

Intent intent = new Intent();
intent.setClass(Android123.this, CWJ.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);  //注意本行的FLAG设置
startActivity(intent);

接下来在B窗口中需要退出时直接使用finish方法即可全部退出

 

Android的KeyEvent.java源码一个神奇的片段

1.定义了

/**
* Private control to determine when an app is tracking a key sequence.
* @hide
*/
public static final int FLAG_START_TRACKING = 0x40000000;
private int mFlags;

//中间省略了无关紧要的代码
//后面有个代码片段
switch (mAction) {
case ACTION_DOWN: {
mFlags &= ~FLAG_START_TRACKING;
if (DEBUG)
Log.v(TAG, "Key down to " + target + " in " + state
+ ": " + this );
boolean res = receiver.onKeyDown(mKeyCode, this );
if (state != null) {
if (res && mRepeatCount == 0
&& (mFlags & FLAG_START_TRACKING) != 0) {
if (DEBUG)
Log.v(TAG, "  Start tracking!");
state.startTracking(this , target);
} else if (isLongPress() && state.isTracking(this )) {
try {
if (receiver.onKeyLongPress(mKeyCode, this )) {
if (DEBUG)
Log.v(TAG, "  Clear from long press!");
state.performedLongPress(this );
res = true;
}
} catch (AbstractMethodError e) {
}
}
}
return res;
}

 

注意两条:

1.mFlags &= ~FLAG_START_TRACKING;

2.if (res && mRepeatCount == 0&& (mFlags & FLAG_START_TRACKING) != 0)

神奇的地反过就是2这个if肯定是为false的一啊,

mFlags & FLAG_START_TRACKING

<=>

mFlags&(~FLAG_START_TRACKING)&FLAG_START_TRACKING

这个肯定为0,所以就奇怪这个if有什么意思~一致搞不明白,这个问题也是群里一个网友提问的。我也被怔住了

Android-Service的远程调用(不用android应用之间)

在Andorid平台中,各个组件运行在自己的进程中,他们之间是不能相互访问的,但是在程序之间是不可避免的要传递一些对象,在进程之间相互通信。为了实现进程之间的相互通信,Andorid采用了一种轻量级的实现方式RPC(Remote Procedure Call 远程进程调用)来完成进程之间的通信,并且Android通过接口定义语言(Andorid Interface Definition Language ,AIDL)来生成两个进程之间相互访问的代码,例如,你在Activity里的代码需要访问Service中的一个方法,那么就可以通过这种方式来实现了。

AIDL是Android的一种接口描述语言; 编译器可以通过aidl文件生成一段代码,通过预先定义的接口达到两个进程内部通信进程的目的. 如果需要在一个Activity中, 访问另一个Service中的某个对象, 需要先将对象转化成 AIDL可识别的参数(可能是多个参数), 然后使用AIDL来传递这些参数, 在消息的接收端, 使用这些参数组装成自己需要的对象。

AIDL RPC机制是通过接口来实现的,类似Windows中的COM或者Corba,但他是轻量级的,客户端和被调用实现之间是通过代理模式实现的,代理类和被代理类实现同一个接口Ibinder接口。

下面是实现Activity访问Service例子的步骤:

一.创建.aidl文件

AIDL使用简单的语法来声明接口,描述其方法以及方法的参数和返回值。这些参数和返回值可以是任何类型,甚至是其他AIDL生成的接口。重要的是必须导入导入除了内建类型(例如:int,boolean等)外的任何其他类型,哪怕是这些类型是在与接口相同的包中。具体的要求如下:

  • JAVA基本数据类型不需要导入
  • String,List,Map和CharSequence不需要导入

使用Eclipse的ADT插件创建一个BookInfo.aidl文件,该文件有4个方法:

setName(String name)设置图书的书名,setPrice(int price)设置图书的价格,setPublish(String pname)设置图书的出版社和String display()显示图书的信息.

BookInfo.aidl文件

  1. package com.android.aidl;
  2. //BookInfo接口
  3. interface BookInfo{
  4.     void setName(String name);
  5.     void setPrice(int price);
  6.     void ssetPublish(String pname);
  7.     //显示图书的信息
  8.     String display();
  9. }

创建好BookInfo.aidl文件,系统会自动在gen目录下生成Java接口文件BookInfo.java

二.实现AIDL文件生成的JAVA接口

AIDL会生成一个和.aidl文件同名的JAVA接口文件,该接口中有一个静态抽象内部类Stub,该类中声明了AIDL文件中定义的所有方法,其中有一个重要的方法是asInterface(),该方法通过代理模式返回JAVA接口的实现我们可以定义一个实现类,BookImpl,该类继承Stub类,实现我们定义的4个方法

  1. package com.android.aidl;
  2. import android.os.RemoteException;
  3. public class BookInfoImpl extends BookInfo.Stub {
  4.     //声明三个个变量
  5.     private int price;
  6.     private String name,pname;
  7.     //显示书名,价格,出版社
  8.     public String display() throws RemoteException{
  9.         return "书名:"+name+";价格:"+price+";出版社:"+price;
  10.     }
  11.     @Override
  12.     //设置书名
  13.     public void setName(String name) throws RemoteException {
  14.         // TODO Auto
  15.         this.name= name;
  16.     }
  17.     @Override
  18.     //设置价格
  19.     public void setPrice(int price) throws RemoteException {
  20.         // TODO Auto-generated method stub
  21.         this.price = price;
  22.     }
  23.     @Override
  24.     //设置出版社
  25.     public void setPublish(String pname) throws RemoteException {
  26.         // TODO Auto
  27.         this.pname= pname;
  28.     }
  29. }

三.向客户端暴露接口

现在已经实现了BookInfo接口,接下来要将该接口暴露给客户端调用。一般通过定义一个Service来实现,在Service的onBind()方法中返回该接口,当我们绑定该接口时调用该方法。

  1. package com.android.aidl;
  2. import com.android.aidl.BookInfo.Stub;
  3. import android.app.Service;
  4. import android.content.Intent;
  5. import android.os.IBinder;
  6. public class RemoteService extends Service {
  7.     //声明BookInfo接口
  8.     private Stub bookifo = new BookInfoImpl();
  9.     public IBinder onBind(Intent intent){
  10.         return bookifo;
  11.     }
  12. }

四.在客户端调用

定义一个Activity来绑定远程Service,获得BookInfo接口,通过RPC机制调用接口中的方法。

  1. package com.android.aidl;
  2. import android.app.Activity;
  3. import android.app.Service;
  4. import android.content.ComponentName;
  5. import android.content.Intent;
  6. import android.content.ServiceConnection;
  7. import android.os.Bundle;
  8. import android.os.IBinder;
  9. import android.os.RemoteException;
  10. import android.view.View;
  11. import android.view.View.OnClickListener;
  12. import android.widget.Button;
  13. import android.widget.Toast;
  14. public class MainActivity extends Activity {
  15.     // 声明IPerson接口
  16.     private BookInfo bookInfo;
  17.     // 声明 Button
  18.     private Button btn;
  19.     // 实例化ServiceConnection
  20.     private ServiceConnection conn = new ServiceConnection() {
  21.         @Override
  22.         synchronized public void onServiceConnected(ComponentName name, IBinder service) {
  23.             // 获得IPerson接口
  24.             bookInfo = BookInfo.Stub.asInterface(service);
  25.             if (bookInfo != null)
  26.                 try {
  27.                     // RPC 方法调用
  28.                     bookInfo.setName("Google Android SDK开发范例大全");
  29.                     bookInfo.setPrice(55);
  30.                     bookInfo.setPublish("人民邮电出版社");
  31.                     String msg = bookInfo.display();
  32.                     // 显示方法调用返回值
  33.                     Toast.makeText(MainActivity.this, msg, Toast.LENGTH_LONG)
  34.                             .show();
  35.                 } catch (RemoteException e) {
  36.                     e.printStackTrace();
  37.                 }
  38.         }
  39.         @Override
  40.         public void onServiceDisconnected(ComponentName name) {
  41.         }
  42.     };
  43.     @Override
  44.     public void onCreate(Bundle savedInstanceState) {
  45.         super.onCreate(savedInstanceState);
  46.         // 设置当前视图布局
  47.         setContentView(R.layout.main);
  48.         // 实例化Button
  49.         btn = (Button) findViewById(R.id.Button1);
  50.         //为Button添加单击事件监听器
  51.         btn.setOnClickListener(new OnClickListener() {
  52.             @Override
  53.             public void onClick(View v) {
  54.                 // 实例化Intent
  55.                 Intent intent = new Intent();
  56.                 // 设置Intent Action 属性
  57.                 intent.setAction("com.android.aidl.action.MY_REMOTE_SERVICE");
  58.                 // 绑定服务
  59.                 bindService(intent, conn, Service.BIND_AUTO_CREATE);
  60.             }
  61.         });
  62.     }
  63. }

五.main.xml和AndroidManifest.xml文件

main.xml

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout 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.     >
  7.     <Button
  8.         android:text="远程调用Service"
  9.         android:id="@+id/Button1"
  10.         android:layout_width="wrap_content"
  11.         android:layout_height="wrap_content"
  12.         />
  13. </LinearLayout>

在AndroidManifest.xml文件16~20声明Service

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"
  3.       package="com.android.aidl"
  4.       android:versionCode="1"
  5.       android:versionName="1.0">
  6.     <uses-sdk android:minSdkVersion="10" />
  7.     <application android:icon="@drawable/icon" android:label="@string/app_name">
  8.         <activity android:name=".MainActivity"
  9.                   android:label="@string/app_name">
  10.             <intent-filter>
  11.                 <action android:name="android.intent.action.MAIN" />
  12.                 <category android:name="android.intent.category.LAUNCHER" />
  13.             </intent-filter>
  14.         </activity>
  15.      <service android:name="RemoteService">
  16.             <intent-filter>
  17.                 <action android:name="com.android.aidl.action.MY_REMOTE_SERVICE"/>
  18.             </intent-filter>
  19.     </service>
  20.     </application>
  21. </manifest>

效果图:

 

Android与服务器端数据交互(基于SOAP协议整合android+webservice)

那么什么是webService呢?,它是一种基于SAOP协议的远程调用标准,通过webservice可以将不同操作系统平台,不同语言,不同技术整合到一起。

我们在PC机器java客户端中,需要一些库,比如XFire,Axis2,CXF等等来支持访问WebService,但是这些库并不适合我们资源有限的android手机客户端,做过JAVA ME的人都知道有KSOAP这个第三方的类库,可以帮助我们获取服务器端webService调用,当然KSOAP已经提供了基于android版本的jar包了,那么我们就开始吧:

首先下载KSOAP包:ksoap2-android-assembly-2.5.2-jar-with-dependencies.jar包

然后新建android项目:并把下载的KSOAP包放在android项目的lib目录下:右键->build path->configure build path–选择Libraries,如图:

以下分为七个步骤来调用WebService方法:

第一:实例化SoapObject 对象,指定webService的命名空间(从相关WSDL文档中可以查看命名空间),以及调用方法名称。如:

View Code

//命名空间 private static final String serviceNameSpace="http://WebXml.com.cn/"; //调用方法(获得支持的城市) private static final String getSupportCity="getSupportCity"; //实例化SoapObject对象 SoapObject request=new SoapObject(serviceNameSpace, getSupportCity);

第二步:假设方法有参数的话,设置调用方法参数

request.addProperty(“参数名称”,”参数值”);

第三步:设置SOAP请求信息(参数部分为SOAP协议版本号,与你要调用的webService中版本号一致):

View Code

//获得序列化的Envelope SoapSerializationEnvelope envelope=
new SoapSerializationEnvelope(SoapEnvelope.VER11); envelope.bodyOut=request;

第四步:注册Envelope,

(new MarshalBase64()).register(envelope);

第五步:构建传输对象,并指明WSDL文档URL:

View Code

//请求URL private static final String serviceURL=
"http://www.webxml.com.cn/webservices/weatherwebservice.asmx"; //Android传输对象 AndroidHttpTransport transport=new AndroidHttpTransport(serviceURL); transport.debug=true;

第六步:调用WebService(其中参数为1:命名空间+方法名称,2:Envelope对象):

View Code

transport.call(serviceNameSpace+getWeatherbyCityName, envelope);

第七步:解析返回数据:

View Code

if(envelope.getResponse()!=null){

 

RPC、RMI、SOAP(webService)

RPC(Remote Procedure Call Protocol)——远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序之间携带信息数据。在OSI网络通信模型中,RPC跨越了传输层和应用层。RPC使得开发包括网络分布式多程序在内的应用程序更加容易。

RMI(远程方法调用)

Web Service

在构建和使用Web Service时,主要用到以下几个关键的技术和规则:  1.XML:描述数据的标准方法.  2.SOAP:表示信息交换的协议.  3.WSDL:Web服务描述语言.  4.UDDI(Universal Description, Discovery and Integration):通用描述、发现与集成,它是一种独立于平台的,基于XML语言的用于在互联网上描述商务的协议。

RMI和RPC之间最主要的区别在于方法是如何别调用的。在RMI中,远程接口使每个远程方法都具有方法签名。如果一个方法在服务器上执行,但是没有相匹配的签名被添加到这个远程接口上,那么这个新方法就不能被RMI客户方所调用。在RPC中,当一个请求到达RPC服务器时,这个请求就包含了一个参数集和一个文本值,通常形成“classname.methodname”的形式。这就向RPC服务器表明,被请求的方法在为“classname”的类中,名叫“methodname”。然后RPC服务器就去搜索与之相匹配的类和方法,并把它作为那种方法参数类型的输入。这里的参数类型是与RPC请求中的类型是匹配的。一旦匹配成功,这个方法就被调用了,其结果被编码后返回客户方。

RMI目前使用Java远程消息交换协议JRMP(Java Remote Messaging Protocol)进行通信,但由于JRMP是专为Java对象制定的,因此,RMI对于用非Java语言开发的应用系统的支持不足。不能与用非Java语言书写的对象进行通信。

xml-rpc 这种远程过程调用使用http作为传输协议,XML作为传送信息的编码格式。Xml-Rpc的定义尽可能的保持了简单,但同时能够传送、处理、返回复杂的数据结构。

 

 

 

Spring2.5整合RMI技术-CLIENT端

二、客户端调用测试

客户端调用有两种方式,一种是使用Spring,一种不使用,这里仅介绍使用Spring的情况。

在Spring中配置客户端要调用服务:

 

<?xml version=”1.0″ encoding=”UTF-8″?>
<beans
xmlns=”http://www.springframework.org/schema/beans”
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
xsi:schemaLocation=”http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd”>
<bean id=”helloService” class=”org.springframework.remoting.rmi.RmiProxyFactoryBean”>
<property name=”serviceUrl” value=”rmi://192.168.14.117:8088/hello”/>
<property name=”serviceInterface” value=”lavasoft.sturmi.HelloService”/>
</bean>

<bean id=”helloServiceClient” class=”lavasoft.sturmi.HelloClient”>
<property name=”helloService” ref=”helloService”/>
</bean>
</beans>

 

客户端测试代码:

 

package lavasoft.sturmi;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.rmi.RemoteException;

/**
* 通过Spring来调用RMI服务
*
* @author leizhimin 2009-8-17 14:12:46
*/

public class HelloClient {
private HelloService helloService;

public static void main(String[] args) throws RemoteException {
ApplicationContext ctx = newClassPathXmlApplicationContext(“/applicationContext_rmi_client.xml”);
HelloService hs = (HelloService) ctx.getBean(“helloService”);
System.out.println(hs.helloWorld());
System.out.println(hs.sayHelloToSomeBody(“Lavasoft”));
}

public void setHelloService(HelloService helloService) {
this.helloService = helloService;
}
}

 

运行结果:

 

Spring2.5整合RMI技术-SERVER端

Java的RMI技术使用起来比较麻烦,有两点:服务发布和调用服务。

通过Spring的RMI支持,可以非常容易的暴露任何的服务。

下面是之前一篇《Java RMI之HelloWorld篇》文章的基础上,加入了Spring的框架来实现的例子。

环境:jdk1.5

spring-framework-2.5.6.SEC01

所用的第三方包优先从Spring的lib包中获取,以获取最佳的兼容性。

所依赖的jar包:

一、服务端实现

第一服务接口,和以前不一样了,不用实现远程接口了。

 

package lavasoft.sturmi;

/**
* 定义一个远程接口
*
* @author leizhimin 2009-8-17 13:53:38
*/

public interface HelloService {

/**
* 简单的返回“Hello World!”字样
*
* @return 返回“Hello World!”字样
*/

public String helloWorld();

/**
* 一个简单的业务方法,根据传入的人名返回相应的问候语
*
* @param someBodyName 人名
* @return 返回相应的问候语
*/

public String sayHelloToSomeBody(String someBodyName);
}

 

服务实现类

 

package lavasoft.sturmi;

/**
* 远程的接口的实现
*
* @author leizhimin 2009-8-17 13:54:38
*/

public class HelloServiceImpl implements HelloService {
public HelloServiceImpl() {
}

/**
* 简单的返回“Hello World!”字样
*
* @return 返回“Hello World!”字样
*/

public String helloWorld() {
return “Hello World!”;
}

/**
* 一个简单的业务方法,根据传入的人名返回相应的问候语
*
* @param someBodyName 人名
* @return 返回相应的问候语
*/

public String sayHelloToSomeBody(String someBodyName) {
return “你好,” + someBodyName + “!”;
}
}

 

Spring配置rmi服务

 

<?xml version=”1.0″ encoding=”UTF-8″?>
<!DOCTYPE beans PUBLIC “-//SPRING//DTD BEAN//EN”
“http://www.springframework.org/dtd/spring-beans.dtd”>
<beans>
<bean id=”helloService” class=”lavasoft.sturmi.HelloServiceImpl”/>

<bean id=”serviceExporter” class=”org.springframework.remoting.rmi.RmiServiceExporter”>
<property name=”service” ref=”helloService”/>
<!– 定义服务名 –>
<property name=”serviceName” value=”hello”/>
<property name=”serviceInterface” value=”lavasoft.sturmi.HelloService”/>
<property name=”registryPort” value=”8088″/>
</bean>
</beans>

 

服务端测试

 

package lavasoft.sturmi;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
* 通过Spring发布RMI服务
*
* @author leizhimin 2009-8-17 14:22:06
*/

public class HelloHost {
public static void main(String[] args) {
ApplicationContext ctx = newClassPathXmlApplicationContext(“/applicationContext_rmi_server.xml”);
System.out.println(“RMI服务伴随Spring的启动而启动了…..”);
}
}

 

启动后如图所示:

 

MapView双击放大

首先我们要自己写一个类继承自MapView,起名为MyMapView,在这个类里我们重新下onInterceptTouchEvent方法。在时候map的Activity中new我们自己的MyMapView。

代码:

 

/* 
 * @(#)MyMapView.java    Created on 2011-11-10
 * Copyright (c) 2011 ZDSoft Networks, Inc. All rights reserved.
 * $Id$
 */
package com.mine.www.maps;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;

import com.google.android.maps.MapView;

/**
 * @author gex
 * @version $Revision: 1.0 $, $Date: 2011-11-10 下午07:25:48 $
 */
public class MyMapView extends MapView {
    private long lastTouchTime = -1;

    public MyMapView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            long thisTime = System.currentTimeMillis();
            if (thisTime - lastTouchTime < 250) {
                this.getController().zoomInFixing((int) ev.getX(), (int) ev.getY());
                lastTouchTime = -1;
            }
            else {
                lastTouchTime = thisTime;
            }
        }
        return super.onInterceptTouchEvent(ev);
    }

}