当前位置:  编程技术>移动开发
本页文章导读:
    ▪(转)geohash:用字符串兑现附近地点搜索        (转)geohash:用字符串实现附近地点搜索 052011 / 07 geohash:用字符串实现附近地点搜索 上回说到了用经纬度范围实现附近地点搜索。一些小型应用中这样做没问题,但在大型应用中它有.........
    ▪ AppCan VS PhoneGap - 对照两大移动开发平台        AppCan VS PhoneGap - 对比两大移动开发平台  http://my.oschina.net/liux/blog/65119       要说hybrid app 框架的典范,Phonegap和AppCan无疑是最受大家关注的。先说明,本人是App的开发者,对手机上的web app也.........
    ▪ 黑马软件工程师_关于纠结接口Comparator的实现方法compare(Object o1,Object o2)       黑马程序员_关于纠结接口Comparator的实现方法compare(Object o1,Object o2)                                          ------- android培训、java培训、期待与您交流! ----------   今天在黑马论坛游.........

[1](转)geohash:用字符串兑现附近地点搜索
    来源: 互联网  发布时间: 2014-02-18
(转)geohash:用字符串实现附近地点搜索

052011 / 07

geohash:用字符串实现附近地点搜索

上回说到了用经纬度范围实现附近地点搜索。一些小型应用中这样做没问题,但在大型应用中它有个显著的缺点:速度慢。慢的原因有两个,第一是范围比较的索引利用率并不高,第二是SQL语句极其不稳定(不同的当前位置会产生完全不同的SQL查询),很难缓存。

可以考虑使用geohash算法。

geohash是一种地址编码,它能把二维的经纬度编码成一维的字符串。比如,北海公园的编码是wx4g0ec1。

geohash有以下几个特点:

首先,geohash用一个字符串表示经度和纬度两个坐标。某些情况下无法在两列上同时应用索引(例如MySQL 4之前的版本,Google App Engine的数据层等),利用geohash,只需在一列上应用索引即可。

其次,geohash表示的并不是一个点,而是一个矩形区域。比如编码wx4g0ec19,它表示的是一个矩形区域。使用者可以发布地址编码,既能表明自己位于北海公园附近,又不至于暴露自己的精确坐标,有助于隐私保护。

第三,编码的前缀可以表示更大的区域。例如wx4g0ec1,它的前缀wx4g0e表示包含编码wx4g0ec1在内的更大范围。这个特性可以用于附近地点搜索。首先根据用户当前坐标计算geohash(例如wx4g0ec1)然后取其前缀进行查询(SELECT * FROM place WHERE geohash LIKE 'wx4g0e%'),即可查询附近的所有地点。

 

geohash的算法

下面以(39.92324, 116.3906)为例,介绍一下geohash的编码算法。首先将纬度范围(-90, 90)平分成两个区间(-90, 0)、(0, 90),如果目标纬度位于前一个区间,则编码为0,否则编码为1。由于39.92324属于(0, 90),所以取编码为1。然后再将(0, 90)分成 (0, 45), (45, 90)两个区间,而39.92324位于(0, 45),所以编码为0。以此类推,直到精度符合要求为止,得到纬度编码为1011 1000 1100 0111 1001。

纬度范围 划分区间0 划分区间1 39.92324所属区间 (-90, 90) (-90, 0.0) (0.0, 90) 1 (0.0, 90) (0.0, 45.0) (45.0, 90) 0 (0.0, 45.0) (0.0, 22.5) (22.5, 45.0) 1 (22.5, 45.0) (22.5, 33.75) (33.75, 45.0) 1 (33.75, 45.0) (33.75, 39.375) (39.375, 45.0) 1 (39.375, 45.0) (39.375, 42.1875) (42.1875, 45.0) 0 (39.375, 42.1875) (39.375, 40.7812) (40.7812, 42.1875) 0 (39.375, 40.7812) (39.375, 40.0781) (40.0781, 40.7812) 0 (39.375, 40.0781) (39.375, 39.7265) (39.7265, 40.0781) 1 (39.7265, 40.0781) (39.7265, 39.9023) (39.9023, 40.0781) 1 (39.9023, 40.0781) (39.9023, 39.9902) (39.9902, 40.0781) 0 (39.9023, 39.9902) (39.9023, 39.9462) (39.9462, 39.9902) 0 (39.9023, 39.9462) (39.9023, 39.9243) (39.9243, 39.9462) 0 (39.9023, 39.9243) (39.9023, 39.9133) (39.9133, 39.9243) 1 (39.9133, 39.9243) (39.9133, 39.9188) (39.9188, 39.9243) 1 (39.9188, 39.9243) (39.9188, 39.9215) (39.9215, 39.9243) 1

经度也用同样的算法,对(-180, 180)依次细分,得到116.3906的编码为1101 0010 1100 0100 0100。

经度范围 划分区间0 划分区间1 116.3906所属区间 (-180, 180) (-180, 0.0) (0.0, 180) 1 (0.0, 180) (0.0, 90.0) (90.0, 180) 1 (90.0, 180) (90.0, 135.0) (135.0, 180) 0 (90.0, 135.0) (90.0, 112.5) (112.5, 135.0) 1 (112.5, 135.0) (112.5, 123.75) (123.75, 135.0) 0 (112.5, 123.75) (112.5, 118.125) (118.125, 123.75) 0 (112.5, 118.125) (112.5, 115.312) (115.312, 118.125) 1 (115.312, 118.125) (115.312, 116.718) (116.718, 118.125) 0 (115.312, 116.718) (115.312, 116.015) (116.015, 116.718) 1 (116.015, 116.718) (116.015, 116.367) (116.367, 116.718) 1 (116.367, 116.718) (116.367, 116.542) (116.542, 116.718) 0 (116.367, 116.542) (116.367, 116.455) (116.455, 116.542) 0 (116.367, 116.455) (116.367, 116.411) (116.411, 116.455) 0 (116.367, 116.411) (116.367, 116.389) (116.389, 116.411) 1 (116.389, 116.411) (116.389, 116.400) (116.400, 116.411) 0 (116.389, 116.400) (116.389, 116.394) (116.394, 116.400) 0

接下来将经度和纬度的编码合并,奇数位是纬度,偶数位是经度,得到编码 11100 11101 00100 01111 00000 01101 01011 00001。

最后,用0-9、b-z(去掉a, i, l, o)这32个字母进行base32编码,得到(39.92324, 116.3906)的编码为wx4g0ec1。

十进制 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 base32 0 1 2 3 4 5 6 7 8 9 b c d e f g 十进制 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 base32 h j k m n p q r s t u v w x y z

解码算法与编码算法相反,先进行base32解码,然后分离出经纬度,最后根据二进制编码对经纬度范围进行细分即可,这里不再赘述。不过由于geohash表示的是区间,编码越长越精确,但不可能解码出完全一致的地址。

geohash的应用:附近地址搜索

geohash的最大用途就是附近地址搜索了。不过,从geohash的编码算法中可以看出它的一个缺点:位于格子边界两侧的两点,虽然十分接近,但编码会完全不同。实际应用中,可以同时搜索当前格子周围的8个格子,即可解决这个问题。

以geohash的python库为例,相关的geohash操作如下:

>>> import geohash
>>> geohash.encode(39.92324, 116.3906, 5)  # 编码,5表示编码长度
'wx4g0'
>>> geohash.expand('wx4g0')                # 求wx4g0格子及周围8个格子的编码
['wx4ep', 'wx4g1', 'wx4er', 'wx4g2', 'wx4g3', 'wx4dz', 'wx4fb', 'wx4fc', 'wx4g0']

最后,我们来看看本文开头提出的两个问题:速度慢,缓存命中率低。使用geohash查询附近地点,用的是字符串前缀匹配:

SELECT * FROM place WHERE geohash LIKE 'wx4g0%';

而前缀匹配可以利用geohash列上的索引,因此查询速度不会太慢。另外,即使用户坐标发生微小的变化,也能编码成相同的geohash,这就保证了每次执行相同的SQL语句,使得缓存命中率大大提高。

相关资源
  • python-geohash
  • geohash演示

    
[2] AppCan VS PhoneGap - 对照两大移动开发平台
    来源: 互联网  发布时间: 2014-02-18
AppCan VS PhoneGap - 对比两大移动开发平台

 http://my.oschina.net/liux/blog/65119

 

    要说hybrid app 框架的典范,Phonegap和AppCan无疑是最受大家关注的。先说明,本人是App的开发者,对手机上的web app也研究一段时间。本文以技术角度去阐述一个事实:为什么AppCan比Phonegap开发出来的应用会比较好。 

    其实要从技术上来讲的话,phonegap只是提供本地API,以及一个打包器,大部分的UI、UE的都是交由phonegap推荐的jquerymobile,sencha touch等js+css框架来实现。而为何phonegap比较受大家关注呢,一方面是它出来比较早,推广时间较长;另一方面它是开源的,很多android native开发者都对其进行了插件扩展,能够满足一些开发需求。然而,经过对手机版(ios,android)webkit研究过一段时间后,一个不争的事实是手机版webkit有诸多问题,特别是在android碎片化的情况下,不同版本,不同手机对某一个css属性表现的就不一样。这对于一个要做跨平台开发的框架来说,是不能接受的,也达不到跨平台的初衷。下面我利用appcan+AppCan UI2.0开发一个简单的app,同时也利用phonegap+jquerymobile去开发同样的一个app。 

首先我们先看一下AppCan应用与PhoneGap应用视频对比: 
http://v.youku.com/v_show/id_XNDIzODg2MjY0.html 
 

下面是开发介绍: 

AppCan开发 

    首先,关于UI,AppCan的UI,即css文件,按照控件的类型(按钮、列表等)拆分的比较细,这样,如果一个应用中用不到的控件,开发者可以把这些css文件删除掉。利用AppCan 的开发环境,创建一个工程,并创建几个页面。其整个工程截图如下: 
 

这个demo要做的是三个UI,第一个就两个按钮,第二个是展示内容用的,内容有3w多字。第三个ui是一个网络跨域获取数据的例子。 
第一个ui,由于是只有两个按钮,只用一个index.html,利用AppCan IDE选择按钮控件,生成代码并利用AppCan IDE中自带的模拟器查看效果: 

01 <!--块容器开始-->
02 <div>  
03     <div >
04         <!--按钮开始-->
05         <div ontouchstart="zy_touch('btn-act',getpageone)">加载page "two"</div>
06         <!--按钮结束-->
07     </div>
08     <div >
09         <!--按钮开始-->
10         <div ontouchstart="zy_touch('btn-act',getpagetwo)" >加载page "three"</div>
11         <!--按钮结束-->
12     </div>  
13 </div>
14 <!--块容器结束-->

 

 

第二个UI:即内容展示页,展示的内容有3W多字,由于内容区域需要用到滚动条,因此可以用到浮动窗口。即two.html是展示头部,内容区域,底部,其中内容区域只是一个div,并没有内容。而index_content.html是显示内容用的,放到一个浮动窗口中去加载,并且此浮动窗口盖到two.html那个窗口中,大小正好和内容区域div一样。这里为什么说在有滚动条的情况下,要用浮动窗口替代呢。因为css的position:fixed在android2.2版本,ios5中才开始支持,并且ios5中还会存在问题,因此如果一个页面布局想要头部,底部固定,中间区域带滚动条的,将会出现问题。AppCan可以很好的借助native的方式解决了此问题。 

 

第三个UI:是为了测试下jquery的$.getJSON跨域异步请求方法,以及AppCan的uexXmlHttpMgr这个方法的响应速度,经过测试,两种方式相差无几。需要提的是uexXmlHttpMgr还有比较强大的功能,不在本文讨论范围之内。 

AppCan打包 

上述三个UI做好之后,直接用AppCan IDE中打包即可: 

 


JqueryMobile开发 

根据jquerymobile官网上例子,搭建上述三个UI的类似代码(文字内容部分删掉了): 

01 <!DOCTYPE html>
02 <html>
03  
04 <head>
05     <meta charset="utf-8">
06     <meta name="viewport" content="width=device-width, initial-scale=1">
07     <title>Multi-page template</title>
08     <link rel="stylesheet" href="/blog_article/css/jquery.mobile-1.0.1.min.css" />
09 <script src="/blog_article/js/jquery.js"></script>
10 <script src="/blog_article/js/jquery.mobile-1.0.1.min.js"></script>
11 </head>
12  
13     
14 <body>
15  
16 <!-- Start of first page: #one -->
17 <div data-role="page" id="one" >
18  
19     <div data-role="header">
20         <h1>Multi-page</h1>
21     </div><!-- /header -->
22  
23     <div data-role="content">  
24         <h2>Page One</h2>
25         <p><a href="#two" data-role="button"data-transition="slide">加载page "two"</a></p>  
26         <p><a href="#three" data-role="button"data-transition="slide">加载page "three"</a></p>  
27     </div><!-- /content -->
28     
29     <div data-role="footer" data-theme="d" data-position="fixed">
30         <h4>Page Footer</h4>
31     </div><!-- /footer -->
32 </div><!-- /page one -->
33  
34  
35 <!-- Start of second page: #two -->
36 <div data-role="page" id="two" data-theme="a">
37  
38     <div data-role="header" data-position="fixed">
39         <h1>Two</h1>
40         <a href="#one" data-icon="home" data-iconpos="notext" data-direction="reverse">Home</a>
41     </div><!-- /header -->
42  
43     <div data-role="content"data-theme="a">  
44         <h2>Hybrid app</h2>
45 </div><!-- /content -->
46     
47     <div data-role="footer" data-position="fixed">
48         <h4>Page Footer</h4>
49     </div><!-- /footer -->
50 </div><!-- /page two -->
51  
52 <!-- Start of three page: #three -->
53 <div data-role="page" id="three" data-theme="a">
54  
55     <div data-role="header" data-position="fixed">
56         <h1>three</h1>
57         <a href="#one" data-icon="home" data-iconpos="notext" data-direction="reverse">Home</a>
58     </div><!-- /header -->
59  
60     <div data-role="content"data-theme="a">  
61         <h2>异步加载网络数据</h2>
62         <a href="javascript:void(0)" onclick="getdata()" data-role="button"data-mini="true">Ajax get Data</a>
63         <ul data-role="listview" data-inset="true" data-theme="b" data-dividertheme="f">
64                 <li data-role="list-divider">时间</li>
65                 <li id="bt">请求开始时间:</li>
66                 <li id="et">请求结束时间:</li>
67             </ul>
68         <ul data-role="listview" data-inset="true" data-theme="c" data-dividertheme="f">
69                 <li data-role="list-divider" id="title"></li>
70                 <div id="content"></div>
71             </ul>
72     </div><!-- /content -->
73     <script>
74         function getdata(){
75             var d = new Date().getTime();
76             document.getElementById("bt").innerHTML = "请求开始时间:"+d;
77             $.getJSON("http://te.3g2win.com/case/?jsoncallback=?",function(data){
78                 var e = new Date().getTime();
79                 document.getElementById("et").innerHTML = "请求结束时间:"+e;
80                 document.getElementById("title").innerHTML = data.title;
81                 document.getElementById("content").innerHTML = data.content;
82             });
83         }
84     </script>
85     <div data-role="footer" data-position="fixed">
86         <h4>Page Footer</h4>
87     </div><!-- /footer -->
88 </div><!-- /page three -->
89  
90 </body>
91 </html>


  


phonegap打成安装包 

把写好的网页包放到android原生开发环境下,通过android原生环境生成安装包的方式生成: 
 

 

对比

通过这个小demo,我们总结下phonegap和appcan的异同点。


相同点: 

  • 都是用html+css+js技术区实现此demo的ui,ue部分
  • 都能生成安装包


不同点: 

  • phonegap负责打包(此demo没有用到本地API),jquerymobile负责页面UI、UE;AppCan两者都提供,且打包无需native开发环境。
  • jquerymobile方案中,所有的page都在一个html页面中。AppCan方案中,不同的page可以放到不同的html中,甚至更灵活的,同一个page中的内容区域可以用单独的html来展示。
  • 生成安装包大小,phonegap比较小,appcan比较大。这是因为appcan带了android,ios的启动图片。以及里面一些native插件需要的一些图片资源。


附件给出两个安装包以及两个网页包的代码: 
 点击此处 


    
[3] 黑马软件工程师_关于纠结接口Comparator的实现方法compare(Object o1,Object o2)
    来源: 互联网  发布时间: 2014-02-18
黑马程序员_关于纠结接口Comparator的实现方法compare(Object o1,Object o2)

                                         ------- android培训、java培训、期待与您交流! ----------

 

今天在黑马论坛游街着一位同学的问题让我纠结了好久好久。

 

说起来想法也非常简单,看下面代码,

package com.itheima;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.TreeSet;
class test 
{
        public static void main(String[] args) 
        {
                
                TreeSet ts = new TreeSet(new Demo2013());
                ts.add("f8");
                ts.add("25d55");
                ts.add("1d1");
                ts.add("8d56");
                ts.add("25555");
                ts.add("8d56");
            
                System.out.println(ts);

        }
}

class Demo2013 implements Comparator 
{
        public int compare(Object o1,Object o2)
        {
                String s1 =(String)o1;
                String s2 =(String)o2;
            


                System.out.println(s1+"---"+s2);//用于研究

                if (s1.length() > s2.length())
                {
                        return 1;
                }
                if (s1.equals(s2))
                {	
                	System.out.println(s1+"+++"+s2);
                	return 0;
                }
                return -1;
        }
}





 compare的方法是让这个ts里面的数据按照长度来排序,这个没问题,但是这位同学要在compare里面打印出相同的元素。

所以当s1和s2相同时,打印结果是

 

f8+++f8

8d56+++8d56

 

 

 

我试了很久,主要集中在如何删除f8.这第一个元素,不知道为什么这个compare在比较的时候,第一次一定是o1和o2一定都要取f8.我想这是java设计者的要求,一定会同时取ts里面的第一个元素。最后我是没找到办法的,但是我倒是发现了compare排序机制里面的一些问题,return 1和-1我之前就知道怎么回事,return 0会如何呢?return 0的话会删除s1或者s2.因为它认为s1和s2是重复的。

 

后来我加入了 System.out.println(s1+"---"+s2);//用于研究 这段代码会,打印结果

 

f8---f8

f8+++f8

25d55---f8

1d1---f8

1d1---25d55

8d56---1d1

8d56---25d55

25555---1d1

25555---25d55

25555---8d56

8d56---1d1

8d56---25555

8d56---8d56

8d56+++8d56

 

我就看这个o1和o2的取法规律,虽然没有完全理清楚,但是再结合java对compare的说明

 

Compares its two arguments for order. Returns a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second.

 

In the foregoing description, the notation sgn(expression) designates the mathematical signum function, which is defined to return one of -1, 0, or 1 according to whether the value of expression is negative, zero or positive.

 

The implementor must ensure that sgn(compare(x, y)) == -sgn(compare(y, x)) for all x and y. (This implies that compare(x, y) must throw an exception if and only if compare(y, x) throws an exception.)

 

The implementor must also ensure that the relation is transitive: ((compare(x, y)>0) && (compare(y, z)>0)) implies compare(x, z)>0.

 

Finally, the implementor must ensure that compare(x, y)==0 implies that sgn(compare(x, z))==sgn(compare(y, z)) for all z.

 

It is generally the case, but not strictly required that (compare(x, y)==0) == (x.equals(y)). Generally speaking, any comparator that violates this condition should clearly indicate this fact. The recommended language is "Note: this comparator imposes orderings that are inconsistent with equals."

 

Specified by: compare(...) in Comparator

Parameters:

o1 the first object to be compared.

o2 the second object to be compared.

Returns:

a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second.

 

上面这段英文总结起来说明一个问题,这个比较是传递的。类似于x>y,y>z.那么x>z。反正这个compare函数内部有这样一个机制。

最终:我大概总结了这个compare的算法。

我猜想有2个集合。第一个装着传进来的treeset数据,第二个是空的。以本代码为例

 

之后开始比较:

1、先把第一个集合里的第一个f8,放到第二个集合里面的第一个位置.之后就是我困惑的地方。(下述)

2、取第一个集合里面的下一个o1=25d55,再取第二个集合里面的第一个o2=f8。比较之后return 1,所以25d55放在f8后面且放入第二个集合的下一个位置

 

3、取第一个集合里面的下一个o1=1d1,再取第二个集合里面的第一个o2=f8,return 1.所以1d1放在f8后面,接着再取第二个集合里面的第二个o2=25d55,return -1.所以1d1放在25d55的后面。

 

其余类似。

 

最后,当o1==8d56和o2==8d56,两者一比较发现return 0了,那么不就把o1放进第二个集合。最后返回的第二个我觉得去不去集合就少了一个重复的元素。

 

我就想不通,第一步,为什么还要o1和o2还要取一次f8,在我没有添加return0的时候,集合里只有一个f8,添加了之后还是只有一个f8.如何判断机制和8d56那一步一样,那么在没有return 0的时候,应该是有2个f8.

 

我又想到了一种解释,就是o1和o2如果相同的话,就让o1放在o2的位置,这样集合2中还是没有重复元素。关键是return 0的存在与否不影响f8,但是却影响着8d56啊。

 

 

算了,这个问题想了太久了,不纠结了,这次博客记录在这里,以后再回答吧

 

 

 

                                                ------- android培训、java培训、期待与您交流! ----------


    
最新技术文章:
▪Android开发之登录验证实例教程
▪Android开发之注册登录方法示例
▪Android获取手机SIM卡运营商信息的方法
▪Android实现将已发送的短信写入短信数据库的...
▪Android发送短信功能代码
▪Android根据电话号码获得联系人头像实例代码
▪Android中GPS定位的用法实例
▪Android实现退出时关闭所有Activity的方法
▪Android实现文件的分割和组装
▪Android录音应用实例教程
▪Android双击返回键退出程序的实现方法
▪Android实现侦听电池状态显示、电量及充电动...
▪Android获取当前已连接的wifi信号强度的方法
▪Android实现动态显示或隐藏密码输入框的内容
▪根据USER-AGENT判断手机类型并跳转到相应的app...
▪Android Touch事件分发过程详解
▪Android中实现为TextView添加多个可点击的文本
▪Android程序设计之AIDL实例详解
▪Android显式启动与隐式启动Activity的区别介绍
▪Android按钮单击事件的四种常用写法总结
▪Android消息处理机制Looper和Handler详解
▪Android实现Back功能代码片段总结
▪Android实用的代码片段 常用代码总结
▪Android实现弹出键盘的方法
▪Android中通过view方式获取当前Activity的屏幕截...
▪Android提高之自定义Menu(TabMenu)实现方法
▪Android提高之多方向抽屉实现方法
▪Android提高之MediaPlayer播放网络音频的实现方法...
▪Android提高之MediaPlayer播放网络视频的实现方法...
▪Android提高之手游转电视游戏的模拟操控
 


站内导航:


特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

©2012-2021,,E-mail:www_#163.com(请将#改为@)

浙ICP备11055608号-3