Android学习笔记(2)----LocationManager的使用
今天使用Android的LocationManager制作了一款获取当前经纬坐标位置的软件。
LocationManager获取的只是经纬坐标点,为了解析出当前经纬坐标点的实际位置,可以使用Google提供的 Geocoding API 服务。
谷歌提供了一套 Geocoding API,使用它的话可以完成反向地理编码的工作,只不过它的用法稍微复杂了一些,但稳定性要比 GeoCoder 强得多。本小节中我们只是学习一下 GeocodingAPI 的简单用法, 更详细的用法请参考官方文档: https://developers.google.com/maps/documentation/geocoding/。
GeocodingAPI 的工作原理并不神秘,其实就是利用了 HTTP 协议。
在手机端我们可以向谷歌的服务器发起一条 HTTP 请求,并将经纬度的值作为参数一同传递过去,然后服务器会帮我们将这个经纬值转换成看得懂的位置信息,再将这些信息返回给手机端,最后手机端去解析服务器返回的信息,并进行处理就可以了。
Geocoding API 中规定了很多接口,其中反向地理编码的接口如下:
http://maps.googleapis.com/maps/api/geocode/json?latlng=40.714224,-73.961452&sensor=true_or_false
我们来仔细看下这个接口的定义, 其中 http://maps.googleapis.com/maps/api/geocode/ 是固定的,表示接口的连接地址。json 表示希望服务器能够返回 JSON 格式的数据,这里也可以指定成 xml。latlng=40.714224,-73.96145 表示传递给服务器去解码的经纬值是北纬 40.714224度,西经 73.96145 度。 sensor=true_or_false 表示这条请求是否来自于某个设备的位置传感器,通常指定成 false 即可。
如果发送
http://maps.googleapis.com/maps/api/geocode/json?latlng=40.714224,-73.96145&sensor=false
这样一条请求给 服务器,我们将会得到一段非常长的 JSON 格式的数据,其中会包括如下部分内容:
"formatted_address" : "277 Bedford Avenue, 布鲁克林纽约州 11211美国"
从这段内容中我们就可以看出北纬 40.714224 度,西经 73.96145 度对应的地理位置是在哪里了。如果你想查看服务器返回的完整数据,在浏览器中访问上面的网址即可。
这样的话,使用 Geocoding API 进行反向地理编码的工作原理你就已经搞清楚了,那么难点其实就在于如何从服务器返回的数据中解析出我们想要的那部分信息了。因而软件的一个关键点就在于JSON数据的解析。
代码如下:
//activity_main.xml
//activity_main.xml <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
> <TextView
android:id="@+id/position_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello"
/>
<TextView
android:id="@+id/position_plain_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/> </LinearLayout>
界面如下:
//MainActivity.java
//MainActivity.java package com.example.location; import java.util.List;
import org.json.JSONArray;
import org.json.JSONObject;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
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.util.Log;
import android.widget.TextView;
import android.widget.Toast; public class MainActivity extends Activity {
private static final String TAG="POSITION";
public static final int SHOW_LOCATION=0;//更新文字式的位置信息
public static final int SHOW_LATLNG=1; //更新经纬坐标式的位置信息
private TextView positionTextView;
private TextView positionLatLng;
private LocationManager locationManager;
private String provider; private Handler handler=new Handler(){
@SuppressLint("HandlerLeak")
@Override
public void handleMessage(Message message){
switch(message.what){
case SHOW_LOCATION:
Log.d(TAG, "showing the positio>>>>>");
String currentPosition=(String)message.obj;
positionTextView.setText(currentPosition);
Log.d(TAG, "Has show the position...>>>>....");
break;
case SHOW_LATLNG:
String latlng=(String)message.obj;
positionLatLng.setText(latlng);
default:
break;
}
}
}; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
positionTextView=(TextView)findViewById(R.id.position_text_view);
positionLatLng=(TextView)findViewById(R.id.position_plain_text);
locationManager=(LocationManager)getSystemService(Context.LOCATION_SERVICE);
//获取所有可用的位置提供器
List<String>providerList=locationManager.getProviders(true);
if(providerList.contains(LocationManager.GPS_PROVIDER)){
provider=LocationManager.GPS_PROVIDER;
}
else if(providerList.contains(LocationManager.NETWORK_PROVIDER)){
provider=LocationManager.NETWORK_PROVIDER;
}
else{
//当没有可用的位置提供器时,弹出Toast提示用户
Toast.makeText(this, "No Location provider to use", Toast.LENGTH_SHORT).show();
return;
}
Location location=locationManager.getLastKnownLocation(provider);
if(location!=null){
//显示当前设备的位置信息
Log.d(TAG, "location!=null");
showLocation(location);
}
locationManager.requestLocationUpdates(provider, 1000, 1, locationListener);
Log.d(TAG, "Running....");
} protected void onDestroy(){
super.onDestroy();
if(locationManager!=null){
//关闭程序时将监听移除
locationManager.removeUpdates(locationListener);
}
}
//LocationListener 用于当位置信息变化时由 locationManager 调用
LocationListener locationListener=new LocationListener(){ @Override
public void onLocationChanged(Location location) {
// TODO Auto-generated method stub
//更新当前设备的位置信息
showLocation(location);
} @Override
public void onProviderDisabled(String provider) {
// TODO Auto-generated method stub } @Override
public void onProviderEnabled(String provider) {
// TODO Auto-generated method stub } @Override
public void onStatusChanged(String provider, int status, Bundle extras) {
// TODO Auto-generated method stub } }; private void showLocation(final Location location){
//显示实际地理位置
//开启线程来发起网络请求
new Thread(new Runnable(){ @Override
public void run() {
// TODO Auto-generated method stub
try{
String request="http://maps.googleapis.com/maps/api/geocode/json?latlng=";
request+=location.getLatitude()+","+location.getLongitude()+"&sensor=false";
String response=HttpUtil.sendHttpRequest(MainActivity.this,request);
parseJSONResponse(response); }
catch(Exception e){
Log.d(TAG, "showLocation: the inptuStream is wrong!");
e.printStackTrace();
}
} }).start();
//显示经纬度坐标
new Thread(new Runnable(){ @Override
public void run() {
// TODO Auto-generated method stub
String position="";
position="Latitude="+location.getLatitude()+"\n"
+"Longitude="+location.getLongitude();
Message msg=new Message();
msg.what=SHOW_LATLNG;
msg.obj=position;
handler.sendMessage(msg);
} }).start();
} //解析JSON数据
private void parseJSONResponse(String response){
try{
Log.d(TAG, "parseJSONResponse: getting the jsonObject...");
JSONObject jsonObject=new JSONObject(response);
//获取results节点下的位置
Log.d(TAG, "parseJSONResponse: Getting the jsongArray...");
JSONArray resultArray=jsonObject.getJSONArray("results");
Log.d(TAG, "parseJSONResponse: Got the JSONArray...");
if(resultArray.length()>0){
JSONObject subObject=resultArray.getJSONObject(0);
//取出格式化后的位置信息
String address=subObject.getString("formatted_address");
Message message=new Message();
message.what=SHOW_LOCATION;
message.obj="您的位置:"+address;
Log.d(TAG, "showLocation:Sending the inputStream...");
handler.sendMessage(message);
}
}
catch(Exception e){
Log.d(TAG, "parseJSONResponse: something wrong");
e.printStackTrace();
} } }
通用类HttpUtil.java(提供获取Http请求的结果的静态方法 sendHttpRequest)
//HttpUtil.java
//HttpUtil.java package com.example.location; import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import android.content.Context;
import android.util.Log; public class HttpUtil {
private static final String TAG="POSITION";
public static String sendHttpRequest(Context context,String address){
HttpURLConnection connection=null;
try{
URL url=new URL(address);
Log.d(TAG, "HttpUtil: request="+address);
connection=(HttpURLConnection)url.openConnection();
connection.setRequestMethod("GET");
connection.setRequestProperty("Accept-Language", "zh-CN");
connection.setConnectTimeout(8000);
connection.setReadTimeout(8000);
Log.d(TAG, "HttpUtil: getting the inputStream...");
InputStream in=connection.getInputStream();
Log.d(TAG, "HttpUtil: got the inputStream...");
//下面对获取到的流进行读取
BufferedReader reader=new BufferedReader(new InputStreamReader(in));
StringBuilder response=new StringBuilder();
String line;
while((line=reader.readLine())!=null){
response.append(line);
}
Log.d(TAG, "HttpUtil: Got the response...");
return response.toString();
}
catch(Exception e){
e.printStackTrace();
Log.d(TAG, "HttpUtil: Some thing wrong....");
return e.getMessage();
}
finally{
if(connection!=null){
connection.disconnect();
}
}
} }
因为软件使用了位置服务,所以要在Manifest.xml文件中添加使用位置服务的 uses-permission:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
//Location Manifest.xml
//Location Manifest.xml <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.location"
android:versionCode="1"
android:versionName="1.0" > <uses-sdk
android:minSdkVersion="14"
android:targetSdkVersion="21" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> <application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application> </manifest>
但是调试软件的时候,发现HttpUtil.sendHttpRequest() 方法总是在 getInputStream() 那一步出现 Exception。百思终得其解:原来忘记添加使用网络功能的权限了。添加如下:
<uses-permission android:name="android.permission.INTERNET"/>
//Location Manifest.xml
//Location Manifest.xml <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.location"
android:versionCode="1"
android:versionName="1.0" > <uses-sdk
android:minSdkVersion="14"
android:targetSdkVersion="21" />
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> <application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application> </manifest>
现在软件就可以正常运行了。
值得注意的是,这里需要使用Google提供的Geocoding服务,而目前Google的网站一般都还在墙外,手机需要翻墙才能获得Geocoding的功能。恰好自己之前购买了VPN,就先用笔记本电脑连接上VPN,在浏览器中确定可以通过http://maps.googleapis.com/maps/api/geocode/json?latlng=40.714224,-73.961452&sensor=true_or_false这样的地址获取位置服务,然后用笔记本开启WiFi,手机连接上这个开通了VPN的WiFi,就可以使用Geocoding服务了。
Android学习笔记(2)----LocationManager的使用的更多相关文章
- Android 学习笔记之Volley(七)实现Json数据加载和解析...
学习内容: 1.使用Volley实现异步加载Json数据... Volley的第二大请求就是通过发送请求异步实现Json数据信息的加载,加载Json数据有两种方式,一种是通过获取Json对象,然后 ...
- Android学习笔记进阶之在图片上涂鸦(能清屏)
Android学习笔记进阶之在图片上涂鸦(能清屏) 2013-11-19 10:52 117人阅读 评论(0) 收藏 举报 HandWritingActivity.java package xiaos ...
- android学习笔记36——使用原始XML文件
XML文件 android中使用XML文件,需要开发者手动创建res/xml文件夹. 实例如下: book.xml==> <?xml version="1.0" enc ...
- Android学习笔记之JSON数据解析
转载:Android学习笔记44:JSON数据解析 JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,采用完全独立于语言的文本格式,为Web应用开发提供了一种 ...
- udacity android 学习笔记: lesson 4 part b
udacity android 学习笔记: lesson 4 part b 作者:干货店打杂的 /titer1 /Archimedes 出处:https://code.csdn.net/titer1 ...
- Android学习笔记36:使用SQLite方式存储数据
在Android中一共提供了5种数据存储方式,分别为: (1)Files:通过FileInputStream和FileOutputStream对文件进行操作.具体使用方法可以参阅博文<Andro ...
- Android学习笔记之Activity详解
1 理解Activity Activity就是一个包含应用程序界面的窗口,是Android四大组件之一.一个应用程序可以包含零个或多个Activity.一个Activity的生命周期是指从屏幕上显示那 ...
- Pro Android学习笔记 ActionBar(1):Home图标区
Pro Android学习笔记(四八):ActionBar(1):Home图标区 2013年03月10日 ⁄ 综合 ⁄ 共 3256字 ⁄ 字号 小 中 大 ⁄ 评论关闭 ActionBar在A ...
- 【转】Pro Android学习笔记(九八):BroadcastReceiver(2):接收器触发通知
文章转载只能用于非商业性质,且不能带有虚拟货币.积分.注册等附加条件.转载须注明出处:http://blog.sina.com.cn/flowingflying或作者@恺风Wei-傻瓜与非傻瓜 广播接 ...
随机推荐
- shell-012:批量创建用户
# #!/bin/bash # 批量创建用户 # 分析:用命令给用户创建密码的方法有两种 # . 可以直接用echo的方法 # echo "abc-123" |passwd roo ...
- Docker for Windows 启动失败,提示Kubernetes证书无效
起因 部署服务器到一台很久未更新的系统(windows 10),安装docker后,恰好系统自动更新,重启后docker不能启动,提示Kubernetes证书无效(未截到图,抱歉) 排查 因为没有开启 ...
- MySQL 备份数据库
一.数据备份 1.备份一个数据库 mysqldump基本语法: mysqldump -u username -p dbname table1 table2 ...-> BackupName.sq ...
- 【数组】Subsets
题目: Given a set of distinct integers, nums, return all possible subsets. Note: Elements in a subset ...
- Types的Type访问模式
在Types类中定义的访问都类如下: 1.MapVisitor类 2.SimpleVisitor 3.UnaryVisitor 4.TypeRelation
- Oracle练习笔记
1 基本查询 SQL> --当前用户 SQL> show user USER 为 "SCOTT" SQL> --当前用户下的表 SQL> select * ...
- VisualSVN Server提供程序无法执行所尝试的操作 0x80041024
VisualSVN安装后没有提供VisualSVN Server Manager的快捷方式,如下图: 可以在安装目录的bin文件夹下找到VisualSVN Server.msc,添加快捷方式.建议Vi ...
- InnoDB的行记录格式, Compact, Redundant, Compressed, Dynamic
InnoDB存储引擎和大多数数据库一样(如Oracle和Microsoft SQL Server数据库),记录是以行的形式存储的.这意味着页中保存着表中一行行的数据.到MySQL 5.1时,InnoD ...
- Java 中 String 的构造方法
String 对于所有 Java 程序员来说都不会陌生,几乎每天甚至每个程序都会和 String 打交道,因此将 String 的常用知识汇集在此,方便查阅. 概叙: Java 中是如此定义 Stri ...
- 图说超线程技术(Hyper-Threading Technology)
在操作系统中,有多线程(multi-threading)的概念,这很好理解,因为线程是进程最小的调度单位,一个进程至少包含一个线程.本文将介绍CPU特有的超线程技术.简单来说就是,多线程比较软,超线程 ...