第十四章:Android中的GPS应用

GPS(Global Position System,全球定位系统)是20世纪70年代由美国陆海空三军联合研制的新一代空间卫星导航定位系统。

24颗GPS卫星在离地面2万2千功力的高空上,以12小时的周期环绕地球运行,使得在任意时刻,在地面的任意一点都可以同时观测到4颗以上的卫星。

由于卫星的位置精确,在GPS观测中,我们可以得到卫星到接收机的距离,利用三维坐标中的距离公式和3颗卫星,就可以组成3个方程式,解出观测点的位置(X、Y、Z)。考虑到卫星的时钟与接收机时钟之间的误差,实际上有4个未知数,X、Y、Z和钟差,因而需要引入第4颗卫星,形成4个方程式求解,从而得到观测点的经纬度和高程。

一、LocationManager和LocationProvider简介

LocationManager位于android.location包中,该类提供了系统位置访问的方法。LocationProvider定义了位置服务的提供方法,例如,是由GPS设备提供还是通过网络提供等。

1、LocationManager

通过LocationManager可以实现设备的定位、跟踪和趋近提示。可以通过getSystemService(Context.LOCATION_SERVICE)方法获得该类的实例。

常用属性和方法

属性或方法名称属性或方法描述
GPS_PROVIDER静态字符串常量,表明LocationProvider是GPS
NETWORK_PROVIDER静态字符串常量,表明LocationProvider是网络
addGpsStatusListener(Listener listener)添加一个GPS状态监听器

addProximityAlert(double latitude, double longitude,

float radius, long expiration, PendingIntent intent)

添加一个趋近警告
getAllProviders()获得所有LocationProvider列表
getBestProvider(Criteria criteria, boolean enabledOnly)根据Criteria返回最适合的LocationProvider
getLastKnownLocation(String provider)根据Provider获得位置信息
getProvider(String name)获得指定名称的LocationProvider
getProviders(boolean enabledOnly)获得可利用的LocationProvider列表
removeProximityAlert(PendingIntent intent)删除趋近警告

requestLocationUpdates(String provider, long minTime,

float minDistance, LocationListener listener)

通过给定的Provider名称,周期性的通知当前Activity

2、LocationProvider

用来描述位置提供者,设置位置提供者的一些属性。可以通过Criteria类来为LocationProvider设置条件,获得合适的LocationProvider。

属性或方法名称属性或方法描述
AVAILABLE静态整形常量,标示是否可利用
OUT_OF_SERVICE静态整形常量,不再服务器
TEMPORARILY_UNAVAILABLE静态整形常量,临时不可利用
getAccuracy()获得经度
getName()获得名称
getPowerRequirement()获得电源需求
hasMonetaryCost()花钱的还是免费的
requiresCell()是否需要访问基本网络
requiresNetwork()是否需要Internet网络数据
requiresSatellite()是否需要访问卫星
supportsAltitude()是否能够提供高度信息
supportsBearing()是否能够提供方向信息
supportsSpeed()是否能够提供速度信息

二、通过模拟器测试位置服务

演示通过模拟器发送经纬度来测试位置服务

注意:创建项目时,target build要选择Google APIs,这是为了添加选项jar文件maps.jar。

public class MainActivity extends Activity {
	private LocationManager locationManager;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        //通过getSystemService方法获得LocationManager实例
        locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
        locate();
    }
    //定位方法
    private void locate(){
    	TextView t = (TextView) findViewById(R.id.GPSTextView01);
    	StringBuilder builder = new StringBuilder("可利用的providers:");
    	List<String> providers = locationManager.getProviders(true);
    	//声明位置监听服务器
    	LocationListener ll = new LocationListener() {
    		//状态改变时调用
			@Override
			public void onStatusChanged(String provider, int status, Bundle extras) {}
			//Provider生效时调用
			@Override
			public void onProviderEnabled(String provider) {}
			//Provider失效时调用
			@Override
			public void onProviderDisabled(String provider) {}
			//位置改变时调用
			@Override
			public void onLocationChanged(Location location) {}
		};
		//循环provider,根据Provider获得位置信息(经纬度)
		for(String provider:providers){
			locationManager.requestLocationUpdates(provider, 0, 1000, ll);
			builder.append("\n").append(provider).append(":");
			Location location = locationManager.getLastKnownLocation(provider);
			if(location != null){
				//获得经度
				double lat = location.getLatitude();
				//获得纬度
				double lng = location.getLongitude();
				builder.append("(");
				builder.append(lat);
				builder.append(",");
				builder.append(lng);
				builder.append(")");
			}else{
				builder.append("没有位置信息");
			}
		}
		t.setText(builder);
    }
}

AndroidManifest.xml

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

三、获得LocationProvider

1、通过名称获得LocationProvider

		//通过getSystemService方法获得LocationManager实例
		LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
		//Provider名称常量
		String name = LocationManager.GPS_PROVIDER;
		//根据Provider名称获得LocationProvider
		LocationProvider myProvider;
		myProvider = locationManager.getProvider(name);

2、获得当前可利用的LocationProvider

		//通过getSystemService方法获得LocationManager实例
		LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
		//LocationProvider的两种方式
		String name = LocationManager.GPS_PROVIDER;
		String name2 = LocationManager.NETWORK_PROVIDER;
		//根据Provider名称获得LocationProvider
		LocationProvider myProvider;
		myProvider = locationManager.getProvider(name);
		
		boolean enabledOnly = true;
		//获得所有可利用的Provider名称列表
		List<String> providers = locationManager.getProviders(enabledOnly);
		//根据名称获得Provider
		myProvider = locationManager.getProvider(name);

3、根据Criteria条件获得LocationProvider

		LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
		//LocationProvider的查询条件案例
		Criteria criteria = new Criteria();
		//设置精确度
		criteria.setAccuracy(Criteria.ACCURACY_COARSE);
		//设置电耗
		criteria.setPowerRequirement(Criteria.POWER_LOW);
		//是否需要高度信息
		criteria.setAltitudeRequired(false);
		//是否需要方位信息
		criteria.setBearingRequired(false);
		//是否需要速度信息
		criteria.setSpeedRequired(false);
		//是否产生费用
		criteria.setCostAllowed(true);
		//获得符合条件最好的Provider
		String bestProvider = locationManager.getBestProvider(criteria, true);
		//获得符合条件的Provider
		List<String> matchingProviders = locationManager.getProviders(criteria, false);

四、定位和跟踪

1、定位
定位就是确定设备的位置,在这里用到了另外一个Location类,该类描述了当前设备的地理位置信息,包括经纬度、方向、高度和速度等。

Location常见属性和方法

属性或方法名称属性或方法描述
getLongitude()获得经度
getLatitude()获得纬度
getAccuracy()获得精确度
getAltitude()获得高度
getBearing()获得方向
getSpeed()获得速度


下面的实例演示了如何定位当前设备,并显示详细信息

public class MainActivity extends Activity {
	//声明定位服务管理器实例
	private LocationManager locationManager;
	private TextView tv;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
		tv = (TextView) findViewById(R.id.LocationTextView01);
		//获得位置信息
		Location location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
		//显示位置信息
		printMsg(location);
	}
	//显示位置信息方法
	private void printMsg(Location location){
		StringBuilder builder = new StringBuilder("可利用的providers");
		 if(location != null){
			 //获得经度
			 double lat = location.getLatitude();
			 //获得纬度
			 double lng = location.getLongitude();
			 builder.append("(");
			 builder.append(lat);
			 builder.append(",");
			 builder.append(lng);
			 builder.append(")");
			 if(location.hasAccuracy()){
				 builder.append("\n精度");
				 builder.append(location.getAccuracy());
			 }
			 if(location.hasAltitude()){
				 builder.append("\n高度");
				 builder.append(location.getAltitude());
			 }
			 if(location.hasBearing()){
				 builder.append("\n方向");
				 builder.append(location.getBearing());
			 }
			 if(location.hasSpeed()){
				 builder.append("\n速度");
				 builder.append(location.getSpeed());
			 }
		 }else{
			 builder.append("没有位置信息");
		 }
		 tv.setText(builder);
	}
}

2、跟踪

跟踪是通过注册监听器来实现的。下面的代码实现了设备的实时跟踪

public class MainActivity extends Activity {
	private LocationManager locationManager;
	private TextView tv;
	StringBuilder builder = new StringBuilder("位置信息:\n");
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
		tv = (TextView) findViewById(R.id.gzTextView01);
		String provider = locationManager.GPS_PROVIDER;
		Location location = locationManager.getLastKnownLocation(provider);
		updateMsg(location);
		LocationListener ll = new LocationListener() {
			@Override
			public void onStatusChanged(String arg0, int arg1, Bundle arg2) {}
			@Override
			public void onProviderEnabled(String arg0) {}
			@Override
			public void onProviderDisabled(String arg0) {}
			@Override
			public void onLocationChanged(Location arg0) {}
		};
		locationManager.requestLocationUpdates(provider, 2000, 10, ll);
	}
	//更新信息方法
	private void updateMsg(Location location) {
		if(location != null){
			 //获得经度
			 double lat = location.getLatitude();
			 //获得纬度
			 double lng = location.getLongitude();
			 builder.append("(");
			 builder.append(lat);
			 builder.append(",");
			 builder.append(lng);
			 builder.append(")");
			 if(location.hasAccuracy()){
				 builder.append("\n精度");
				 builder.append(location.getAccuracy());
			 }
			 if(location.hasAltitude()){
				 builder.append("\n高度");
				 builder.append(location.getAltitude());
			 }
			 if(location.hasBearing()){
				 builder.append("\n方向");
				 builder.append(location.getBearing());
			 }
			 if(location.hasSpeed()){
				 builder.append("\n速度");
				 builder.append(location.getSpeed());
			 }
		 }else{
			 builder.append("没有位置信息");
		 }
		 tv.setText(builder);
	}
}

五、趋近警告

如果有这样一种位置服务,能够对我们进入或退出某个设定的区域进行提示,这样的应用是很有意义的。

LocationManager提供了这一方法实现这一功能:addProximityAlert(double latitude, double longitude, float radius, long expiration, PendingIntent intent),该方法有5个参数,前两个是经纬度,第三个是区域半径,第四个是是否过期,第五个一般是一个广播PendingIntent。

要实现此功能需要两个步骤:一是获得LocationManager实例,调用其方法addProximityalert并添加趋近提示;二是定义一个广播接收器,当设备进入设定区域时提醒用户。

/**
 * 趋近警告
 */
public class MainActivity extends Activity {
	private static final String PROXIMITY_ALERT_ACTION_NAME = "mx.android.ch14.ProximityAlert";
	private Button btn;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		btn = (Button) findViewById(R.id.Button01);
		btn.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View arg0) {
				set();
			}
		});
	}
	//趋近提示方法
	private void set(){
		//定位i服务常量
		String locService = Context.LOCATION_SERVICE;
		//定位i服务管理器实例
		LocationManager locationManager;
		locationManager = (LocationManager) getSystemService(locService);
		//声明经度
		double lat = 37.4;
		//声明纬度
		double lng = 55.0;
		//声明半径(单位米)
		float radius = 200f;
		//不过期
		long expiration = -1;
		Intent intent = new Intent(PROXIMITY_ALERT_ACTION_NAME);
		PendingIntent pi = PendingIntent.getBroadcast(this, -1, intent, 0);
		//添加趋近警告
		locationManager.addProximityAlert(lat, lng, radius, expiration, pi);
	}
}
/**
 * 定义广播接收器,用来检测当设备进入设定区域时提示用户
 */
public class ProximityAlertReciever extends BroadcastReceiver {
	@Override
	public void onReceive(Context context, Intent intent) {
		//趋近关键字
		String key = LocationManager.KEY_PROXIMITY_ENTERING;
		//从Intent获得额外信息,判断是否进入设置区域
		boolean isEnter = intent.getBooleanExtra(key, false);
		if(isEnter){
			Toast.makeText(context, "你已经进入海淀区!", Toast.LENGTH_LONG).show();
		}
	}
}

在AndroidManifest.xml中声明广播接收器

	<receiver android:name="ProximityAlertReciever">
            <intent-filter>
                <action android:name="mx.android.ch14.ProximityAlert" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </receiver>

六、Geocoder正逆向编码
Geocoder可以完成位置信息和经纬度坐标之间的相互转换。例如,你知道了某个地方的名称,想知道它的经纬度坐标,或者你知道了某个地方的经纬度坐标,想知道其名称。

解码方式有以下两种:

  • 正向编码:通过位置名称获得经纬度坐标
  • 反向编码:通过经纬度坐标获得位置名称
public class MainActivity extends Activity {
	private TextView tv;
	private Button b1,b2;
	private LocationManager locationManager;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
		tv = (TextView) findViewById(R.id.coder_TextView01);
		b1 = (Button) findViewById(R.id.coder_Button01);
		b2 = (Button) findViewById(R.id.coder_Button02);
		//正向编码
		b1.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				forward();
			}
		});
		//反向编码
		b2.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				reserse();
			}
		});
	}
	//正向编码
	private void forward(){
		Geocoder gc = new Geocoder(this, Locale.getDefault());
		String address = "北京天安门";
		List<Address> locations = null;
		try {
			locations = gc.getFromLocationName(address, 10);
			if(locations.size() > 0){
				Address a = locations.get(0);
				double lat = a.getLatitude();
				double lng = a.getLongitude();
				tv.setText(lat + ":" + lng);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	//反向编码
	private void reserse(){
		double lng = 116.46;
		double lat = 39.92;
		Geocoder gc = new Geocoder(this, Locale.getDefault());
		List<Address> addresses = null;
		try {
			addresses = gc.getFromLocation(lat, lng, 10);
			StringBuilder sb = new StringBuilder();
			if(addresses.size() > 0){
				Address a = addresses.get(0);
				for (int i = 0; i < a.getMaxAddressLineIndex(); i++) {
					sb.append(a.getAddressLine(i)).append("\n");
					sb.append(a.getLocality()).append("\n");
					sb.append(a.getPostalCode()).append("\n");
					sb.append(a.getCountryName());
				}
				tv.setText(sb.toString());
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值