欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Windows Phone笔记(5)加速计和位置服务

程序员文章站 2023-08-23 11:24:43
这篇笔记主要是讲述如windows phone中两个提供外界信息的设备以及如何在程序中适用它们,在用户授权允许的情况下,加速计能够获取当前手机设备的具体方向;而位置服务则可以对手机当前所在地的位置进...

这篇笔记主要是讲述如windows phone中两个提供外界信息的设备以及如何在程序中适用它们,在用户授权允许的情况下,加速计能够获取当前手机设备的具体方向;而位置服务则可以对手机当前所在地的位置进行定位。
1.传感器之加速计
  加速计时windows phone手机中的一个硬件设备,加速计测量在某一时刻施加于设备的力。可以使用这些力来确定用户正在向哪个方向移动设备。加速度值采用 3 维矢量表示,该矢量表示在 x、y 和 z 轴中的加速度分量(采用重力单位)。当设备面朝平台时,加速度的方向相对于设备以便对 z 轴应用 -1g,当垂直于平台顶部放置设备时,对 y 轴应用 -1g。从加速计的这些特性我们可以知道,windows phone中的程序中处理方向改变的基础。加速度也会对突然的移动做出响应,比如摇晃(微信中的摇一摇功能)等等。对于加速计的使用,创意是对开发人员最大的挑战。
  程序使用加速计需要引用microsoft.devices.sensors库,并且在properties文件夹中的wmappmanifest.xml文件中设置(这是默认设置):
<capability name="id_cap_sensors"/>

下面让我们通过观察一个示例程序,该程序获取加速计测量的数据,并使用line元素和textblock元素展示出来:
 这是mainpage.xaml页面的代码:
 1   <!--contentpanel - 在此处放置其他内容-->
 2         <grid x:name="contentpanel" grid.row="1" margin="12,0,12,0">
 3             <stackpanel orientation="vertical">
 4                 <stackpanel orientation="horizontal">
 5                     <textblock text="状态:" margin="10 0"/>
 6                     <textblock name="txtblkaccelerometerstate"  text="停止采集数据"/>
 7                 </stackpanel>
 8                 <stackpanel orientation="horizontal">
 9                     <textblock text="更新加度计数据时间:" margin="10 0"/>
10                     <textblock name="txtblkupdatedataaccelerometer"  text="20ms"/>
11                 </stackpanel>
12                 <grid>
13                     <textblock height="45" horizontalalignment="left"  name="txtblkx" text="x:1.0" verticalalignment="top" foreground="red" fontweight="bold" fontsize="28" margin="10 0" />
14                     <textblock height="45" horizontalalignment="center"  name="txtblky" text="y:1.0" verticalalignment="top"  foreground="green" fontweight="bold" fontsize="28" />
15                     <textblock height="45" horizontalalignment="right"  name="txtblkz" text="z:1.0" verticalalignment="top"   foreground="blue" fontweight="bold" fontsize="28" margin="10 0" />
16                 </grid>
17                 <grid height="300">
18                     <line x:name="xline" x1="240" y1="150" x2="340" y2="150" stroke="red" strokethickness="4"></line>
19                     <line x:name="yline" x1="240" y1="150" x2="240" y2="60" stroke="green" strokethickness="4"></line>
20                     <line x:name="zline" x1="240" y1="150" x2="190" y2="200" stroke="blue" strokethickness="4"></line>
21                 </grid>
22                 <button content="开始采集" margin="0 100" name="btnswitch" click="btnswitch_click"></button>
23             </stackpanel>
24         </grid>

这是mainpage.xaml.cs后台处理程序:
 public partial class mainpage : phoneapplicationpage
    {
        accelerometer accelerometer;
        dispatchertimer timer;
        vector3 acceleration;
        bool isdatavalid;
        // 构造函数
        public mainpage()
        {
            initializecomponent();

            if (!accelerometer.issupported)
            {
                txtblkaccelerometerstate.text = "设备不支持加速计";
            }
            else
            {
                //初始化timer,并绑定tick事件
                timer = new dispatchertimer();
                timer.interval = timespan.frommilliseconds(30);
                timer.tick += new eventhandler(timer_tick);
            }
        }

        /// <summary>
        /// 开始和停止采集加速计数据
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnswitch_click(object sender, routedeventargs e)
        {
            if (accelerometer != null && accelerometer.isdatavalid)
            {
                //停止采集加速计数据
                accelerometer.stop();
                timer.stop();
                txtblkaccelerometerstate.text = "停止加速度度计";
                btnswitch.content = "开始采集数据";
            }
            else
            {
                if (accelerometer == null)
                {
                    //实例化一个accelerometer对象
                    accelerometer = new accelerometer();

                    //20毫秒更新一次数据
                    accelerometer.timebetweenupdates = timespan.frommilliseconds(20);

                    //更新传感器数据的时间
                    txtblkupdatedataaccelerometer.text = accelerometer.timebetweenupdates.totalmilliseconds + " ms";
                    //从传感器获得新数据时发生
                    accelerometer.currentvaluechanged += new eventhandler<sensorreadingeventargs<accelerometerreading>>(accelerometer_currentvaluechanged);
                }

                try
                {
                    txtblkaccelerometerstate.text = "开始采集数据";
                    btnswitch.content = "停止采集数据";
                    accelerometer.start();
                    timer.start();
                }
                catch (invalidoperationexception)
                {
                    txtblkaccelerometerstate.text = "无法启动加速计.";
                }
            }
        }

        void accelerometer_currentvaluechanged(object sender, sensorreadingeventargs<accelerometerreading> e)
        {
            //这个事件处理程序是被主执行线程(ui)之外的线程调用的
            //不能直接访问页面上的元素,因为它们位于ui线程中
            isdatavalid = accelerometer.isdatavalid;
            acceleration = e.sensorreading.acceleration;
        }

        void timer_tick(object sender, eventargs e)
        {
            if (isdatavalid)
            {
                txtblkaccelerometerstate.text = "正在从加速计获取数据";

                // 显示加速计的数值
                txtblkx.text = "x: " + acceleration.x.tostring("0.00");
                txtblky.text = "y: " + acceleration.y.tostring("0.00");
                txtblkz.text = "z: " + acceleration.z.tostring("0.00");

                // 使用line元素显示加速计返回的值
                xline.x2 = xline.x1 + acceleration.x * 100;
                yline.y2 = yline.y1 - acceleration.y * 100;
                zline.x2 = zline.x1 - acceleration.z * 50;
                zline.y2 = zline.y1 + acceleration.z * 50;
            }
        }

    }

编译运行上面的程序:
  这是运行程序后的效果(没有开始采集数据)    点击开始采集数据后,y等于-1g,表示手机(模拟器)是纵向竖立的

    Windows Phone笔记(5)加速计和位置服务 Windows Phone笔记(5)加速计和位置服务

 

但这样看好像并不能直观的了解加速计的作用,我们可以通过使用该模拟器的加速计模拟器工具来测试应用程序。

  Windows Phone笔记(5)加速计和位置服务

点击模拟器的加速计工具的“播放按钮”或者是拖动加速计工作中手机上的桔红色圆点,模拟手机的各个移动状态。我们可看到页面的3个分别代表着x/y/z的三个line元素随着加速计的数据变化而不断变化。

  Windows Phone笔记(5)加速计和位置服务

2.位置服务(location service)
  windows phone应用程序可以通过一种被称为a-gps(assisted-gps,辅助gps)的技术获取手机当前所在的地理位置。对手机进行定位所实用的核心类是:geocoordinatewatcher。使用时需要引用system.device.dll程序集,并引用system.device.location命名空间。wmappmanifest.xml做如下标记(默认包含):
<capability name="id_cap_loction"/>
geocoordinatewatcher的构造方法可以接收一个getpositionaccuracy枚举类型的参数,该枚举的成员有:
• default(默认精度)
• high(高精度)
geocoordinatewatcher对象需要注册一个名为:positionchanged事件,检测到位置更改时发生。postitionchanged事件会传递一个geocoordinate对象,该对象有八个属性,分别是:
• latitude(纬度),double类型,-90至90之间。
• longitude(经度),double类型,-180到180之间
• altitude(高度),double类型
• horizontalaccuracy(水平精度)和verticalaccuracy(竖直精度),double类型
• course(航向),double类型,0至360之间
• speed(速度),double类型
• isunknown,boolean类型,当latitude(纬度)和longitude(经度)为非数字时,则为ture
geocoordinate类有一个方法getdistanceto,用于计算两个geocoordinate对象的距离。
北纬为正值,南纬为负值;东经为正值,西经为负值。如果应用程序没有获取用户位置的授权,latitude(纬度)和longitude(经度)的值为double.nan。
   
现在我们通过一个示例来学习如何使用windows phone中的位置服务。
mainpage.xaml
 1     <!--contentpanel - 在此处放置其他内容-->
 2         <grid x:name="contentpanel" grid.row="1" margin="12,0,12,0">
 3             <stackpanel >
 4                 <stackpanel orientation="horizontal">
 5                     <textblock height="30" name="textblock1" text="状态:" margin="10 0" />
 6                     <textblock height="30" name="txtblklocationstate" text="位置服务当前不可用" />
 7                 </stackpanel>
 8                 <stackpanel>
 9                     <grid height="500">
10                         <textblock text="经度:" fontsize="28" foreground="red" horizontalalignment="left" verticalalignment="top"/>
11                         <textblock text="0.000" fontsize="28" foreground="red" horizontalalignment="center" verticalalignment="top" name="txtblklatitude" margin="0 0 200 0" />
12                         <textblock text="纬度:" fontsize="28" foreground="red" horizontalalignment="left" verticalalignment="center" />
13                         <textblock text="0.000" fontsize="28" foreground="red" horizontalalignment="center" verticalalignment="center" name="txtblklongitude" margin="0 0 200 0"/>
14                     </grid>
15                 </stackpanel>
16                 <grid>
17                     <button content="开始定位" height="72" name="btnstartlocation" width="160" horizontalalignment="left" verticalalignment="bottom" margin="50 0" click="btnstartlocation_click" />
18                     <button content="停止定位" height="72" name="btnstoplocation" width="160" horizontalalignment="right" verticalalignment="bottom" margin="50 0" click="btnstoplocation_click" />
19                 </grid>
20             </stackpanel>
21         </grid>

这里是mainpage.xaml.cs后台处理程序:
 1 public partial class mainpage : phoneapplicationpage
 2     {
 3         geocoordinatewatcher watcher;
 4         // 构造函数
 5         public mainpage()
 6         {
 7             initializecomponent();
 8         }
 9
10         /// <summary>
11      /// 开始定位
12      /// </summary>
13      /// <param name="sender"></param>
14      /// <param name="e"></param>
15         private void btnstartlocation_click(object sender, routedeventargs e)
16         {
17             if (watcher == null)
18             {
19                 watcher = new geocoordinatewatcher(geopositionaccuracy.high); // 采用高精度
20                 watcher.movementthreshold = 20; // positionchanged事件之间传送的最小距离
21
22                 watcher.statuschanged += new eventhandler<geopositionstatuschangedeventargs>(watcher_statuschanged);
23                 watcher.positionchanged += new eventhandler<geopositionchangedeventargs<geocoordinate>>(watcher_positionchanged);
24
25                 watcher.start();//开始使用位置服务
26             }
27             else//方便测试,实际使用需要注意
28             {
29                 watcher.start();//开始使用位置服务
30             }
31         }
32
33         //检测到位置更改时
34 //当定位服务已准备就绪并接收数据时,它将开始引发 positionchanged 事件
35         void watcher_positionchanged(object sender, geopositionchangedeventargs<geocoordinate> e)
36         {
37             this.txtblklatitude.text = e.position.location.latitude.tostring("0.000");
38             this.txtblklongitude.text = e.position.location.longitude.tostring("0.000");
39         }
40
41         //当位置服务状态发生变化时
42      //在 geopositionstatuschangedeventargs 对象中传递的 geopositionstatus 枚举获取该服务的当前状态。
43      //可以使用它在应用程序中启用基于位置的功能,以及将服务的当前状态通知给用户。
44         void watcher_statuschanged(object sender, geopositionstatuschangedeventargs e)
45         {
46             switch (e.status)
47             {
48                 //如果服务的状态为 disabled,则可以检查 permission 属性,看用户是否禁用了应用程序的定位服务功能。
49                 case geopositionstatus.disabled:
50                     if (watcher.permission == geopositionpermission.denied)
51                     {
52                         //用户禁用了定位服务
53                         this.txtblklocationstate.text = "对位置服务的访问被拒绝。";
54                     }
55                     else
56                     {
57                         this.txtblklocationstate.text = "设备的定位服务不能够正常使用。";
58                     }
59                     break;
60                 case geopositionstatus.initializing:
61                     // 位置服务正在尝试获取数据
62                     this.btnstartlocation.isenabled = false;
63                     break;
64                 case geopositionstatus.nodata:
65                     this.txtblklocationstate.text = "当前位置无法进行定位";
66                     this.btnstoplocation.isenabled = true;
67                     break;
68                 case geopositionstatus.ready:
69                     this.txtblklocationstate.text = "位置服务已启用,并准备就绪";
70                     this.btnstoplocation.isenabled = true;
71                     break;
72             }
73         }
74
75         /// <summary>
76      /// 停止定位
77      /// </summary>
78      /// <param name="sender"></param>
79      /// <param name="e"></param>
80         private void btnstoplocation_click(object sender, routedeventargs e)
81         {
82             watcher.stop();
83             this.btnstartlocation.isenabled = true;
84             this.txtblklocationstate.text = "位置服务已经停止";
85         }
86     }

编译运行程序后,通过模拟器可以模拟当前位置,通过使用模拟器中模拟位置工具变化当前设备所在坐标,我们可以看到程序上的数字也随之不断变化:

  Windows Phone笔记(5)加速计和位置服务




摘自  晴天猪の博客