做網(wǎng)站的不給源文件seo關(guān)鍵詞優(yōu)化推廣
前段時間,我在學習鴻蒙應(yīng)用開發(fā)的過程中,在鴻蒙系統(tǒng)的手機上實現(xiàn)了獲取經(jīng)緯度及地理位置描述信息(鴻蒙應(yīng)用開發(fā)學習:手機位置信息進階,從經(jīng)緯度數(shù)據(jù)獲取地理位置描述信息)。反而學習時間更長的安卓應(yīng)用開發(fā)還未實現(xiàn)獲取經(jīng)緯度及地理位置描述。這幾天,我正在看《Android App 開發(fā)進階與項目實戰(zhàn)》一書,正好看到了第9章是講定位導(dǎo)航的。這一章里正好有獲取經(jīng)緯度和詳細地址的內(nèi)容,隨書還附帶有源碼。我照著做,很輕松的實現(xiàn)了用安卓手機獲取經(jīng)緯度和詳細地址的功能。特此記錄以備忘。
(我的安卓手機上實現(xiàn)了獲取經(jīng)緯度和詳細地址)
稍微有點不足的就是,我的手機上顯示的定位類型為 null,而書中顯示的是衛(wèi)星定位。這邊書是幾年前的,基于安卓11的而我的手機系統(tǒng)已經(jīng)是安卓13,可能操作系統(tǒng)的不同,使得同樣的代碼運行效果有所不同吧。
我的這個應(yīng)用中與獲取經(jīng)緯度及詳細地址有關(guān)的代碼如下:
1.獲取經(jīng)緯度及詳細地址的Activity文件
src\main\java\......\LocationPageActivity.java
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;import android.Manifest;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;import com.bahamutjapp.task.GetAddressTask;
import com.bahamutjapp.util.DateUtil;
import com.bahamutjapp.util.SwitchUtil;import java.util.HashMap;
import java.util.Locale;
import java.util.Map;@SuppressLint(value={"DefaultLocale","SetTextI18n"})
public class LocationPageActivity extends AppCompatActivity {private final static String TAG = "myDebug";private Map<String,String> providerMap = new HashMap<>();private TextView tv_location; // 聲明一個文本視圖對象private String mLocationDesc = ""; // 定位說明private LocationManager mLocationMgr; // 聲明一個定位管理器對象private Handler mHandler = new Handler(Looper.myLooper()); // 聲明一個處理器對象private boolean isLocationEnable = false; // 定位服務(wù)是否可用@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_location_page);tv_location = findViewById(R.id.tv_location);providerMap.put("gps", "衛(wèi)星定位");providerMap.put("network", "網(wǎng)絡(luò)定位");SwitchUtil.checkLocationIsOpen(this, "需要打開定位功能才能查看定位信息");}@Overrideprotected void onResume() {super.onResume();mHandler.removeCallbacks(mRefresh); // 移除定位刷新任務(wù)initLocation(); // 初始化定位服務(wù)mHandler.postDelayed(mRefresh, 100); // 延遲100毫秒啟動定位刷新任務(wù)}// 初始化定位服務(wù)private void initLocation() {// 從系統(tǒng)服務(wù)中獲取定位管理器mLocationMgr = (LocationManager) getSystemService(Context.LOCATION_SERVICE);Criteria criteria = new Criteria(); // 創(chuàng)建一個定位準則對象// 設(shè)置定位精確度。Criteria.ACCURACY_COARSE表示粗略,Criteria.ACCURACY_FIN表示精細criteria.setAccuracy(Criteria.ACCURACY_FINE);criteria.setAltitudeRequired(true); // 設(shè)置是否需要海拔信息criteria.setBearingRequired(true); // 設(shè)置是否需要方位信息criteria.setCostAllowed(true); // 設(shè)置是否允許運營商收費criteria.setPowerRequirement(Criteria.POWER_LOW); // 設(shè)置對電源的需求// Log.d(TAG, "初始化定位服務(wù), 準備獲取定位管理器的最佳定位提供者");// 獲取定位管理器的最佳定位提供者String bestProvider = mLocationMgr.getBestProvider(criteria, true);if (mLocationMgr.isProviderEnabled(bestProvider)) { // 定位提供者當前可用tv_location.setText("正在獲取" + providerMap.get(bestProvider) + "對象");mLocationDesc = String.format("【定位信息】\n定位類型為%s", providerMap.get(bestProvider));beginLocation(bestProvider); // 開始定位isLocationEnable = true;} else { // 定位提供者暫不可用tv_location.setText(providerMap.get(bestProvider) + "不可用");isLocationEnable = false;}}// 顯示定位結(jié)果文本private void showLocation(Location location) {if (location != null) {// 創(chuàng)建一個根據(jù)經(jīng)緯度查詢詳細地址的任務(wù)GetAddressTask task = new GetAddressTask(this, location, address -> {String desc = String.format(Locale.CHINESE,"%s" +"\n\t定位時間為%s," + "\n\t經(jīng)度為%f,緯度為%f," +"\n\t高度為%d米,精度為%d米," +"\n\t詳細地址為%s。",mLocationDesc, DateUtil.formatDate(location.getTime()),location.getLongitude(), location.getLatitude(),Math.round(location.getAltitude()), Math.round(location.getAccuracy()),address);tv_location.setText(desc);});task.start(); // 啟動地址查詢?nèi)蝿?wù)} else {tv_location.setText(mLocationDesc + "\n暫未獲取到定位對象");}}// 開始定位private void beginLocation(String method) {// 檢查當前設(shè)備是否已經(jīng)開啟了定位功能if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)!= PackageManager.PERMISSION_GRANTED) {Toast.makeText(this, "請授予定位權(quán)限并開啟定位功能", Toast.LENGTH_SHORT).show();return;}// 設(shè)置定位管理器的位置變更監(jiān)聽器mLocationMgr.requestLocationUpdates(method, 300, 0, mLocationListener);// 獲取最后一次成功定位的位置信息Location location = mLocationMgr.getLastKnownLocation(method);showLocation(location); // 顯示定位結(jié)果文本}// 定義一個位置變更監(jiān)聽器private LocationListener mLocationListener = new LocationListener() {@Overridepublic void onLocationChanged(Location location) {showLocation(location); // 顯示定位結(jié)果文本}@Overridepublic void onProviderDisabled(String arg0) {}@Overridepublic void onProviderEnabled(String arg0) {}@Overridepublic void onStatusChanged(String arg0, int arg1, Bundle arg2) {}};// 定義一個刷新任務(wù),若無法定位則每隔一秒就嘗試定位private Runnable mRefresh = new Runnable() {@Overridepublic void run() {if (!isLocationEnable) {initLocation(); // 初始化定位服務(wù)mHandler.postDelayed(this, 1000);}}};@Overrideprotected void onDestroy() {super.onDestroy();mLocationMgr.removeUpdates(mLocationListener); // 移除定位管理器的位置變更監(jiān)聽器}}
2.Activity文件對應(yīng)的xml文件
src\main\res\layout\activity_location_page.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".LocationPageActivity"><TextViewandroid:id="@+id/tv_locationTitle"android:layout_width="wrap_content"android:layout_height="30dp"android:text="定位導(dǎo)航"android:textSize="24sp"android:textStyle="bold"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent" /><TextViewandroid:id="@+id/tv_location"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginStart="10dp"android:layout_marginTop="50dp"android:layout_marginEnd="10dp"android:paddingStart="10dp"android:paddingEnd="10dp"android:text="【定位信息】"android:textSize="16sp"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toBottomOf="@+id/tv_locationTitle" /></androidx.constraintlayout.widget.ConstraintLayout>
3.GetAddressTask.java文件(此文件根據(jù)經(jīng)緯度數(shù)據(jù)獲取詳細地址信息)
src\main\java\......\task\GetAddressTask.java
import android.app.Activity;
import android.location.Location;
import android.util.Log;
import android.widget.Toast;import androidx.annotation.NonNull;import org.json.JSONException;
import org.json.JSONObject;import java.io.IOException;
import java.util.Objects;import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;// 根據(jù)經(jīng)緯度獲取詳細地址的線程
public class GetAddressTask extends Thread {private static final String TAG = "GetAddressTask";private String mQueryUrl = "https://api.tianditu.gov.cn/geocoder?postStr={'lon':%f,'lat':%f,'ver':1}&type=geocode&tk=253b3bd69713d4bdfdc116255f379841";private Activity mAct; // 聲明一個活動實例private OnAddressListener mListener; // 聲明一個獲取地址的監(jiān)聽器對象private Location mLocation; // 聲明一個定位對象public GetAddressTask(Activity act, Location location, OnAddressListener listener) {mAct = act;mListener = listener;mLocation = location;}@Overridepublic void run() {String url = String.format(mQueryUrl, mLocation.getLongitude(), mLocation.getLatitude());Log.d(TAG, "url="+url);OkHttpClient client = new OkHttpClient(); // 創(chuàng)建一個okhttp客戶端對象// 創(chuàng)建一個GET方式的請求結(jié)構(gòu)Request request = new Request.Builder().url(url).build();Call call = client.newCall(request); // 根據(jù)請求結(jié)構(gòu)創(chuàng)建調(diào)用對象// 加入HTTP請求隊列。異步調(diào)用,并設(shè)置接口應(yīng)答的回調(diào)方法call.enqueue(new Callback() {@Overridepublic void onFailure(@NonNull Call call, @NonNull IOException e) { // 請求失敗// 回到主線程操縱界面mAct.runOnUiThread(() -> Toast.makeText(mAct,"查詢詳細地址出錯:"+e.getMessage(), Toast.LENGTH_SHORT).show());}@Overridepublic void onResponse(@NonNull Call call, @NonNull final Response response) throws IOException { // 請求成功String resp = Objects.requireNonNull(response.body()).string();Log.d(TAG, "resp="+resp);// 下面從json串中逐級解析formatted_address字段獲得詳細地址描述try {JSONObject obj = new JSONObject(resp);JSONObject result = obj.getJSONObject("result");String address = result.getString("formatted_address");// 回到主線程操縱界面mAct.runOnUiThread(() -> mListener.onFindAddress(address));} catch (JSONException e) {e.printStackTrace();}}});}// 定義一個查詢詳細地址的監(jiān)聽器接口public interface OnAddressListener {void onFindAddress(String address);}}
4.DateUtil.java文件(對日期數(shù)據(jù)進行格式化)
src\main\java\......\util\DateUtil.java
import android.annotation.SuppressLint;import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;@SuppressLint("SimpleDateFormat")
public class DateUtil {// 獲取當前的日期時間public static String getNowDateTime() {SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");return sdf.format(new Date());}// 將長整型的時間數(shù)值格式化為日期時間字符串public static String formatDate(long time) {Date date = new Date(time);SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");return sdf.format(date);}}
5.SwitchUtil.java文件(獲取定位功能開關(guān)狀態(tài))
src\main\java\......\util\SwitchUtil.java
import android.content.Context;
import android.content.Intent;
import android.location.LocationManager;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.wifi.WifiManager;
import android.provider.Settings;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.widget.Toast;import java.lang.reflect.Method;public class SwitchUtil {private static final String TAG = "SwitchUtil";// 獲取定位功能的開關(guān)狀態(tài)public static boolean getLocationStatus(Context ctx) {// 從系統(tǒng)服務(wù)中獲取定位管理器LocationManager lm = (LocationManager) ctx.getSystemService(Context.LOCATION_SERVICE);return lm.isProviderEnabled(LocationManager.GPS_PROVIDER);}// 檢查定位功能是否打開,若未打開則跳到系統(tǒng)的定位功能設(shè)置頁面public static void checkLocationIsOpen(Context ctx, String hint) {if (!getLocationStatus(ctx)) {Toast.makeText(ctx, hint, Toast.LENGTH_SHORT).show();Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);ctx.startActivity(intent);}}}
6月25日補充:
今天代碼進一步研究發(fā)現(xiàn)導(dǎo)致頁面上定位類型顯示為null的原因是在LocationPageActivity.java文件中的源代碼“ String bestProvider = mLocationMgr.getBestProvider(criteria, true); ” 的返回值是“fused”。通過搜尋資料,才知道這是一種定位類型(融合定位),介紹資料見下面的鏈接:
Fused定位
再對代碼進行仔細研究,發(fā)現(xiàn)上面的代碼的返回值賦值給“bestProvider”后,通過執(zhí)行以下語句獲取在頁面上顯示定位類型的字符串:
mLocationDesc = String.format("【定位信息】\n\t定位類型為%s", providerMap.get(bestProvider));
?這個語句是將“bestProvider”作為參數(shù)從providerMap對象中獲取對應(yīng)的值。而providerMap對象是在onCreate方法中賦值的:
providerMap.put("gps", "衛(wèi)星定位");
providerMap.put("network", "網(wǎng)絡(luò)定位");
因為只put了兩個鍵值對,沒有fused的鍵值對,因此得到的結(jié)果是null。解決方法就是再加入下面這條即可。
providerMap.put("fused", "融合");