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