位置感知的应用程序.docx

上传人:b****5 文档编号:7033526 上传时间:2023-01-16 格式:DOCX 页数:16 大小:137.23KB
下载 相关 举报
位置感知的应用程序.docx_第1页
第1页 / 共16页
位置感知的应用程序.docx_第2页
第2页 / 共16页
位置感知的应用程序.docx_第3页
第3页 / 共16页
位置感知的应用程序.docx_第4页
第4页 / 共16页
位置感知的应用程序.docx_第5页
第5页 / 共16页
点击查看更多>>
下载资源
资源描述

位置感知的应用程序.docx

《位置感知的应用程序.docx》由会员分享,可在线阅读,更多相关《位置感知的应用程序.docx(16页珍藏版)》请在冰豆网上搜索。

位置感知的应用程序.docx

位置感知的应用程序

WindowsMobile技术文章翻译系列

(1)—为WindowsMobile设备创建位置感知的应用程序

Author:

MagicBoy|Posted:

16.三月201020:

52150

作者:

MaartenStruys,Alten-PTS    日期:

2009-12-28

概要

为你的应用程序添加位置感知并在当前位置呼叫Web服务,不仅为在线商务应用也为其他各种各样的消费者应用程序增加了许多潜在价值。

你可以根据本文介绍的技术通过GPS检索或蜂窝站点检索获取当前位置从而开发具备位置感知的应用程序。

本文主要讨论为WindowsMobile应用程序添加位置感知功能的技术细节。

涵盖了诸如定位对电池寿命的影响等问题,并提供了相关的代码和示例。

适用于

∙WindowsMobile5.0

∙WindowsMobile5.0SDK

∙WindowsMobile6Professional

∙WindowsMobile6SDK

索引

∙简介

∙通过GPS检索位置信息

∙使用GPSID托管包

∙通过蜂窝站点检索位置信息

∙在WindowsMobile设备上访问蜂窝站点信息

∙使WindowsMobile设备的位置感知不依赖于位置检索方式

∙使用类工厂取回当前位置

∙总结

∙关于代码

∙作者经历

简介

位置感知需要获得你的WindowsMobile设备的当前位置。

所以你必须使你的应用程序能够感知位置。

应用程序应该被设计为不依赖于位置检索方式。

这个白皮书向你展示了怎样通过GPS检索和蜂窝站点检索取得你的位置信息。

你也将学习到如何在WindowsMobile设备中使用位置信息。

通过GPS检索位置信息

在WindowsMobile设备中有几种不同的方式检索位置信息,各自有着不同的优势。

WindowsMobile5.0和WindowsMobile6.0设备中都包含了GPS中间驱动(GPSID)。

尽管从名字来看它似乎是一个设备驱动,但实际上它并不是一个真正的设备驱动。

GPSID是介于控制GPS接收器的设备驱动与要使用GPS信息的应用程序之间的一个抽象层。

应用程序和GPS硬件之间GPSID的存在给了WindowsMobile5.0及WindowsMobile6设备比以前本版本更大的优势。

通过GPSID,多个应用程序可以使用同一个GPS硬件,而在WindowsMobile5.0中这是不可能的。

在那些先前版本的WindowsMobile设备中同一时间只能有一个应用程序访问GPS硬件。

为了使一个应用程序通过GPS接收器获得位置信息,原来正在使用GPS硬件的应用必须关闭,至少必须停止使用GPS硬件。

GPSID解决了这个问题,因为它扮演了从底层使用GPS硬件的唯一应用程序。

同时,GPSID也扮演了多个应用程序的位置提供者。

GPSID公开了几个本地API来检索位置信息。

当然,这个白皮书重点关注托管应用程序开发。

托管应用开发者可以通过包含在WindowsMobile5.0和WindowsMobile6SDK中的简单代码来访问一系列基于本地GPSIDAPIs的托管包。

假设你已经安装了WindowsMobile6SDK在默认文件夹的话,你可以在以下路径找到这些托管包:

C:

\ProgramFiles\WindowsMobile6SDK\Samples\PocketPC\CS\GPS

这个路径和Windows Mobile5.0SDK是不同的。

使用GPSID托管包

打开WindowsMobile5.0或WindowsMobile6SDK中的GPS示例,你会看到一个包含完整源代码的项目。

为了使用GPSID托管包,你必须首先编译这个示例项目。

因为WindowsMobileSDKs实在VisualStudio2008之前发布的,所以在用VisualStudio2008编译示例项目之前必须先进行转化。

VisualStudio2008会处理项目的转换。

在示例项目编译之后,你会看到一个可执行文件和一个类库。

类库的名字为Microsoft.WindowsMobile.Samples.Location.dll。

它包含了这个GPSID托管包。

为了使用这些托管包,你必须在你的项目中添加对这个类库的引用。

下面的示意图展示了GPSID托管包中的类。

如果你想在你的托管应用程序中使用GPSID,在添加了对GPSID托管包的引用之后,首先必须创建一个Gps类的示例。

然后你需要在项目中调用Open以获取位置信息。

你可以用同步或异步的方式来获取位置信息。

在稍后的案例中,你将会在GPS接收器数据变化时获得持续更新的数据。

你必须意识到GPS通信,作为一个附加通信,是很消耗电池的。

因此,如果你不再需要在应用程序中获取位置信息时,请确保调用Gps对象的Close方法。

忽略调用Close方法会使Gps通讯保持工作状态,即使你不在需要获取位置信息。

下面的屏幕展示了一个同步和异步获取GPS位置信息的示例应用程序。

在调用同步方法GetPosition后,位置信息被取回,并且通过注册LocationChanged事件而持续更新。

为了同步获取位置,如以下的示例代码展示的一样,你必须在调用Gps对象的Open方法之后调用另外一个一个方法。

在这个代码示例中,一个Gps类的实例在MainForm的的构造方法中被创建,并立即调用了它的Open方法以启用GPS硬件。

当用户选择了MyLocation菜单后menuLocation_Click事件处理程序中的代码就会执行。

在这个事件处理程序中,你会看到程序通过GetPosition方法获取到了当前位置。

直到GPSID返回从底层硬件获得的位置后,这个方法才会中断。

在位置信息可用后,纬度、经度和头信息的读取就会生效并在一个Label空间中显示出来。

简而言之,在读取生效前任何操作都是不可用的。

GetPosition方法有两种可用的风格。

以下第一个示例代码中用的方法是一直等待,直到GPS硬件返回新的读取信息;换句话说,就是在收到来自一个或多个卫星的位置信息之前,程序会一直等待。

同时还有一个以时间戳对象为参数的重载方法可用。

用这个方法,可以返回一个缓存的只要不比指定时间戳老的位置信息,从而更高效得获取位置。

当你知道设备的位置从上次读取之后没有变化时,这个版本的GetPosition方法对初始化位置读取是很有用的。

如下的代码展示了如何通过GPSID同步获取位置。

publicpartialclassMainForm:

Form

{

privateGpsgps;

publicMainForm()

{

InitializeComponent();

gps=newGps();

gps.Open();

}

privatevoidmenuExit_Click(objectsender,EventArgse)

{

gps.Close();

Close();

}

privatevoidmenuLocation_Click(objectsender,EventArgse)

{

GpsPositionposition=gps.GetPosition();

LatLonglocation=newLatLong();

if(position.LatitudeValid)

location.Latitude=position.Latitude;

if(position.LongitudeValid)

location.Longitude=position.Longitude;

if(position.HeadingValid)

location.Heading=position.Heading;

StringBuildersb=newStringBuilder();

sb.AppendLine();

sb.Append("Latitude=");

sb.AppendLine(location.Latitude.ToString());

sb.Append("Longitude=");

sb.AppendLine(location.Longitude.ToString());

sb.Append("Heading=");

sb.AppendLine(location.Heading.ToString());

label1.Text=sb.ToString();

}

}

为了异步获取位置,如下一个示例代码所示,你必须注册LocationChanged事件。

在这个示例中GPS对象的初始化被省略了,因为它和第一个代码示例是一样的方式。

无论应用程序有没有注册LocationChanged事件,用户都可以选择LocationUpdates菜单(参看GPSLookup屏幕)。

当应用程序注册了这个事件时,在gps_LocationChanged事件处理程序中就会接收到持续更新的位置信息。

与同步方式取得的位置信息相同,这个信息在GpsPosition对象中也是可用的。

然而,异步更新是在不同的线程中获取的,甚至对GPSID用户来说是透明的。

因为除了用户界面控件的创建者进程之外其他进程都不允许更新用户界面,所以要更新用户界面还必须做一些其他的工作。

就像你在下面代码中gps_LocationChanged处理程序中看到的一样,控件必须通过Control.Invoke方法来更新。

如下代码展示了如何通过GPSID一步获取位置。

privatevoidmenuLocationUpdates_Click(objectsender,EventArgse)

{

if(menuLocationUpdates.Checked)

{

menuLocationUpdates.Checked=false;

gps.LocationChanged-=gps_LocationChanged;

}

else

{

menuLocationUpdates.Checked=true;

gps.LocationChanged+=new

LocationChangedEventHandler(gps_LocationChanged);

}

}

privatedelegatevoidUpdateLocationInfo();

voidgps_LocationChanged(objectsender,LocationChangedEventArgsargs)

{

GpsPositionposition=args.Position;

LatLonglocation=newLatLong();

if(position.LatitudeValid)

location.Latitude=position.Latitude;

if(position.LongitudeValid)

location.Longitude=position.Longitude;

if(position.HeadingValid)

location.Heading=position.Heading;

StringBuildersb=newStringBuilder();

sb.AppendLine();

sb.Append("Latitude=");

sb.AppendLine(location.Latitude.ToString());

sb.Append("Longitude=");

sb.AppendLine(location.Longitude.ToString());

sb.Append("Heading=");

sb.AppendLine(location.Heading.ToString());

label2.Invoke((UpdateLocationInfo)delegate()

{

label2.Text=sb.ToString();

});

}

GPSID与电池

在上面的第二段代码示例中,位置信息仅仅是更新并提供给用户。

在某些情况下,合理的做法是添加代码使应用程序工作于前台时更新位置信息(例如在地图中显示位置信息的更新),而在应用程序转到后台时停止位置信息的持续更新。

限制工作于后台的应用程序的运行以节省电池电量。

在这样的情况下你甚至可以通过在应用程序转到后台时关闭GPSID连接,而在程序转到前台时重新打开的方式来节省更多的电量。

下面的代码演示了如何优化应用程序以维持电池的寿命。

应用程序通过对MainForm对象引发的Activated事件作出反应,从而在每次应用程序转到前台时注册LocationChanged事件。

通过对MainForm对象引发的Deactivate事件作出反应,在每次应用转到后台时解除LocationChanged事件的绑定。

下面的代码示范了如何在应用程序转到后台时节省电池电量。

privatevoidMainForm_Activated(objectsender,EventArgse)

{

if(menuLocationUpdates.Checked)

{

gps.LocationChanged+=new

LocationChangedEventHandler(gps_LocationChanged);

}

}

privatevoidMainForm_Deactivate(objectsender,EventArgse)

{

if(menuLocationUpdates.Checked)

{

gps.LocationChanged-=gps_LocationChanged;

}

}

尽管你可以通过GPSID轻易得取得你的当前位置,并且卫星返回的位置非常精确,然而使用GPSID却未必是获取位置信息最高效的方法。

从开始到第一个位置信息被返回给设备可能花费很长时间。

依赖于物理硬件设备,你的当前位置,卫星的可见性,以及最后一次通过GPSID的位置读取,取得位置信息可能会花费几分钟的时间。

如果你不需要达到GPS传输的精确度,但同事又需要更快的定位速度,可以考虑以下的选择。

通过蜂窝基站检索位置信息

大部分的WindowsMobile设备当然都是手机。

依赖于你所使用的移动运营商,你的手机可以以编程方式取得蜂窝基站的信息。

信息中包含一个蜂窝基站代码、一个地区代码和一个国家代码。

根据这些信息,你可以取得你的手机当前连接的蜂窝基站的位置,从而为你提供不同精确度的位置信息。

通过蜂窝基站检索位置的优势在于可以不使用额外电量而快速得取得你的当前位置。

其缺点是假如你不使用蜂窝基站三角测量法的话,精确度是不确定的。

另一个缺点是你必须创建额外的代码来获取位置。

蜂窝基站信息的获取可以通过WindowsMobile设备中的无线接口层(RIL)来实现。

然而,仅仅有蜂窝基站代码、国家代码及移动运营商的信息是不够的。

所有这些信息都必须最终转化为位置。

你可以把取得的蜂窝基站信息传递给第三方Web服务。

在WindowsMobile设备中访问蜂窝基站信息

为了在你的应用程序中取得蜂窝基站信息,你必须要访问设备的无线接口层(RIL)。

OEMRIL的推荐设置禁止不受信任的应用程序访问RIL功能。

因此,你必须用一个有效的证书为你的应用程序签名,或者在你的应用程序内部限制对TIL功能的访问。

为了取得为蜂窝基站信息,你主要要调用一个独立的RIL函数。

但是,你必须调用其他的函数作为RIL的处理程序,并且必须在结束使用RIL功能时清楚这些处理程序。

你可能对通过访问WindowsMobile的底层功能取回蜂窝基站信息还不是很熟悉。

但是这不是什么大问题,因为无线接口层被实现为划分成两个独立层次的驱动程序和一个从应用程序内部访问信息的代理。

MDD(模型设备驱动)层是独立于无线通讯堆栈的。

它包含了与RIL代理通信的代码,和RIL驱动中所有无线通讯功能的实现。

发布在MDD层中的代码是使用安全、文档良好的,并且为你提供了对所有种类无线通讯功能的高层访问。

另一方面,RIL的底层,PDD(平台依赖驱动)层是依赖于无线通信层的。

每个OEM对它的实现都是不同的。

RIL公开了几个以“RIL_”为前缀的API.这些API都是用本地代码编写的,因此想要在托管程序中访问必须使用P/Invoke。

你必须使用以下的API来获取蜂窝基站信息:

∙RIL_Initialize.初始化无线接口层以提供应用程序使用。

∙RIL_Deinitialize.在应用程序结束使用RIL时正确地关闭并清除资源。

∙RIL_GetCellTowerInfo.获取WidowsMobile设备所使用的蜂窝基站信息。

正如你在下面的代码示例中看到的一样,从托管代码中访问这些API是相当简单的。

以下代码展示用以访问RIL的P/Invoke的声明。

publicdelegatevoidRILRESULTCALLBACK(uintdwCode,

IntPtrhrCmdID,IntPtrlpData,uintcbData,uintdwParam);

publicdelegatevoidRILNOTIFYCALLBACK(uintdwCode,

IntPtrlpData,uintcbData,uintdwParam);

[DllImport("ril.dll")]

publicstaticexternIntPtrRIL_Initialize(uintdwIndex,

RILRESULTCALLBACKpfnResult,

RILNOTIFYCALLBACKpfnNotify,

uintdwNotificationClasses,

uintdwParam,

outIntPtrlphRil);

[DllImport("ril.dll",EntryPoint="RIL_GetCellTowerInfo")]

publicstaticexternIntPtrRIL_GetCellTowerInfo(IntPtrhRil);

[DllImport("ril.dll")]

publicstaticexternIntPtrRIL_Deinitialize(IntPtrhRil);

使用RIL_Initialize,你既可以通过回调函数pfnResult返回结果,也可以通过回调函数pfnNotify来异步返回应用程序通过dwNotificationClasses注册的所有状态的状态改变。

这个白皮书的示例代码只使用了同步操作。

每次当应用程序调用RIL_GetCellTowerInfo时,这个API的执行结果就马上返回。

然而,实际的数据却是通过传递给RIL_Initialize的回调函数pfnResult返回的。

回调函数返回一个结构体,这个结构体必须先经过整理然后才能在托管代码中使用。

下面的代码展示了在调用RIL_GetCellTowerInfo之后由RIL返回的结构体。

[StructLayout(LayoutKind.Explicit)]

internalclassRILCELLTOWERINFO

{

[FieldOffset(0)]

uintdwSize;

[FieldOffset(4)]

uintdwParams;

[FieldOffset(8)]

publicuintdwMobileCountryCode;

[FieldOffset(12)]

publicuintdwMobileNetworkCode;

[FieldOffset(16)]

publicuintdwLocationAreaCode;

[FieldOffset(20)]

publicuintdwCellID;

}

在这段代码中,你将看到如何取得最重要的结构体成员以传递给一个可以返回蜂窝基站位置的Web服务。

在RILCELLTOWERINFO结构体中还有一些更有趣的字段,譬如,你所连接的基站的信号强度。

通过这个结构体的其他成员,你可以自己计算出一个更为精确的当前位置。

然而为了简单起见,我们只关注你所连接的蜂窝基站和它的位置。

现在在托管代码中,你可以取得你所连接的基站的信息并存储到一个类中了。

如下的代码示范了托管类如何存储蜂窝基站信息。

publicclassCellTower

{

publicintCellId{get;set;}

publicintLAC{get;set;}

publicintMCC{get;set;}

publicintMNC{get;set;}

}

你可以使用下面的示例代码来调用必须的RILAPIs。

有趣的部分是蜂窝基站信息被返回给RIL_GetCellTowerInfo调用者的方式。

信息不是至极返回的,而是通过一个回调函数返回的。

因为位置感知的应用程序在WindowsMobile获知自己的位置之前无法做任何有用的工作,所以RIL_GetCellTowerInfo的异步行为通过基站信息可用时设置的一个托管事件转变成了同步行为。

如下的代码示范了在托管代码中如何获取基站信息。

publicclassCellTowerInfo

{

privatestaticAutoResetEventdataReceived=newAutoResetEvent(false);

privatestaticRIL.RILCELLTOWERINFOtowerInfo;

publicstaticCellTowerGetCellTowerInfo()

{

IntPtrhRIL=IntPtr.Zero;

IntPtrhResult=IntPtr.Zero;

hResult=RIL.RIL_Initialize(1,

newRIL.RILRESULTCALLBACK(CellTowerData),

null,0,0,outhRIL);

if(hResult!

=IntPtr.Zero)

returnnull;

hResult=RIL.RIL_GetCellTowerInfo(hRIL);

dataReceived.WaitOne();

RIL.RIL_Deinitialize(hRIL);

CellTowerct=newCellTower();

ct.LAC=(int)towerInfo.dwLocationAreaCode;

ct.MCC=(int)towerInfo.dwMobileCountryCode;

ct.MNC=(int)towerInfo.dwMobileNetworkC

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 初中教育 > 语文

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1