在Android中获取用户位置

获取用户在Android中的位置可以通过以下步骤完成:

1. 在渐变中添加依赖关系

在生成.gradle(应用)文件中添加以下依赖项:

dependencies {
    implementation 'com.google.android.gms:play-services-location:19.0.0'
}

获取用户权限

可以使用以下任何权限:
(在 Android 清单中添加这些权限.xml文件)

ACCESS_COARSE_LOCATION:它提供城市街区内的位置精度

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>

ACCESS_FINE_LOCATION:它提供了更准确的位置

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

ACCESS_BACKGROUND_LOCATION:如果应用需要在后台运行时访问用户的位置,我们需要将此权限与上述权限一起添加

<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />

📌 准确性

安卓系统支持以下级别的定位精度:

近似
提供设备位置的估计值,在大约1.6 公里内。当您声明ACCESS_COARSE_LOCATION权限而不是ACCESS_FINE_LOCATION权限时,您的应用将使用此级别的位置准确性。

精确
提供尽可能准确的设备位置估计值,通常在大约 160 英尺(50 米)以内,有时精确到 10 英尺(几米)或更好。你的应用在声明ACCESS_FINE_LOCATION权限时使用此级别的位置准确性。

注意:

在 Android 12(API 级别 31)或更高版本上,用户可以请求您的应用仅检索大致的位置信息,即使您的应用请求ACCESS_FINE_LOCATION运行时权限也是如此。

若要处理此潜在用户行为,请不要自行请求ACCESS_FINE_LOCATION权限。相反,请在单个运行时请求中同时请求ACCESS_FINE_LOCATION权限和ACCESS_COARSE_LOCATION权限。如果您尝试仅请求ACCESS_FINE_LOCATION,系统将忽略某些版本的 Android 12 上的请求。

如果您的应用以 Android 12 或更高版本为目标平台,系统会在 Logcat 中记录以下错误消息:

ACCESS_FINE_LOCATION must be requested with ACCESS_COARSE_LOCATION

当你的应用同时请求ACCESS_FINE_LOCATION和ACCESS_COARSE_LOCATION时,系统权限对话框将包含以下用户选项:

精确:这允许你的应用获取精确的位置信息。
近似值:这允许你的应用仅获取近似位置信息。

设计布局

创建文本视图以在屏幕上显示用户的纬度和经度

<?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=".MainActivity">

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="Location here"
        android:textSize="24sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

逻辑

我们将逻辑写入主活动文件中。在我的情况下,它是主要活动.java。

创建一些基本变量:
位置对象以存储用户的位置,
FusedLocationProvider客户端对象以获取位置,整数请求代码用于权限,TextView对象用于向用户显示提取的位置

还创建了一个用于获取位置的提取位置函数。

它实际上是一种位置服务,结合了GPS定位和网络定位,以实现电池消耗和准确性之间的平衡。GPS 位置用于提供精度,网络位置用于在用户处于室内时获取位置。

public class MainActivity extends AppCompatActivity {
    Location currentLocation;
    FusedLocationProviderClient fusedLocationProviderClient;
    private static final int REQUEST_CODE = 101;
    TextView textView;

    @RequiresApi(api = Build.VERSION_CODES.N)
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView = findViewById(R.id.textView);

        fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this);
        fetchLocation();
    }
}

所需的权限包括:

  • Manifest.permission.ACCESS_COARSE_LOCATION
  • Manifest.permission.ACCESS_FINE_LOCATION
String[] LocationPermissions = new String[]{Manifest.permission.ACCESS_COARSE_LOCATION,
                                        Manifest.permission.ACCESS_FINE_LOCATION};

提取位置的逻辑可以如下:

  1. 检查我们请求的权限是否已启用。
  2. 如果未启用,请请求权限。
  3. 如果接受权限并启用位置,请获取用户的最后一个位置
@RequiresApi(api = Build.VERSION_CODES.N)
private void fetchLocation() {
        // Check for permissions
        if (ActivityCompat.checkSelfPermission
                (this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
                ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            // Request for permissions
            ActivityCompat.requestPermissions(
                    this, LocationPermissions, REQUEST_CODE);
            return;
        } else if (ActivityCompat.shouldShowRequestPermissionRationale(this,Manifest.permission.ACCESS_FINE_LOCATION)) {
            Toast.makeText(this, "Location cannot be determined", Toast.LENGTH_SHORT).show();
            // Request for permissions
            ActivityCompat.requestPermissions(
                    this, LocationPermissions, REQUEST_CODE);
        }

        // Getting last location from Fused Location Provider Client Object
        fusedLocationProviderClient.getLastLocation().
                addOnCompleteListener(new OnCompleteListener<Location>() {
                    @Override
                    public void onComplete(@NonNull Task<Location> task) {
                        Location location = task.getResult();
                        if (location == null) {
                            requestNewLocationData();
                        } else {
                            currentLocation = location;
                            textView.setText("Latitude:"+currentLocation.getLatitude()+"\nLongitude:"+currentLocation.getLongitude());
                        }
                    }
                });
 }

OnRequest权限结果 :

@RequiresApi(api = Build.VERSION_CODES.N)
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == REQUEST_CODE) {
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                fetchLocation();
            }
            else {
                // Permission not granted
                Toast.makeText(this, "Location cannot be determined", Toast.LENGTH_SHORT).show();
                currentLocation=null;
            }
        }
 }

正如在上面的 fetchLocation 方法中看到的,如果由 fused 位置获取的位置提供者客户端.getLastLocation() 为空,我们请求新的位置数据,从而创建一个名为 requestNewLocationData() 的方法

fusedLocationProviderClient.getLastLocation().
        addOnCompleteListener(new OnCompleteListener<Location>() {
            @Override
            public void onComplete(@NonNull Task<Location> task) {
                Location location = task.getResult();
                if (location == null) {
                    requestNewLocationData(); // Here
                } else {
                   // .....
                }
            }

RequestNewLocationData()

现在将请求新的位置数据方法。

🚩 创建类位置回调的变量(用于在设备位置已更改或无法再确定时从融合位置提供程序Api接收通知)

private LocationCallback locationCallback = new LocationCallback() {
        @Override
        public void onLocationResult(LocationResult locationResult) {
            Location location=locationResult.getLastLocation();
            currentLocation=location;
        }
    };

🚩 创建新的位置请求变量。在此对象上,设置各种方法,例如设置位置的精度或要发出的位置请求的间隔数的优先级。

🚩如果需要非常高的准确性,请使用PRIORITY_HIGH_ACCURACY作为 setPriority(int) 方法的参数。对于城市级精度(低精度),请使用PRIORITY_LOW_POWER。

🚩位置请求对象准备就绪后,将其设置在融合位置提供程序客户端对象上以获取最终位置

private void requestNewLocationData() {
        // Initializing LocationRequest object with appropriate methods
        LocationRequest locationRequest = new LocationRequest();

        //  For a city level accuracy(low accuracy), use PRIORITY_LOW_POWER.
        locationRequest.setPriority(LocationRequest.PRIORITY_LOW_POWER);

        // Set the desired interval for active location updates, in milliseconds.
        locationRequest.setInterval(5);

        // Explicitly set the fastest interval for location updates, in milliseconds
        locationRequest.setFastestInterval(0);

        // Set the number of location updates.
        locationRequest.setNumUpdates(1);

        // setting LocationRequest on FusedLocationClient
        fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this);

        // Check for permissions
        if (ActivityCompat.checkSelfPermission
                (this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
                ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            // Request for permissions
            ActivityCompat.requestPermissions(
                    this, LocationPermissions, REQUEST_CODE);
            return;
        } else if (ActivityCompat.shouldShowRequestPermissionRationale(this,Manifest.permission.ACCESS_FINE_LOCATION)) {
            Toast.makeText(this, "Location cannot be determined", Toast.LENGTH_SHORT).show();
            // Request for permissions
            ActivityCompat.requestPermissions(
                    this, LocationPermissions, REQUEST_CODE);
        }

        fusedLocationProviderClient.requestLocationUpdates(locationRequest, locationCallback, Looper.myLooper());
}

现在,你已成功获取用户的位置,并且可以根据需要在应用中实现此位置。

完整代码

完整的主要活动:

package com.example.locationdemo;

import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;

import android.Manifest;
import android.content.pm.PackageManager;
import android.location.Location;
import android.os.Build;
import android.os.Bundle;
import android.os.Looper;
import android.widget.TextView;
import android.widget.Toast;

import com.google.android.gms.location.FusedLocationProviderClient;
import com.google.android.gms.location.LocationCallback;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationResult;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;

public class MainActivity extends AppCompatActivity {
    Location currentLocation;
    FusedLocationProviderClient fusedLocationProviderClient;
    private static final int REQUEST_CODE = 101;
    TextView textView;

    @RequiresApi(api = Build.VERSION_CODES.N)
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView = findViewById(R.id.textView);

        fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this);
        fetchLocation();
    }

    String[] LocationPermissions = new String[]{Manifest.permission.ACCESS_COARSE_LOCATION,
                                        Manifest.permission.ACCESS_FINE_LOCATION};

    @RequiresApi(api = Build.VERSION_CODES.N)
    private void fetchLocation() {
        // Check for permissions
        if (ActivityCompat.checkSelfPermission
                (this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
                ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            // Request for permissions
            ActivityCompat.requestPermissions(
                    this, LocationPermissions, REQUEST_CODE);
            return;
        } else if (ActivityCompat.shouldShowRequestPermissionRationale(this,Manifest.permission.ACCESS_FINE_LOCATION)) {
            Toast.makeText(this, "Location cannot be determined", Toast.LENGTH_SHORT).show();
            // Request for permissions
            ActivityCompat.requestPermissions(
                    this, LocationPermissions, REQUEST_CODE);
        }

        // Getting last location from Fused Location Provider Client Object
        fusedLocationProviderClient.getLastLocation().
                addOnCompleteListener(new OnCompleteListener<Location>() {
                    @Override
                    public void onComplete(@NonNull Task<Location> task) {
                        Location location = task.getResult();
                        if (location == null) {
                            requestNewLocationData();
                        } else {
                            currentLocation = location;
                            textView.setText("Latitude:"+currentLocation.getLatitude()+"\nLongitude:"+currentLocation.getLongitude());
                        }
                    }
                });
    }

    private LocationCallback locationCallback = new LocationCallback() {
        @Override
        public void onLocationResult(LocationResult locationResult) {
            Location location=locationResult.getLastLocation();
            currentLocation=location;
        }
    };

    private void requestNewLocationData() {
        // Initializing LocationRequest object with appropriate methods
        LocationRequest locationRequest = new LocationRequest();

        //  For a city level accuracy(low accuracy), use PRIORITY_LOW_POWER.
        locationRequest.setPriority(LocationRequest.PRIORITY_LOW_POWER);

        // Set the desired interval for active location updates, in milliseconds.
        locationRequest.setInterval(5);

        // Explicitly set the fastest interval for location updates, in milliseconds
        locationRequest.setFastestInterval(0);

        // Set the number of location updates.
        locationRequest.setNumUpdates(1);

        // setting LocationRequest on FusedLocationClient
        fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this);

        // Check for permissions
        if (ActivityCompat.checkSelfPermission
                (this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
                ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            // Request for permissions
            ActivityCompat.requestPermissions(
                    this, LocationPermissions, REQUEST_CODE);
            return;
        } else if (ActivityCompat.shouldShowRequestPermissionRationale(this,Manifest.permission.ACCESS_FINE_LOCATION)) {
            Toast.makeText(this, "Location cannot be determined", Toast.LENGTH_SHORT).show();
            // Request for permissions
            ActivityCompat.requestPermissions(
                    this, LocationPermissions, REQUEST_CODE);
        }

        fusedLocationProviderClient.requestLocationUpdates(locationRequest, locationCallback, Looper.myLooper());
    }

    @RequiresApi(api = Build.VERSION_CODES.N)
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == REQUEST_CODE) {
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                fetchLocation();
            }
            else {
                // Permission not granted
                Toast.makeText(this, "Location cannot be determined", Toast.LENGTH_SHORT).show();
                currentLocation=null;
            }
        }
    }
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,470评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,393评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,577评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,176评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,189评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,155评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,041评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,903评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,319评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,539评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,703评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,417评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,013评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,664评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,818评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,711评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,601评论 2 353

推荐阅读更多精彩内容