1. LBS系统架构
LBS系统分为三大部分:
1) 第一部分为LBS客户端管理部分,主要提供给客户端应用使用,客户端应用调用此部分提供的功能进行位置定位。
LocationManager,提供给客户端应用调用,获取位置等信息,同时当有位置信息变化时通知客户端应用。
LocationListener,提供给客户端应用注册使用,每个客户端应用对应一个LocationListener,通过LocationManager注册到系统维护的一个位置服务的链表中,当系统中发现有位置信息变化或者其它信息变化时,会通过它通知客户端应用。
GpsStatus,提供给客户端应用获取GPS定位服务的状态。
GeoCoder,提供给客户端应用调用,获取地理编码信息。
2)第二部分为LBS系统服务部分,开机时启动此服务LocationManagerService,一方面负责处理LBS客户端管理提供的定位等功能需求,另一方面启动提供定位功能的功能模块。
3)第三部分为LBS的定位功能服务部分,完成定位服务模块的定位等动能。
GpsLocationProvider,提供GPS定位服务,通过GPS底层模块获取位置信息及状态变化,通知LBS系统服务来获取位置信息及状态变化等。
LocationProviderProxy,提供网路定位服务,会通过ILocationProvider调用LocationProvider提供的定位功能。LocationProvider只是提供了一个抽象的定位服务模块,并没有真正实现定位功能,需要用户去实现继承LocationProvider来完成此功能。
GeocodeProxy,提供地址编码服务,会通过IGeocodeProvider调用GeocodeProvider提供的正反向地址编码功能。GeocodeProvider只提供了一个抽象的反向地址编码服务模块,根据经纬度来获取地址信息,它并没有真正实现反向地址编码功能,需要用户去实现继承GeocodeProvider来完成此功能。
2. LBS目录结构
(1) frameworks/base/services/java/com.android.server/LocationManager.java
提供的系统定位服务类。
(2) frameworks/base/services/java/com.android.server.location/
提供给系统定位服务使用的相关类。
(3) frameworks/base/location/lib/java/com.android.location.provider/
提供的抽象定位服务模块类以及地址编码服务模块类。供用户继续以实现某种定位功能。
(4) frameworks/base/location/java/android.location
提供给客户端使用的定位服务相关类。
3. LBS定位服务流程
3.1. 启动系统定位服务
开机后由系统启动系统定位服务LocationManagerService。
1) 加载和启动提供定位服务的各个定位模块LocationProviderInterface;
2) 注册网络更新;
3) 注册包管理更新,监听设置变化信息,获取各个定位模块可用信息。
3.2. 客户端应用注册监听
客户端应用实现LocationListener接口,通过LocationManager传递给LocationManagerService一个注册监听器,当定位模块有状态变化或者位置变化等信息变化时,定位模块会通知LocationManagerService,LocationManagerService再通过该监听器把信息变化发给对应的客户端应用,然后客户端应用再进行相应的处理。
1)客户端应用调用LocationManager.requestLocationUpdates(Stringprovider,..., ILocationListener listener);
客户端会实现一个接口LocationListener,封装在ILocationListener中,通过参数传入上面的函数中,进行注册回调。
2)LocationManagerService.getReiver(ILocationListenerlistener);根据ILocationListener生成Receiver,并加入到LocationManagerService维护的一个HashMap<ILocationListener,Receiver>列表中。 当LocationManagerService发现有位置、状态等信息变化时,调用该列表中的各个Receiver,通知客户端应用对应的监听器。
3)LocationManagerService.requestLocationLocked(Stringprovider,…,Receiver receiver);创建一个UpdateRecord(provider,…,receiver,uid),记录客户端监听的记录,存入到LocationManagerService维护的HashMap<String provider, ArrayList<UpdateRecord>>中,记录客户端对每个定位功能模块provider的位置监听记录。
3.3. 系统定位服务通知状态或者位置变化
当LocationMangerService收到定位功能模块传来的状态或位置等信息变化时,会更新保存的状态或者位置信息,同时通知客户端监听器列表中的各个客户端监听器。
以位置变化为例:
1)当定位模块获取到位置信息变化时,调用LocationManagerService.reportLocaiton(Localtion);
2) LocationManagerService通知其它的定位模块LocationProviderInterface去更新位置信息,LocationProviderInterface.updateLocation(Location);
3)取出客户端监听器列表中的各个监听器Receiver,更新位置信息,调用
Receiver.callLocationChangedLocked (Locatlion);
调用客户端提供的回调函数接口:
ILocationListener.onLocationChanged (Location);
4) 客户端应用更新位置信息:
LocationManager.ListenerTransport.onLocationChanged(Location);
调用LocationListener.onLocationChanged(Location);更新客户端应用所需要的位置信息。
4. LBS网络定位
4.1. LBS系统定位服务初始化网络定位服务
1)获取网络定位模块的包名
在LocationManagerService(…) 中
mNetworkLocationProviderPackageName =resources.getString(
com.android.internal.R.string.config_networkLocationProvider);
2)创建和启动网络定位模块
在LocationManagerService._loadProvidersLocked()中,
如果网络定位模块的包名不为空,则:
创建一个LocationProviderProxy(LocationManager.NETWORK_PROVIDER,
mNetworkLocationProviderPackageName, …);
调用addProvider(…),将其加入到LocationManagerService维护的定位模块列表中,以提供具体的定位服务。
3)LocationProviderProxy在创建时,通过调用bindService(…, ServiceConnection, Context.BIND_AUTO_CREATE),启动绑定mNetworkLocationProviderPackageName对应的网络定位服务,与此服务创建一个连接,创建成功后,会执行:
LocationProviderProxy.ServiceConnection.onServiceConnected(ComponentName className,IBinder service),获取网络定位服务模块传过来的调用接口ILocationProvider。
4.2. 网络定位服务的实现和启动
1)实现网络定位模块
LocationProvider为网络定位的基类,外部需要继承并实现它; LocationProvider中创建了一个接口类 ILocationProvider,用于与LBS系统服务交互。
2)启动网络定位模块
LocationProviderProxy启动网络定位服务模块,网络定位服务模块创建LocationProvider,
并与之建立连接; 网络定位服务启动成功后,会传给LocationProviderProxy 已经创建好的ILocationProvider对象。
4.3. 系统定位服务调用网络定位模块
LocationManagerService会调用ILocationProvider的接口函数,进而调用到LocationProvider的函数。
5. LBS地址编码
5.1. 系统定位服务中初始化
1)获取地址编码模块的包名
在LocationManagerService(…) 中
mGeocodeProviderPackageName= resources.getString(
com.android.internal.R.string.config_geocodeProvider);
2)创建和启动地址编码模块
在LocationManagerService._loadProvidersLocked()中,
如果地址编码模块的包名不为空,则:
创建一个GeocoderProxy(mGeocodeProviderPackageName)。
3)GeocoderProxy在创建时,通过调用bindService(…, ServiceConnection, Context.BIND_AUTO_CREATE), 启动mGeocodeProviderPackageName对应的地址编码服务,与此服务创建一个连接,创建成功后,会执行:
GeocoderProxy.ServiceConnection.onServiceConnected(ComponentNameclassName, IBinder service),获取地址编码模块传过来的调用接口IGeocodeProvider。
5.2. 地址编码模块的实现和启动
1)实现地址编码模块
GeocodeProvider为地址编码模块的基类,外部需要继承并实现它;
GeocodeProvider中创建了一个接口类 IGeocodeProvider,用于与LBS系统服务交互。
2)启动地址编码模块
GeocoderProxy启动地址编码模块GeocodeProvider,
并与之建立连接; GeocodeProvider启动成功后,会通过getBinder() 传给GeocoderProxy已经创建好的IGeocodeProvider对象。
5.3. 系统定位服务调用地址编码模块
LocationManagerService中的GeocodeProxy会调用IGeocodeProvider的接口函数,进而调用到GeocodeProvider的函数。
1 逻辑远比方便重要。
有的人喜欢将主表数据之前,生成细表数据。撇开数据库的主外键约束的情况不说,单单从逻辑上,也应该是先有主表数据,然后再有细表数据。
为了绑定显示方便,而将细表数据先存到数据库中,和逻辑上的混乱与造成的麻烦相比,远远得不偿失。
2 临时数据,临时存。
简单的临时数据,可以存到ViewState当中,复杂的(如发表一个新闻,带多个附件的)可以用Session.
Session可以放置任何对象。Ctype(Session("FJ"),ArrayList)可以存放很多东西,比如FileUpload。一些技巧应用能带来非常多的好处。但是,不要将临时数据存到数据库中。更不要指望用复杂的判断和清除数据、置标识等方式,貌似很有技巧,实际上是把简单的事情复杂了。
3 事务,事务!
主细表数据一个按钮同时添的时候,要有先有后,有事务,出错就回滚。我的习惯如下
Try
DB.StartTrans()
执行SQL1(主表)
执行SQL2(细表)
执行SQL3(细表)
执行SQL4(细表)
....
DB.Commit()
'提示成功
Catch ex As Exception
DB.RollBack()
'将ex信息提示出来
End Try
如果有一些是调用函数内部有Try了。或者某些执行返回影响行数为0,那就在本页面自己手动Throw一些错误,比如
If Myuser.Insert(参数,参数)=0 Then
Throw New Exception "增加人员失败"
End If
由于我的Insert函数中已经Try了,返回值根据是否为0判断是执行否有错误,那么我就手动Throw出相应的信息。
4 约束关系一定要完整
一个好的程序,不仅仅是代码要逻辑清楚,简捷,健壮.同时,对于数据库,其约束,索引,主键,外键一定要完整.一个好的约束,是避免错误数据产生和简化开发最直接有效的办法.
ArrayList可以方便的实现列表操作,但有时候需要建立一个ArrayList数组.首先想到的是类似下面的方法:ArrayList<Integer[]list=newArrayList<Integer()[N];但会出现错误.改为ArrayList[]list=newArrayList[N];会有警告.这是因为Java没有范型数组,可以参考以下方法实现类似功能:ArrayList<ArrayList<Integerals=newArrayList<ArrayList<Integer();ArrayList<Integera1=newArrayList<Integer();ArrayList<Integera2=newArrayList<Integer();ArrayList<Integera3=newArrayList<Integer();
stirng指令 是C++里面一个用来处理字符串的类。
包含了字符串处理掉一下常用方法,如:
Constructors 构造函数,用于字符串初始化
Operators 操作符,用于字符串比较和赋值
append() 在字符串的末尾添加文本
assign() 为字符串赋新值
at() 按给定索引值返回字符
begin() 返回一个迭代器,指向第一个字符
c_str() 将字符串以C字符数组的形式返回
capacity() 返回重新分配空间前的字符容量
compare() 比较两个字符串
copy() 将内容复制为一个字符数组
data() 返回内容的字符数组形式
empty() 如果字符串为空,返回真
end() 返回一个迭代器,指向字符串的末尾。(最后一个字符的下一个位置)
erase() 删除字符
find() 在字符串中查找字符
find_first_of() 查找第一个与value中的某值相等的字符
find_first_not_of() 查找第一个与value中的所有值都不相等的字符
find_last_of() 查找最后一个与value中的某值相等的字符
find_last_not_of() 查找最后一个与value中的所有值都不相等的字符
get_allocator() 返回配置器
insert() 插入字符
length() 返回字符串的长度
max_size() 返回字符的最大可能个数
rbegin() 返回一个逆向迭代器,指向最后一个字符
rend() 返回一个逆向迭代器,指向第一个元素的前一个位置
replace() 替换字符
reserve() 保留一定容量以容纳字符串(设置capacity值)
resize() 重新设置字符串的大小
rfind() 查找最后一个与value相等的字符(逆向查找)
size() 返回字符串中字符的数量
substr() 返回某个子字符串
swap() 交换两个字符串的内容
ArrayList
1)只能装入引用对象(基本类型要转换为封装类);
2)线程不安全;
3)底层由数组实现(顺序表),因为由顺序表实现,所以会具备顺序表的特点,如:需要声明长度、超出长度时需要进行扩容、不适合频繁的移动删除元素、检索元素快;
4)capacity默认为10,超出时,capacity自动增长0.5倍(oldCapacity >> 1)。
Vector:
1)只能装入引用对象(基本类型要转换为封装类);
2)Vector通过synchronized方法保证线程安全;
3)底层也由数组实现;
4)capacity默认为10(在构造方法中),超出时增长capacityIncrement的量,capacityIncrement小于等于0时,则增长1倍((capacityIncrement > 0) ? capacityIncrement : oldCapacity)。
LinkedList
1)只能装入引用对象(基本类型会转换为封装类);
2)线程不安全;
3)底层实现为链表,具备链表的特点,如:不用声明长度、检索性能较差,但是插入移动删除较快。
4)链表通过Node对象实现。
ArrayList和LinkedList
共性:ArrayList与LinkedList都是List接口的实现类,因此都实现了List的所有未实现的方法,只是实现的方式有所不同。
区别:List接口的实现方式不同
ArrayList实现了List接口,以数组的方式来实现的,因此对于快速的随机取得对象的需求,使用ArrayList实现执行效率上会比较好。
LinkedList是采用链表的方式来实现List接口的,因此在进行insert和remove动作时效率要比ArrayList高。适合用来实现Stack(堆栈)与Queue(队列)。
HashTable和HashMap
共性:都实现了Map接口。
区别:
(1)继承的父类不同
Hashtable继承自Dictionary类,而HashMap继承自AbstractMap类。
(2)线程安全性不同
Hashtable的方法是Synchronize的,而HashMap中的方法在缺省情况下是非Synchronize的。
(3)提供contains方法
HashMap把Hashtable的contains方法去掉了,改成containsValue和containsKey,因为contains方法容易让人引起误解。
Hashtable则保留了contains,containsValue和containsKey三个方法,其中contains和containsValue功能相同。
(4)key和value是否允许null值
Hashtable中,key和value都不允许出现null值。HashMap中,null可以作为键,这样的键只有一个;可以有一个或多个键所对应的值为null。
(5)两个遍历方式的内部实现上不同
HashMap使用了 Iterator;Hashtable使用 Iterator,Enumeration两种方式 。
(6)hash值不同
哈希值的使用不同,HashTable直接使用对象的hashCode。而HashMap重新计算hash值。
(7)内部实现使用的数组初始化和扩容方式不同
HashTable在不指定容量的情况下的默认容量为11,增加的方式是 old*2+1;而HashMap为16,Hashtable不要求底层数组的容量一定要为2的整数次幂,而HashMap则要求一定为2的整数次幂。