10天学安卓-第六天
經過前幾天的學習,我們的天氣預報程序已經可以把天氣正常的呈現出來了,正如之前說的,現在的APP只能顯示固定地區的天氣,那么我們要怎樣才能顯示我們本身所在地的天氣呢?
Android定位
Android系統本身提供了三種定位方式,分別是網絡、基站和GPS,主要利用的是LocationManager、TelephonyManager相關的類庫,但是因為一些原因,Google的API在國內訪問經常出現問題,所以在這里我就不對這些API做介紹了,有想了解的可以自行查詢相關資料。
百度地圖定位
除了Android本身提供的定位功能外,在國內也有很多供我們使用的定位系統,比如百度地圖、高德地圖都提供了相應的功能,我這里主要介紹一下百度地圖的使用方式。
需要到?http://lbsyun.baidu.com/sdk/download?selected=location 下載定位功能的開發包,然后把開發包的內容放到libs文件夾,這樣我們就引入了百度地圖定位功能的API。
然后,開工吧。
?
配置Manifest
首先添加定位功能所需要的權限,還記得添加到哪吧。
<!-- 這個權限用于進行網絡定位 --><uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /><!-- 這個權限用于訪問GPS定位 --><uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /><!-- 用于訪問wifi網絡信息,wifi信息會用于進行網絡定位 --><uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /><!-- 獲取運營商信息,用于支持提供運營商信息相關的接口 --><uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /><!-- 這個權限用于獲取wifi的獲取權限,wifi信息會用來進行網絡定位 --><uses-permission android:name="android.permission.CHANGE_WIFI_STATE" /><!-- 用于讀取手機當前的狀態 --><uses-permission android:name="android.permission.READ_PHONE_STATE" /><!-- 寫入擴展存儲,向擴展卡寫入數據,用于寫入離線定位數據 --><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /><!-- SD卡讀取權限,用戶寫入離線定位數據 --><uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" /><!-- 允許應用讀取低級別的系統日志文件 --><uses-permission android:name="android.permission.READ_LOGS" />?
然后在application節點內,添加一個service,這個service是運行于后臺的獲取定位的服務,
<serviceandroid:name="com.baidu.location.f"android:enabled="true"android:process=":remote" ><intent-filter><action android:name="com.baidu.location.service_v2.2" ></action></intent-filter></service>?
最后,在application節點內,添加我們申請的百度地圖API的Accesskey。
<meta-dataandroid:name="com.baidu.lbsapi.API_KEY"android:value="YknGmxIoPugT7YrNrG955YLS" />?
就這樣,百度地圖的引入就算是完成了。那么如何在代碼中使用?
?
打開MainActivity.java,我們需要簡單重構一下代碼。
你可以使用Eclipse的重構工具,也可以手動修改代碼,修改為如下:
@Overrideprotected void onCreate( Bundle savedInstanceState ){super.onCreate( savedInstanceState );setContentView( R.layout.activity_main );ViewUtils.inject( this );datas = new ArrayList<WeatherDataBean>();adapter = new WeatherAdapter( getApplicationContext(), datas );lstWeather.setAdapter( adapter );getWeather( "北京" );}private void getWeather( String city ){HttpUtils http = new HttpUtils();RequestParams params = new RequestParams();params.addQueryStringParameter( "location", city );params.addQueryStringParameter( "output", "json" );params.addQueryStringParameter( "ak", "YknGmxIoPugT7YrNrG955YLS" );http.send( HttpMethod.GET, "http://api.map.baidu.com/telematics/v3/weather", params, new RequestCallBack<String>(){@Overridepublic void onSuccess( ResponseInfo<String> responseInfo ){String weather = responseInfo.result;Gson gson = new Gson();data = gson.fromJson( weather, BaiduData.class );datas.clear();datas.addAll( data.getResults().get( 0 ).getWeather_data() );adapter.notifyDataSetChanged();Log.v( "onSuccess", data.toString() );}@Overridepublic void onFailure( HttpException arg0, String arg1 ){Log.v( "onFailure", arg1 );}} );}?
?
這里新增加了一個以城市為參數方法getWeather,做好了重構之后,我們加入百度的定位功能。
?
聲明兩個變量:
private LocationClient mLocationClient;private BDLocationListener myListener;?
添加初始化這兩個變量的方法,
private void initLocationClient(){mLocationClient = new LocationClient( getApplicationContext() ); myListener = new MyLocationListener();LocationClientOption option = new LocationClientOption();option.setLocationMode( LocationMode.Hight_Accuracy );option.setIsNeedAddress( true );mLocationClient.setLocOption( option );mLocationClient.registerLocationListener( myListener );}?
我們是用到了MyLocationListener,這個類需要自定義,作為MainActivity的內部類存在,
public class MyLocationListener implements BDLocationListener{@Overridepublic void onReceiveLocation( BDLocation location ){String city = location.getCity();getWeather( city );setTitle( city + "天氣" );}}?
然后,修改onCreate方法,
protected void onCreate( Bundle savedInstanceState ){super.onCreate( savedInstanceState );setContentView( R.layout.activity_main );ViewUtils.inject( this );datas = new ArrayList<WeatherDataBean>();adapter = new WeatherAdapter( getApplicationContext(), datas );lstWeather.setAdapter( adapter );initLocationClient();mLocationClient.start();}?
最后,添加onStop方法,
@Overrideprotected void onStop(){super.onStop();mLocationClient.stop();}?
打完收工。
?
運行吧,看看是怎樣的效果,反正我的是這樣:
?
是不是你所在的城市呢?
?
既然看到效果了,那么稍微解釋一下上面那些代碼。
首先在界面加載的時候,會調用initLocationClient方法,這個方法初始化了LocationClient和BDLocationListener,LocationClient的作用是異步獲取定位,MyLocationListener則是在LocationClient獲取定位后的回調方法,我們在這個回調方法中調用了獲取天氣的方法getWeather,并且調用setTitle方法修改了APP頁面的標題為“城市名+天氣”。
整個流程堪稱完美,只差一點點。
?
這一點點是什么地方呢?
?
就在于我們每一次獲取天氣之前都需要定位,而你是不會每天都換一個城市的,為此我們的程序需要優化一下。優化后的流程為:
1. 從本地讀取城市,并且同時調用百度定位
2. 如果1中的本地城市不為空,則獲取天氣
3. 如果1中百度定位的城市跟本地城市一致,就不再次獲取天氣;若不一致,則覆蓋本地城市,并且重新獲取天氣
這樣做的好處有兩個:
1. 只有第一次啟動APP的時候,本地城市為空,那么就是獲取天氣會比較快
2. 即使更換了城市,也能準確應對
?
既然整理好思路了,那么就開工吧。
?
Android本地存儲數據有多種方式,主要有Preference、Sqlite、File這三種,我們今天使用的是Preference這種方式。
Preference
Preference適合存儲輕量數據,如String、Int、Boolean等類型的數據,我們所需要保存的城市數據就是一個簡單的字符串,非常適合這種方式。
在MainActivity.java 內添加兩個方法,分別為存儲、讀取數據的方法。
private void saveCity( String city ){SharedPreferences sharedPreferences = getSharedPreferences( "weather", Context.MODE_PRIVATE );Editor editor = sharedPreferences.edit();editor.putString( "city", city );editor.commit();}private String readCity(){SharedPreferences sharedPreferences = getSharedPreferences( "weather", Context.MODE_PRIVATE );return sharedPreferences.getString( "city", "" );}?
有些經驗的程序員一眼就能看明白,Preference中是以Key/Value的形式存儲數據的。
?
然后修改onCreate方法,
protected void onCreate( Bundle savedInstanceState ){super.onCreate( savedInstanceState );setContentView( R.layout.activity_main );ViewUtils.inject( this );datas = new ArrayList<WeatherDataBean>();adapter = new WeatherAdapter( getApplicationContext(), datas );lstWeather.setAdapter( adapter );initLocationClient();mLocationClient.start();String city = readCity();if( city != null && city.length() > 0 ){getWeather( city );}}?
這里加入了讀取本地城市,并且獲取天氣的邏輯。
?
接下來修改MyLocationListener,
public class MyLocationListener implements BDLocationListener{@Overridepublic void onReceiveLocation( BDLocation location ){String city = location.getCity();String localCity = readCity();if( !localCity.equals( city ) ){saveCity( city );getWeather( city );}}}?
這里加入了定位的城市和本地城市判斷的邏輯,并且刪掉了對setTitle 方法的調用.
?
最后,修改getWeather方法,在方法第一行加入對setTitle的調用。
setTitle( city + "天氣" );?
打完收工,最后MainActivity.java是這個樣子的:
public class MainActivity extends Activity {@ViewInject( R.id.weather_list )private ListView lstWeather;private WeatherAdapter adapter;private BaiduData data;private List<WeatherDataBean> datas;private LocationClient mLocationClient;private BDLocationListener myListener;@Overrideprotected void onCreate( Bundle savedInstanceState ){super.onCreate( savedInstanceState );setContentView( R.layout.activity_main );ViewUtils.inject( this );datas = new ArrayList<WeatherDataBean>();adapter = new WeatherAdapter( getApplicationContext(), datas );lstWeather.setAdapter( adapter );initLocationClient();mLocationClient.start();String city = readCity();if( city != null && city.length() > 0 ){getWeather( city );}}private void getWeather( String city ){setTitle( city + "天氣" );HttpUtils http = new HttpUtils();RequestParams params = new RequestParams();params.addQueryStringParameter( "location", city );params.addQueryStringParameter( "output", "json" );params.addQueryStringParameter( "ak", "YknGmxIoPugT7YrNrG955YLS" );http.send( HttpMethod.GET, "http://api.map.baidu.com/telematics/v3/weather", params, new RequestCallBack<String>(){@Overridepublic void onSuccess( ResponseInfo<String> responseInfo ){String weather = responseInfo.result;Gson gson = new Gson();data = gson.fromJson( weather, BaiduData.class );datas.clear();datas.addAll( data.getResults().get( 0 ).getWeather_data() );adapter.notifyDataSetChanged();Log.v( "onSuccess", data.toString() );}@Overridepublic void onFailure( HttpException arg0, String arg1 ){Log.v( "onFailure", arg1 );}} );}private void initLocationClient(){mLocationClient = new LocationClient( getApplicationContext() ); // 聲明LocationClient類myListener = new MyLocationListener();LocationClientOption option = new LocationClientOption();option.setLocationMode( LocationMode.Hight_Accuracy );option.setIsNeedAddress( true );mLocationClient.setLocOption( option );mLocationClient.registerLocationListener( myListener );}@Overrideprotected void onStop(){super.onStop();mLocationClient.stop();}public class MyLocationListener implements BDLocationListener{@Overridepublic void onReceiveLocation( BDLocation location ){String city = location.getCity();String localCity = readCity();if( !localCity.equals( city ) ){saveCity( city );getWeather( city );}}}private void saveCity( String city ){SharedPreferences sharedPreferences = getSharedPreferences( "weather", Context.MODE_PRIVATE );Editor editor = sharedPreferences.edit();editor.putString( "city", city );editor.commit();}private String readCity(){SharedPreferences sharedPreferences = getSharedPreferences( "weather", Context.MODE_PRIVATE );return sharedPreferences.getString( "city", "" );} }?
今天的主要任務就是嵌入了百度地圖,重構了代碼,優化了流程,最最重要的是我們學習了SharedPreferences的使用,這種保存數據方式在做APP的時候是經常會用到的,希望大家能熟練掌握。
?
請注意,本文用到的key是我個人使用的,請勿將其用于任何商業用途。如果有商業需要,請聯系我或者自行在百度官網申請Accesskey。
?
附件是本次的工程文件,點擊下載?http://pan.baidu.com/s/1jG9puYU?。
此系列文章系本人原創,如需轉載,請注明出處 www.liuzhibang.cn
?
轉載于:https://www.cnblogs.com/game-over/p/4242058.html
總結
以上是生活随笔為你收集整理的10天学安卓-第六天的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 一个简单问题引发对IEnumerable
- 下一篇: MyBatis 多参数传递