Trang chủHướng dẫnTìm hiểu về Android Location API
Chuyên gia

Tìm hiểu về Android Location API

CyStack blog 7 phút để đọc
CyStack blog10/07/2025
Reading Time: 7 minutes

Bạn đã bao giờ tự hỏi làm thế nào các ứng dụng bản đồ, giao hàng hay mạng xã hội lại có thể biết chính xác vị trí của bạn không? Chìa khóa nằm ở Android Location API một công cụ mạnh mẽ cho phép các nhà phát triển truy cập và sử dụng dữ liệu vị trí trên thiết bị di động. Việc nắm vững API này không chỉ giúp bạn tạo ra những ứng dụng thông minh hơn mà còn mở ra vô vàn khả năng cho các dịch vụ dựa trên vị trí (location-based services).

Trong bài blog này, chúng ta sẽ cùng nhau khám phá cách sử dụng Android Location API để lấy vị trí hiện tại của người dùng một cách lập trình, từ đó hiển thị nó trong ứng dụng của chúng ta. Chúng ta sẽ đi sâu vào các khái niệm cốt lõi, cách cấu hình và triển khai code.

Giới thiệu về Android Location API

Có hai cách chính để thu thập vị trí người dùng trong ứng dụng Android của chúng ta:

  • android.location.LocationListener: Đây là một phần của Android API cốt lõi.
  • com.google.android.gms.location.LocationListener: Thuộc về Google Play Services API. (

Android Location Services đã có mặt từ Android API 1. Mặc dù Google chính thức khuyến nghị sử dụng Google Play Location Service APIs cho các ứng dụng mới, Android Location Services API vẫn được sử dụng rộng rãi để phát triển các ứng dụng dựa trên vị trí cho những thiết bị không hỗ trợ Google Play Services.

Tìm hiểu LocationListener

Interface LocationListener là một phần của Android Locations API, được sử dụng để nhận thông báo từ LocationManager khi vị trí đã thay đổi. Class LocationManager cung cấp quyền truy cập vào các dịch vụ định vị của hệ thống. Class LocationListener cần phải implement các phương thức sau:

  • onLocationChanged(Location location): Được gọi khi vị trí đã thay đổi.
  • onProviderDisabled(String provider): Được gọi khi nhà cung cấp (provider) bị người dùng tắt.
  • onProviderEnabled(String provider): Được gọi khi nhà cung cấp được người dùng bật.
  • onStatusChanged(String provider, int status, Bundle extras): Được gọi khi trạng thái của nhà cung cấp thay đổi.

Gói android.location có hai phương tiện để thu thập dữ liệu vị trí:

  • LocationManager.GPS_PROVIDER: Xác định vị trí bằng cách sử dụng vệ tinh. Tùy thuộc vào điều kiện, nhà cung cấp này có thể mất một thời gian để trả về vị trí chính xác.
  • LocationManager.NETWORK_PROVIDER: Xác định vị trí dựa trên sự có sẵn của các trạm phát sóng di động và điểm truy cập WiFi gần đó. Phương pháp này nhanh hơn GPS_PROVIDER.

Trong hướng dẫn này, chúng ta sẽ tạo một Service implement class LocationListener để nhận các bản cập nhật vị trí định kỳ thông qua GPS Providers hoặc Network Providers.

Cấu trúc dự án Android Location API

Dự án của chúng ta bao gồm một class MainActivity.java hiển thị nút “Get Location” và một class Service tên là LocationTrack.java.

Code Android Location API

Layout activity_main.xml được định nghĩa dưới đây:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="<https://schemas.android.com/apk/res/android>"
    xmlns:tools="<https://schemas.android.com/tools>"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.journaldev.gpslocationtracking.MainActivity">

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/btn"
        android:layout_centerInParent="true"
        android:text="GET LOCATION" />
</RelativeLayout>

Class MainActivity.java được định nghĩa dưới đây:

package com.journaldev.gpslocationtracking;

import android.annotation.TargetApi;
import android.content.DialogInterface;
import android.content.pm.PackageManager;
import android.os.Build;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

import java.util.ArrayList;

import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
import static android.Manifest.permission.ACCESS_FINE_LOCATION;

public class MainActivity extends AppCompatActivity {

    private ArrayList permissionsToRequest;
    private ArrayList permissionsRejected = new ArrayList();
    private ArrayList permissions = new ArrayList();

    private final static int ALL_PERMISSIONS_RESULT = 101;
    LocationTrack locationTrack;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        permissions.add(ACCESS_FINE_LOCATION);
        permissions.add(ACCESS_COARSE_LOCATION);

        permissionsToRequest = findUnAskedPermissions(permissions);
        //get the permissions we have asked for before but are not granted..
        //we will store this in a global list to access later.

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {

            if (permissionsToRequest.size() > 0)
                requestPermissions(permissionsToRequest.toArray(new String[permissionsToRequest.size()]), ALL_PERMISSIONS_RESULT);
        }

        Button btn = (Button) findViewById(R.id.btn);

        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                locationTrack = new LocationTrack(MainActivity.this);

                if (locationTrack.canGetLocation()) {

                    double longitude = locationTrack.getLongitude();
                    double latitude = locationTrack.getLatitude();

                    Toast.makeText(getApplicationContext(), "Longitude:" + Double.toString(longitude) + "\\\\nLatitude:" + Double.toString(latitude), Toast.LENGTH_SHORT).show();
                } else {

                    locationTrack.showSettingsAlert();
                }

            }
        });

    }

    private ArrayList findUnAskedPermissions(ArrayList wanted) {
        ArrayList result = new ArrayList();

        for (String perm : wanted) {
            if (!hasPermission(perm)) {
                result.add(perm);
            }
        }

        return result;
    }

    private boolean hasPermission(String permission) {
        if (canMakeSmores()) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                return (checkSelfPermission(permission) == PackageManager.PERMISSION_GRANTED);
            }
        }
        return true;
    }

    private boolean canMakeSmores() {
        return (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1);
    }

    @TargetApi(Build.VERSION_CODES.M)
    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {

        switch (requestCode) {

            case ALL_PERMISSIONS_RESULT:
                for (String perms : permissionsToRequest) {
                    if (!hasPermission(perms)) {
                        permissionsRejected.add(perms);
                    }
                }

                if (permissionsRejected.size() > 0) {

                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                        if (shouldShowRequestPermissionRationale(permissionsRejected.get(0))) {
                            showMessageOKCancel("These permissions are mandatory for the application. Please allow access.",
                                    new DialogInterface.OnClickListener() {
                                        @Override
                                        public void onClick(DialogInterface dialog, int which) {
                                            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                                                requestPermissions(permissionsRejected.toArray(new String[permissionsRejected.size()]), ALL_PERMISSIONS_RESULT);
                                            }
                                        }
                                    });
                            return;
                        }
                    }

                }

                break;
        }

    }

    private void showMessageOKCancel(String message, DialogInterface.OnClickListener okListener) {
        new AlertDialog.Builder(MainActivity.this)
                .setMessage(message)
                .setPositiveButton("OK", okListener)
                .setNegativeButton("Cancel", null)
                .create()
                .show();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        locationTrack.stopListener();
    }
}

Trong đoạn code trên, chúng ta đang triển khai cơ chế cấp quyền thời gian chạy (runtime permissions) được sử dụng trên các thiết bị Android 6.0+. Chúng ta đã thêm quyền ACCESS_FINE_LOCATIONACCESS_COARSE_LOCATION vào file AndroidManifest.xml. Khi người dùng nhấp vào nút, service class LocationTrack.java sẽ được gọi. Nếu vị trí trả về là NULL (thường xảy ra với GPS Provider), chúng ta gọi phương thức showSettingsAlert() từ class LocationTrack.java mà chúng ta sẽ tìm hiểu ngay sau đây. Khi activity bị hủy, phương thức stopListener() được gọi để tắt các cập nhật vị trí. Class LocationTrack.java được định nghĩa dưới đây:

public class LocationTrack extends Service implements LocationListener {

    private final Context mContext;

    boolean checkGPS = false;

    boolean checkNetwork = false;

    boolean canGetLocation = false;

    Location loc;
    double latitude;
    double longitude;

    private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 10;

    private static final long MIN_TIME_BW_UPDATES = 1000 * 60 * 1;
    protected LocationManager locationManager;

    public LocationTrack(Context mContext) {
        this.mContext = mContext;
        getLocation();
    }

    private Location getLocation() {

        try {
            locationManager = (LocationManager) mContext
                    .getSystemService(LOCATION_SERVICE);

            // get GPS status
            checkGPS = locationManager
                    .isProviderEnabled(LocationManager.GPS_PROVIDER);

            // get network provider status
            checkNetwork = locationManager
                    .isProviderEnabled(LocationManager.NETWORK_PROVIDER);

            if (!checkGPS && !checkNetwork) {
                Toast.makeText(mContext, "No Service Provider is available", Toast.LENGTH_SHORT).show();
            } else {
                this.canGetLocation = true;

                // if GPS Enabled get lat/long using GPS Services
                if (checkGPS) {

                    if (ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
                        // TODO: Consider calling
                        //    ActivityCompat#requestPermissions
                        // here to request the missing permissions, and then overriding
                        //   public void onRequestPermissionsResult(int requestCode, String[] permissions,
                        //                                          int[] grantResults)
                        // to handle the case where the user grants the permission. See the documentation
                        // for ActivityCompat#requestPermissions for more details.
                    }
                    locationManager.requestLocationUpdates(
                            LocationManager.GPS_PROVIDER,
                            MIN_TIME_BW_UPDATES,
                            MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
                    if (locationManager != null) {
                        loc = locationManager
                                .getLastKnownLocation(LocationManager.GPS_PROVIDER);
                        if (loc != null) {
                            latitude = loc.getLatitude();
                            longitude = loc.getLongitude();
                        }
                    }

                }

                /*if (checkNetwork) {

                    if (ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
                        // TODO: Consider calling
                        //    ActivityCompat#requestPermissions
                        // here to request the missing permissions, and then overriding
                        //   public void onRequestPermissionsResult(int requestCode, String[] permissions,
                        //                                          int[] grantResults)
                        // to handle the case where the user grants the permission. See the documentation
                        // for ActivityCompat#requestPermissions for more details.
                    }
                    locationManager.requestLocationUpdates(
                            LocationManager.NETWORK_PROVIDER,
                            MIN_TIME_BW_UPDATES,
                            MIN_DISTANCE_CHANGE_FOR_UPDATES, this);

                    if (locationManager != null) {
                        loc = locationManager
                                .getLastKnownLocation(LocationManager.NETWORK_PROVIDER);

                    }

                    if (loc != null) {
                        latitude = loc.getLatitude();
                        longitude = loc.getLongitude();
                    }
                }*/

            }

        } catch (Exception e) {
            e.printStackTrace();
        }

        return loc;
    }

    public double getLongitude() {
        if (loc != null) {
            longitude = loc.getLongitude();
        }
        return longitude;
    }

    public double getLatitude() {
        if (loc != null) {
            latitude = loc.getLatitude();
        }
        return latitude;
    }

    public boolean canGetLocation() {
        return this.canGetLocation;
    }

    public void showSettingsAlert() {
        AlertDialog.Builder alertDialog = new AlertDialog.Builder(mContext);

        alertDialog.setTitle("GPS is not Enabled!");

        alertDialog.setMessage("Do you want to turn on GPS?");

        alertDialog.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int which) {
                Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
                mContext.startActivity(intent);
            }
        });

        alertDialog.setNegativeButton("No", new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int which) {
                dialog.cancel();
            }
        });

        alertDialog.show();
    }

    public void stopListener() {
        if (locationManager != null) {

            if (ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
                // TODO: Consider calling
                //    ActivityCompat#requestPermissions
                // here to request the missing permissions, and then overriding
                //   public void onRequestPermissionsResult(int requestCode, String[] permissions,
                //                                          int[] grantResults)
                // to handle the case where the user grants the permission. See the documentation
                // for ActivityCompat#requestPermissions for more details.
                return;
            }
            locationManager.removeUpdates(LocationTrack.this);
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onLocationChanged(Location location) {

    }

    @Override
    public void onStatusChanged(String s, int i, Bundle bundle) {

    }

    @Override
    public void onProviderEnabled(String s) {

    }

    @Override
    public void onProviderDisabled(String s) {

    }
}

Một vài điểm đáng chú ý từ đoạn code trên:

  • Phương thức isProviderEnabled(String provider) được gọi trên đối tượng locationManager và được dùng để kiểm tra xem GPS/Network Provider đã được bật hay chưa.
  • Nếu các Providers chưa được bật, chúng ta gọi phương thức showSettingsAlert() để hiển thị lời nhắc bật GPS.
  • Phương thức requestLocationUpdates(String provider, long minTime, float minDistance, LocationListener listener) của class LocationManager được sử dụng để đăng ký activity hiện tại để được nhà cung cấp thông báo định kỳ.
  • onLocationChanged được gọi định kỳ dựa trên minTimeminDistance, tùy điều kiện nào đến trước.
  • Class Location chứa các giá trị vĩ độ (latitude) và kinh độ (longitude). Để lấy vị trí hiện tại, đoạn code sau được sử dụng:
    Location loc = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
    
    

    Trên đối tượng Location ở trên, các phương thức getter được gọi để lưu trữ các giá trị double của vĩ độ và kinh độ. Các giá trị này sau đó được hiển thị dưới dạng một tin nhắn Toast trên màn hình.

  • Để dừng các cập nhật vị trí, phương thức removeUpdates được gọi trên instance của LocationManager.

Giờ đây, chúng ta đã nắm được cách triển khai, hãy cùng xem kết quả thực tế và những lưu ý quan trọng.

Kết quả của ứng dụng trên trình giả lập:

Trình giả lập của chúng ta không thể lấy được vị trí thực tế, do đó nó trả về 0.0 cho lat/lng. Bạn có thể kết nối điện thoại thông minh của mình và chạy ứng dụng ở chế độ gỡ lỗi (debug mode) để kiểm tra vị trí hiện tại của mình. Để mô phỏng vị trí GPS trong trình giả lập, chúng ta có thể truyền các giá trị Vĩ độ và Kinh độ cố định từ Android Studio. Bên cạnh cửa sổ trình giả lập, bạn có thể thấy một danh sách các tùy chọn. Tùy chọn ở dưới cùng (có ba dấu chấm) là tùy chọn Kiểm soát mở rộng (Extended Controls). Mở nó ra và gửi một vị trí giả. Ứng dụng của bạn sẽ trông như thế này:

Kết luận

Như vậy, chúng ta đã cùng nhau tìm hiểu sâu về cách triển khai tính năng định vị trên Android bằng cách sử dụng Android Location API cốt lõi, đặc biệt là interface LocationListener.

Khả năng định vị người dùng là một yếu tố then chốt trong rất nhiều loại ứng dụng hiện đại, từ bản đồ, du lịch, thể thao, đến các dịch vụ giao hàng hay an toàn cá nhân. Việc thành thạo API này sẽ mở ra nhiều cơ hội để bạn phát triển những ứng dụng sáng tạo và hữu ích.

0 Bình luận

Đăng nhập để thảo luận

Chuyên mục Hướng dẫn

Tổng hợp các bài viết hướng dẫn, nghiên cứu và phân tích chi tiết về kỹ thuật, các xu hướng công nghệ mới nhất dành cho lập trình viên.

Đăng ký nhận bản tin của chúng tôi

Hãy trở thành người nhận được các nội dung hữu ích của CyStack sớm nhất

Xem chính sách của chúng tôi Chính sách bảo mật.

Đăng ký nhận Newsletter

Nhận các nội dung hữu ích mới nhất