位置在这个LBS与SNS的时代显得特别重要,Android获取移动设备位置的功能也成为大多数App的标配。
最常用的定位方式有以下几种:
1.GPS
2.网络(包括基站、WIFI)
3.被动定位
以上3种方式中,GPS定位经度最高,水平精度可达10米左右,虽然GPS定位精度高,但是这种方式是最费电的,同时定位的时间也比较长,尤其是在GPS信号不好的情况下。甚至有时候,如果你在室内,那么GPS定位只是徒劳而已。网络定位速度较快,依赖于网络状况良好与否。其实很多情况下,我们都是同时使用多种定位方式,像百度地图的定位SDK和高德地图的定位SDK都提供了网络和GPS混合定位的方式。多种定位方式的混合定位可以减少定位时间,但是对电量的消耗却没有帮助。
再来看被动定位,被动定位我们一般用的比较少,它是在API=8才加入的,顾名思义,这种方式不是主动去请求位置信息,而是被动的接收位置更新,因此这种方式是最省电的。具体来说,我们的App如果想知道位置信息,只需要开启一个位置监听即可,然后就等待其他应用或服务主动发出位置请求,我们的App可以和主动发起为之请求的组件同时接收更新。很明显被动定位的方式有着严重的局限性,因为我们的定位依赖于其他应用,那么则无法控制定位的实时性,如果在一段时间内没有任何其他应用主动请求位置,那么被动定位则不会收到位置更新,只能继续等待;如果我们急于获取位置,那么这种方式就不适用。有时候觉得这种方式有点自私,因为它自己不怎么耗电,而却把定位消耗的电量算到其他应用的头上了,有点坐享其成的感觉,既然Android API提供了这种方式,应该会在某个合适的时候有它的特定用途吧。
有时候在特定的需求下,宁可牺牲电量来频繁请求位置;也有的为了节省电量而使用省电的定位方法和限制定位请求次数。Android还提供了Criteria对象,通过设置各种条件来筛选符合要求的定位服务,这些限制条件包括精度、耗电等。
一般来说,可以同时使用网络定位和被动定位方式,网络定位方式比GPS方式省电且速度较快,使用被动定位方式可以接收GPS的精确的位置信息。
因为被动定位用的比较少,所以提供一个被动定位的测试demo,就一个Activity,布局文件很简单,只有一个textview(显示定位结果)和一个button(启动被动定位)。Activity的代码如下:
package com.andy.passivelocation; import android.location.Location; import android.location.LocationListener; import android.location.LocationManager; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.app.Activity; import android.content.Context; import android.util.Log; import android.view.Menu; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.TextView; public class MainActivity extends Activity { private final String TAG = "MainActivity"; private TextView mTextView; private Button mButton; private Handler mHandler; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mTextView = (TextView) findViewById(R.id.location); mButton = (Button) findViewById(R.id.locationBtn); mButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub mButton.setText("被动定位中……"); requestPassiveLocationUpdates(); } }); mHandler = new Handler() { @Override public void dispatchMessage(Message msg) { // TODO Auto-generated method stub super.dispatchMessage(msg); Location location = (Location) msg.obj; switch (msg.what) { case 1: if (location != null) { mTextView.setText("GPS:" + location.getLatitude() + "," + location.getLongitude()); mButton.setText("Passive Location"); } break; case 2: if (location != null) { mTextView.setText("NetWork:" + location.getLatitude() + "," + location.getLongitude()); mButton.setText("Passive Location"); } break; default: break; } } }; } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } public void requestPassiveLocationUpdates() { LocationManager manager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); LocationListener listener = new LocationListener() { @Override public void onStatusChanged(String provider, int status, Bundle extras) { // TODO Auto-generated method stub Log.e(TAG, "[Passive]" + provider + "onStatusChanged"); } @Override public void onProviderEnabled(String provider) { // TODO Auto-generated method stub Log.e(TAG, "[Passive]" + provider + "onProviderEnabled"); } @Override public void onProviderDisabled(String provider) { // TODO Auto-generated method stub Log.e(TAG, "[Passive]" + provider + "onProviderDisabled"); } @Override public void onLocationChanged(Location location) { // TODO Auto-generated method stub Log.e(TAG, "[Passive]-onLocationChanged"); Message msg = new Message(); // GPS if (LocationManager.GPS_PROVIDER.equals(location.getProvider())) { msg.what = 1; msg.obj = location; mHandler.sendMessage(msg); } else if (LocationManager.NETWORK_PROVIDER.equals(location.getProvider())) { // 网络 msg.what = 2; msg.obj = location; mHandler.sendMessage(msg); } } }; // 采用被动定位,为了省电 manager.requestLocationUpdates(LocationManager.PASSIVE_PROVIDER, 5000, 100, listener); } }