編輯:關於Android編程
上接前兩篇,要自己去讀取什麼CellId,LocationAreaCode, MobileCountryCode,MobileNetworkCode等參數,而且多數是針對GSM/UMTS。而自己使用的CDMA,跟上面的參數叫法不一樣,還得自己一個一個去對應。雖然最後算是解決了,但是難道就沒有更好的辦法嗎。
翻了翻Android Developer找到一個不錯的東西LocationManager。LocationManager是通過listener的方式來告知調用者,而原來寫好的模塊是直接return的,於是得稍微改造一下:
首先定義一個Model:
- public class LocationData {
- String lat;
- String lon;
- String address;
- }
然後LBS的所有功能都封裝到一個工具類裡面:
首先在構造函數裡面獲取系統服務中的LocationManager:
- public class LBSTool {
- private Context mContext;
- private LocationManager mLocationManager;
- private LocationData mLocation;
- private LBSThread mLBSThread;
- private MyLocationListner mNetworkListner;
- private MyLocationListner mGPSListener;
- private Looper mLooper;
- public LBSTool(Context context) {
- mContext = context;
- //獲取Location manager
- mLocationManager = (LocationManager)mContext.getSystemService(Context.LOCATION_SERVICE);
- }
- ......
- }
然後是入口方法,這裡會啟動一個子線程去獲取地理位置信息,並讓主線程進入等待,時長通過timeout設置
- /**
- * 開始定位
- * @param timeout 超時設置
- * @return LocationData位置數據,如果超時則為null
- */
- public LocationData getLocation(long timeout) {
- mLocation = null;
- mLBSThread = new LBSThread();
- mLBSThread.start();//啟動LBSThread
- timeout = timeout > 0 ? timeout : 0;
- synchronized (mLBSThread) {
- try {
- Log.i(Thread.currentThread().getName(), "Waiting for LocationThread to complete...");
- mLBSThread.wait(timeout);//主線程進入等待,等待時長timeout ms
- Log.i(Thread.currentThread().getName(), "Completed.Now back to main thread");
- }
- catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- mLBSThread = null;
- return mLocation;
- }
子線程通過調用registerLocationListener開啟位置服務的監聽,並且講監聽器分配給指定looper
- private class LBSThread extends Thread {
- @Override
- public void run() {
- setName("location thread");
- Log.i(Thread.currentThread().getName(), "--start--");
- Looper.prepare();//給LBSThread加上Looper
- mLooper = Looper.myLooper();
- registerLocationListener();
- Looper.loop();
- Log.e(Thread.currentThread().getName(), "--end--");
- }
- }
- private void registerLocationListener () {
- Log.i(Thread.currentThread().getName(), "registerLocationListener");
- if (isGPSEnabled()) {
- mGPSListener=new MyLocationListner();
- //五個參數分別為位置服務的提供者,最短通知時間間隔,最小位置變化,listener,listener所在消息隊列的looper
- mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 5000, 0, mGPSListener, mLooper);
- }
- if (isNetworkEnabled()) {
- mNetworkListner=new MyLocationListner();
- mLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 3000, 0, mNetworkListner, mLooper);
- }
- }
isGPSEnabled和isNetworkEnabled分別為判斷當前手機是否開啟了GPS以及網絡的狀況(包含了是否開啟wifi和移動網絡),以決定使用哪一種服務提供者:GPS_PROVIDER或者NETWORK_PROVIDER。
- /**
- * 判斷GPS是否開啟
- * @return
- */
- public boolean isGPSEnabled() {
- if(mLocationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
- Log.i(Thread.currentThread().getName(), "isGPSEnabled");
- return true;
- }
- else {
- return false;
- }
- }
- /**
- * 判斷Network是否開啟(包括移動網絡和wifi)
- * @return
- */
- public boolean isNetworkEnabled() {
- return (isWIFIEnabled() || isTelephonyEnabled());
- }
- /**
- * 判斷移動網絡是否開啟
- * @return
- */
- public boolean isTelephonyEnabled() {
- boolean enable = false;
- TelephonyManager telephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
- if (telephonyManager != null) {
- if (telephonyManager.getNetworkType() != TelephonyManager.NETWORK_TYPE_UNKNOWN) {
- enable = true;
- Log.i(Thread.currentThread().getName(), "isTelephonyEnabled");
- }
- }
- return enable;
- }
- /**
- * 判斷wifi是否開啟
- */
- public boolean isWIFIEnabled() {
- boolean enable = false;
- WifiManager wifiManager = (WifiManager)mContext.getSystemService(Context.WIFI_SERVICE);
- if(wifiManager.isWifiEnabled()) {
- enable = true;
- Log.i(Thread.currentThread().getName(), "isWIFIEnabled");
- }
- return enable;
- }
當LocationManager在大於最短時間且檢測到最小位置變化時,就會通知給監聽器,然後我們就可以通過返回的經緯度信息去google服務器查找對應的地址,然後停止LocationManger的工作,解除LBSThread中的Looper,讓LBSThread結束,最後通知主線程可以繼續,整個流程結束。
- private class MyLocationListner implements LocationListener{
- @Override
- public void onLocationChanged(Location location) {
- // 當LocationManager檢測到最小位置變化時,就會回調到這裡
- Log.i(Thread.currentThread().getName(), "Got New Location of provider:"+location.getProvider());
- unRegisterLocationListener();//停止LocationManager的工作
- try {
- synchronized (mLBSThread) {
- parseLatLon(location.getLatitude()+"", location.getLongitude()+"");//解析地理位置
- mLooper.quit();//解除LBSThread的Looper,LBSThread結束
- mLBSThread.notify();//通知主線程繼續
- }
- }
- catch (Exception e) {
- e.printStackTrace();
- }
- }
- //後3個方法此處不做處理
- @Override
- public void onStatusChanged(String provider, int status, Bundle extras) {}
- @Override
- public void onProviderEnabled(String provider) {}
- @Override
- public void onProviderDisabled(String provider) {}
- };
- /**
- * 使用經緯度從goole服務器獲取對應地址
- * @param 經緯度
- */
- private void parseLatLon(String lat, String lon) throws Exception {
- Log.e(Thread.currentThread().getName(), "---parseLatLon---");
- Log.e(Thread.currentThread().getName(), "---"+lat+"---");
- try {
- HttpClient httpClient = new DefaultHttpClient();
- HttpGet get = new HttpGet("http://ditu.google.cn/maps/geo?output=json&q="+lat+","+lon);
- HttpResponse response = httpClient.execute(get);
- String resultString = EntityUtils.toString(response.getEntity());
- JSONObject jsonresult = new JSONObject(resultString);
- if(jsonresult.optJSONArray("Placemark") != null) {
- mLocation = new LocationData();
- mLocation.lat = lat;
- mLocation.lon = lon;
- mLocation.address = jsonresult.optJSONArray("Placemark").optJSONObject(0).optString("address");
- }
- }
- catch (Exception e) {
- e.printStackTrace();
- }
- }
- /**
- * 注銷監聽器
- */
- private void unRegisterLocationListener () {
- if(mGPSListener!=null){
- mLocationManager.removeUpdates(mGPSListener);
- mGPSListener=null;
- }
- if(mNetworkListner!=null){
- mLocationManager.removeUpdates(mNetworkListner);
- mNetworkListner=null;
- }
- }
接下來可以在界面上安放個button:
- locationBtn.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- //return mode
- LBSTool lbs = new LBSTool(LBStestActivity.this);
- LocationData location = lbs.getLocation(120000);
- if (location != null) {
- Log.i("---lat---",location.lat);
- Log.i("---lon---",location.lon);
- Log.i("---address---",location.address);
- Toast.makeText(LBStestActivity.this, location.lat + " " + location.lon + " " + location.address, Toast.LENGTH_LONG).show();
- }
- }
- });
最後別忘了加入權限:
此外,LocationManager還有些高級的用法,比如設置一些關鍵參數,以及獲取最後一次定位信息等等:
- Criteria criteria = new Criteria();
- criteria.setAccuracy(Criteria.ACCURACY_FINE); // 高精度
- criteria.setAltitudeRequired(false);
- criteria.setBearingRequired(false);
- criteria.setCostAllowed(true);
- criteria.setPowerRequirement(Criteria.POWER_LOW); // 低功耗
- String bestprovider = locationManager.getBestProvider(criteria, true); // 獲取GPS信息
- Location location = locationManager.getLastKnownLocation(bestprovider); // 通過GPS獲取位置
- Log.e("--bestprovider--", bestprovider);
- Log.e("--bestprovider--", location.getLatitude()+"");
前言別看本文看上去很簡單,實際在實驗過程中遇到了很多問題,比如andorid studio下ndk編譯報錯,而本文呈現給大家的都是最終可行的方法.所需資源bzip2 bs
導論 本文著重講解Android3.0後推出的屬性動畫框架Property Animation——Animator。
?之前一段時間,我都在研究Android自定義View的相關知識,隨著逐漸的深入,漸漸了解到了一些Android圖像處理的知識,主要是Bitmap,Canvas,Shad
滾輪選擇控件Android自帶的選擇時間控件有點丑,往往產品和設計都比較嫌棄,希望做成ios一樣的滾輪選擇,下面是我在NumberPicker的基礎上自定義的選擇控件,效