demo基于百度定位APIv4.0版、新浪天气(不用查询城市代码)。
需求:
1、button实现触发定位监听和天气捕获
2、两个textview 分别显示详细地址、天气。
界面很简陋,侧重功能实现。
下面记录下主要技术点:
1.百度定位
/**
* 发起定位
*/
public void requestLocationInfo() {
setLocationOption(); if (mLocationClient != null && !mLocationClient.isStarted()) {
mLocationClient.start();
} if (mLocationClient != null && mLocationClient.isStarted()) {
mLocationClient.requestLocation();
}
} /**
* 设置相关参数
*/
private void setLocationOption() {
LocationClientOption option = new LocationClientOption();
option.setOpenGps(true); // 打开gps
option.setCoorType("bd09ll"); // 设置坐标类型
option.setServiceName("com.baidu.location.service_v2.9");
option.setPoiExtraInfo(true);
option.setAddrType("all");
option.setPoiNumber(10);
option.disableCache(true);
mLocationClient.setLocOption(option);
} /**
* 监听函数,有更新位置的时候,格式化成字符串,输出到屏幕中
*/
public class MyLocationListenner implements BDLocationListener {
@Override
public void onReceiveLocation(BDLocation location) {
if (location == null) {
sendBroadCast(new ParcelableInfo("获取失败","获取失败"));
return;
} address=location.getAddrStr();
} public void onReceivePoi(BDLocation poiLocation) {
if (poiLocation == null) {
sendBroadCast(new ParcelableInfo("获取失败","获取失败"));
return;
}
sendBroadCast(new ParcelableInfo(poiLocation.getDistrict(),poiLocation.getAddrStr()));
} }
2.异步获取天气信息
异步多线程一般处理方式有;1.handler处理:
handler异步多线程执行步骤(非UI线程发送消息到UI线程分为3个步骤)
1.message.sendToTarget()方法把这条message放到消息队列中去。
Runnable runnable = new Runnable()
{
@Override
public void run() {// run()在新的线程中运行 sb.append("\nweather:"); sb.append(new GetWeather().getWeather(
location.getDistrict().substring(0, location.getDistrict().length()
- 1)) .getSuggestion());//获取基本出行建议
mHandler.obtainMessage(MSG_SUCCESS, sb.toString())
.sendToTarget();// 获取成功,将定位信息和异步获取的出行建议存入messagem,向ui线程发送
}
};
2.定义更新UI
private Handler mHandler = new Handler() {
public void handleMessage(Message msg) {// 此方法在ui线程运行
switch (msg.what) {
case MSG_SUCCESS:
logMsg((String) msg.obj);//根据第一步发送来的message的信息,将msg.obj(定位信息和出行信息)显示在textview中。
break;
default:
logMsg("查询失败");
break;
}
}
};
3.在主线程中启动thread
if (mThread == null) {
mThread = new Thread(runnable);
mThread.start();// 线程启动
}
2、AsyncTask:AsyncTask能够更恰当和更简单的去使用UI线程。这个类允许执行后台操作和展现结果在UI线程上,无需操纵线程和/或处理程序。AsyncTask的内部实现是一个线程池,每个后台任务会提交到线程池中的线程执行,然后使用Thread+Handler的方式调用回调函数。
使用AsyncTask类,以下是几条必须遵守的准则:
1) Task的实例必须在UI thread中创建
2) execute方法必须在UI thread中调用
3) 不要手动的调用onPreExecute(), onPostExecute(Result),doInBackground(Params...), onProgressUpdate(Progress...)这几个方法
4) 该task只能被执行一次,否则多次调用时将会出现异常
doInBackground方法和onPostExecute的参数必须对应,这两个参数在AsyncTask声明的泛型参数列表中指定,第一个为doInBackground接受的参数,第二个为显示进度的参数,第第三个为doInBackground返回和onPostExecute传入的参数。
关键代码1(传递 单一String 字段):
package com.liucanwen.baidulocation;
/*
* 异步多线程加载网络信息,并更新UI
* 通常有两种方法:1、handler和Threat
* 2、AsyncTask
* 参考网址 http://www.cnblogs.com/dawei/archive/2011/04/18/2019903.html
*/ import java.net.URL; import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory; import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList; import com.liucanwen.baidulocation.util.UTF82GBK;
import com.liucanwen.baidulocation.util.Weather; import android.os.AsyncTask;
import android.widget.TextView; public class LoadWeatherAsyncTask extends AsyncTask<Object, Integer, String> { private TextView tv; String getweather; //表明对哪个textview进行异步更新
public LoadWeatherAsyncTask(TextView tv) {
this.tv = tv;
} //准备工作,一般初始化textview
@Override
protected void onPreExecute() { } @Override
protected String doInBackground(Object... params) {
return new Weather().getWeather((String)params[0]);//真正的异步工作,从服务器获取xml数据并解析,但不能对UI操作 } protected void onPostExecute(String result) {
// 该方法运行在UI线程内,更新UI
tv.setText(result); } }
UI主线程调用
//注意:1)LoadWeatherAsyncTask 的实例必须在UI thread中创建 2) execute方法必须在UI thread中调用
LoadWeatherAsyncTask lwa = new LoadWeatherAsyncTask(weatherInfo);
//将parcelableInfo.getCity()变量传入LoadWeatherAsyncTask.java中doInBackground方法中
lwa.execute(parcelableInfo.getCity());
附:传递JavaBean对象
public class LoadWeatherAsyncTask extends AsyncTask<Object, Integer, WeatherInfo> { private TextView tv; //表明对哪个textview进行异步更新
public LoadWeatherAsyncTask(TextView tv) {
this.tv = tv;
} //准备工作,一般初始化textview
@Override
protected void onPreExecute() { } //注意:1) Task的实例必须在UI thread中创建 2) execute方法必须在UI thread中调用 )
@Override
protected WeatherInfo doInBackground(Object... params) {
// TODO Auto-generated method stub
System.out.println((String)params[0]);
return new GetWeather().getWeather((String)params[0]);//该处返回的结果作为onPostExecute(WeatherInfo result)的rusult参数
} protected void onPostExecute(WeatherInfo result) { // 该方法运行在UI线程内 tv.setText(result.getSuggestion()); } }
3.困扰好几天的编码问题导致返回天气数据为null
由于之前直接将“广州“的UTF8编码传入URL(ADT默认编码UTF8)导致获取不到天气数据,
URL ur = new URL("http://php.weather.sina.com.cn/xml.php?city="
+ str+ "&password=DJOYnieT8234jlsK&day=" + day);
后来发现,传入的str需要为GB2312编码数据。所以需要转码
new UTF82GBK().getCoding(str)
public String getCoding(String str) throws IOException{
String s1 = URLEncoder.encode(str, "gb2312");
return s1;
}
public String getWeather(String str) {
try {
DocumentBuilderFactory domfac = DocumentBuilderFactory
.newInstance();
DocumentBuilder dombuilder = domfac.newDocumentBuilder();
Document doc;
Element root;
NodeList books; // 浏览器中识别的是GBK编码,直接输入汉字是接收不到数据的
URL ur = new URL("http://php.weather.sina.com.cn/xml.php?city="
+ new UTF82GBK().getCoding(str)
+ "&password=DJOYnieT8234jlsK&day=" + day);
// 解析XML
doc = (Document) dombuilder.parse(ur.openStream());
root = (Element) doc.getDocumentElement();
books = ((Node) root).getChildNodes();
for (Node node = books.item(1).getFirstChild(); node != null; node = node
.getNextSibling()) {
if (node.getNodeType() == Node.ELEMENT_NODE) {
if (node.getNodeName().equals("status1"))
weather = node.getTextContent(); // 获取天气状况
else if (node.getNodeName().equals("temperature1"))
high = node.getTextContent(); // 获取最高温度
else if (node.getNodeName().equals("temperature2"))
low = node.getTextContent(); // 获取最低温度
}
}
} catch (Exception e) {
e.getMessage();
}
String getweather = str + " " + weather + " " + low + "度~" + high + "度";
return getweather;
}
4.Intent传递对象
需要从传入MyApplication将City和address传入到MainActivity中,将需要传递的数据封装到LocationInfo类中。
使用intent传递对象的方法有两种:
1、实现Serializable接口
2、实现Parcelable接口
我采用 实现Parcelable接口:
LocationInfo .java用于确定传递数据的数据模型
public class LocationInfo implements Serializable {
private String city;
private String address; public String getCity() {
return city;
} public void setCity(String city) {
this.city = city;
} public String getAddress() {
return address;
} public void setAddress(String address) {
this.address = address;
} }
/**
* 实现了Parcelable接口的ParcelableInfo类:
*/
import android.os.Parcel;
import android.os.Parcelable; public class ParcelableInfo implements Parcelable {
private String city;
private String address; public ParcelableInfo() {
} public ParcelableInfo(String city, String address) {
this.city = city;
this.address = address;
} public String getCity() {
return city;
} public void setCity(String city) {
this.city = city;
} public String getAddress() {
return address;
} public void setAddress(String address) {
this.address = address;
} public static final Parcelable.Creator<ParcelableInfo> CREATOR = new Creator<ParcelableInfo>() {
@Override
public ParcelableInfo createFromParcel(Parcel source) {
ParcelableInfo parcelableInfo = new ParcelableInfo();
parcelableInfo.city = source.readString();
parcelableInfo.address = source.readString();
return parcelableInfo;
} @Override
public ParcelableInfo[] newArray(int size) {
return new ParcelableInfo[size];
}
}; @Override
public int describeContents() {
// TODO Auto-generated method stub
return 0;
} @Override
public void writeToParcel(Parcel dest, int flags) {
// TODO Auto-generated method stub
dest.writeString(city);
dest.writeString(address);
} }
public void sendBroadCast(ParcelableInfo parcelableInfo) {
stopLocationClient(); Intent intent = new Intent(MainActivity.LOCATION_BCR);
//ParcelableInfo parcelableUser = new ParcelableInfo(city,address);
//intent.putExtra("address", address);
Bundle bundle = new Bundle();
bundle.putParcelable("parcelableInfo", parcelableInfo);
intent.putExtras(bundle);
sendBroadcast(intent);
}
在MyApplication中发送
public void sendBroadCast(ParcelableInfo parcelableInfo) {
stopLocationClient(); Intent intent = new Intent(MainActivity.LOCATION_BCR); Bundle bundle = new Bundle();
bundle.putParcelable("parcelableInfo", parcelableInfo); //将parcelableInfo对象封装在bundle中
intent.putExtras(bundle); //intent传递bundle
sendBroadcast(intent);
}
在MainActivity中接收
parcelableInfo = intent.getParcelableExtra("parcelableInfo");
locInfo.setText("你所在的地址为:" + parcelableInfo.getAddress());
5.获取和XML解析和JSON解析
a.JSON
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder; import org.json.JSONException;
import org.json.JSONObject; public class GetWeather { String StrUrl;
public WeatherInfo getWeather(String cityName)
{
StringBuffer strBuf = new StringBuffer();
WeatherInfo weatherInfo=new WeatherInfo(); //访问URL获取JSON
String StrUrl = null;
try {
StrUrl = "http://api.map.baidu.com/telematics/v3/weather?location="+URLEncoder.encode(cityName, "utf-8")+"&output=json&ak=NtQaBbYDC2kn89KENQhFM2o5";
} catch (UnsupportedEncodingException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} System.out.println(StrUrl); try{
URL url=new URL(StrUrl);
URLConnection conn = url.openConnection();
BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream(),"utf-8"));//转码。
String line = null;
while ((line = reader.readLine()) != null)
strBuf.append(line);
reader.close();
}catch(Exception e){
e.printStackTrace();
} String getStr=strBuf.toString();
System.out.println("JSON数据打印: "+getStr); try{
// 将json字符串转换为json对象
JSONObject jsonObj = new JSONObject(getStr);
// 得到指定json key对象的value对象 //获取当前城市
JSONObject mainArr=jsonObj.getJSONArray("results").getJSONObject(0);
weatherInfo.setCity(mainArr.getString("currentCity")); //获取PM2.5信息
weatherInfo.setPM25(mainArr.getString("pm25")); JSONObject weatherData=jsonObj.getJSONArray("results").getJSONObject(0).getJSONArray("weather_data").getJSONObject(0);
//获取实时时间
weatherInfo.setTime(weatherData.getString("date"));
// 获取基本天气属性simpleweather
weatherInfo.setSimpleweather(weatherData.getString("weather"));
//获取温度
weatherInfo.setTemperature(weatherData.getString("temperature"));
//获取出行建议
JSONObject weatherSuggetion=jsonObj.getJSONArray("results").getJSONObject(0).getJSONArray("index").getJSONObject(0);
weatherInfo.setSuggestion(weatherSuggetion.getString("des"));
}catch (JSONException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
return weatherInfo;
}
}
b.xml(也可以返回javaBean对象,这里只考虑返回String变量)
import java.net.URL; import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory; import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList; public class Weather { static int[] day = { 0, 1, 2, 3, 4 };
static String weather;
static String high;
static String low;
int SECCESS = 1;
int FAIL = 0; public String getWeather(String str) {
try {
DocumentBuilderFactory domfac = DocumentBuilderFactory
.newInstance();
DocumentBuilder dombuilder = domfac.newDocumentBuilder();
Document doc;
Element root;
NodeList books; // 浏览器中识别的是GBK编码,直接输入汉字是接收不到数据的
URL ur = new URL("http://php.weather.sina.com.cn/xml.php?city="
+ new UTF82GBK().getCoding(str)
+ "&password=DJOYnieT8234jlsK&day=" + day);
// 解析XML
doc = (Document) dombuilder.parse(ur.openStream());
root = (Element) doc.getDocumentElement();
books = ((Node) root).getChildNodes();
for (Node node = books.item(1).getFirstChild(); node != null; node = node
.getNextSibling()) {
if (node.getNodeType() == Node.ELEMENT_NODE) {
if (node.getNodeName().equals("status1"))
weather = node.getTextContent(); // 获取天气状况
else if (node.getNodeName().equals("temperature1"))
high = node.getTextContent(); // 获取最高温度
else if (node.getNodeName().equals("temperature2"))
low = node.getTextContent(); // 获取最低温度
}
}
} catch (Exception e) {
e.getMessage();
}
String getweather = str + " " + weather + " " + low + "度~" + high + "度";
return getweather;
}
}
本人初学上路,语言表达不准确,见谅···
第一版XML源码地址:http://download.csdn.net/detail/xiejun1026/8411437
第二版JSON源码下载地址:http://download.csdn.net/detail/xiejun1026/8413329