You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android后台Location Listener无法工作问题求助

解决应用关闭后Service无法获取位置更新的问题

我来帮你拆解下这个问题——你的Service在应用关闭后停止获取位置更新,主要是没适配Android的后台限制机制,还有一些API使用上的小坑,咱们一步步来解决:

问题根源分析

  1. Android后台Service管控:从Android 8.0(API 26)开始,系统对普通后台Service的限制非常严格,哪怕你返回了START_STICKY,也很容易被系统回收。
  2. 权限缺失:Android 10(API 29)及以上版本,想要在后台持续获取位置,必须申请ACCESS_BACKGROUND_LOCATION权限,你的Manifest里没加这个关键权限。
  3. 原生LocationManager的局限性:原生LocationManager在后台场景下的稳定性不如谷歌官方推荐的FusedLocationProviderClient,系统更容易限制它的位置更新频率。
  4. 独立进程Service:你给Service设置了:my_service独立进程,这种进程的优先级更低,系统资源紧张时会优先被回收。

具体修改步骤

1. 更新Manifest配置

补充必要权限,调整Service的配置:

<manifest xmlns:android="http://schemas.android.com/apk/res/android" 
          package="com.example.kanwarpreet.location_manager">

    <!-- 基础定位权限 -->
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <!-- Android 10+ 后台定位权限 -->
    <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />

    <application 
        android:allowBackup="true" 
        android:icon="@mipmap/ic_launcher" 
        android:label="@string/app_name" 
        android:roundIcon="@mipmap/ic_launcher_round" 
        android:supportsRtl="true" 
        android:theme="@style/AppTheme">

        <activity android:name=".Activity_Location_Tracker">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <!-- 去掉独立进程,添加前台服务类型声明 -->
        <service 
            android:name=".utils.MyService" 
            android:enabled="true"
            android:foregroundServiceType="location" />
    </application>
</manifest>

2. 添加谷歌定位服务依赖

在app/build.gradle(Module级别)中添加Fused Location Provider的依赖:

dependencies {
    // 谷歌定位服务
    implementation 'com.google.android.gms:play-services-location:21.0.1'
}

3. 重写Service类(改用FusedLocationProviderClient+前台服务)

替换原来的MyService代码,用更稳定的Fused定位API,同时把Service转为前台服务:

import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.IBinder;
import android.util.Log;
import androidx.core.app.ActivityCompat;
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;

public class MyService extends Service {
    private static final String TAG = "BOOMBOOMTESTGPS";
    private static final int NOTIFICATION_ID = 12345;
    private static final String CHANNEL_ID = "LOCATION_SERVICE_CHANNEL";

    private FusedLocationProviderClient fusedLocationClient;
    private LocationCallback locationCallback;
    private LocationRequest locationRequest;

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

    @Override
    public void onCreate() {
        super.onCreate();
        Log.e(TAG, "onCreate");
        
        // 创建通知渠道(Android O+ 必需)
        createNotificationChannel();
        // 启动前台服务,避免被系统回收
        startForeground(NOTIFICATION_ID, getTrackingNotification());

        // 初始化Fused定位客户端
        fusedLocationClient = LocationServices.getFusedLocationProviderClient(this);

        // 配置位置更新参数
        locationRequest = LocationRequest.create();
        locationRequest.setInterval(1000); // 1秒更新一次
        locationRequest.setFastestInterval(500); // 最快500毫秒更新
        locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); // 高精度模式

        // 设置位置回调
        locationCallback = new LocationCallback() {
            @Override
            public void onLocationResult(LocationResult locationResult) {
                super.onLocationResult(locationResult);
                if (locationResult == null) return;
                // 处理位置更新
                for (Location location : locationResult.getLocations()) {
                    Log.e(TAG, "onLocationChanged: " + location.getLatitude() + ", " + location.getLongitude());
                }
            }
        };

        // 开始请求位置更新
        startLocationUpdates();
    }

    private void startLocationUpdates() {
        // 检查权限
        if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
                && ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            Log.i(TAG, "缺少定位权限,无法获取位置");
            return;
        }
        fusedLocationClient.requestLocationUpdates(locationRequest, locationCallback, null);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.e(TAG, "onStartCommand");
        return START_STICKY;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.e(TAG, "onDestroy");
        // 停止位置更新
        if (fusedLocationClient != null && locationCallback != null) {
            fusedLocationClient.removeLocationUpdates(locationCallback);
        }
    }

    // 创建前台服务通知渠道
    private void createNotificationChannel() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel(
                    CHANNEL_ID,
                    "位置追踪服务",
                    NotificationManager.IMPORTANCE_LOW // 低优先级,不打扰用户
            );
            NotificationManager manager = getSystemService(NotificationManager.class);
            manager.createNotificationChannel(channel);
        }
    }

    // 创建前台服务显示的通知
    private Notification getTrackingNotification() {
        Notification.Builder builder;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            builder = new Notification.Builder(this, CHANNEL_ID);
        } else {
            builder = new Notification.Builder(this);
        }
        return builder.setSmallIcon(R.mipmap.ic_launcher)
                .setContentTitle("位置追踪中")
                .setContentText("正在获取您的实时位置")
                .setPriority(Notification.PRIORITY_LOW)
                .build();
    }
}

4. 在Activity中动态申请权限

启动Service前,向用户申请必要的定位权限(尤其是后台权限):

import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

public class Activity_Location_Tracker extends AppCompatActivity {
    private static final int LOCATION_PERMISSION_REQUEST_CODE = 1001;

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

        // 检查权限,没有就申请
        if (checkLocationPermissions()) {
            startLocationService();
        } else {
            requestLocationPermissions();
        }
    }

    private boolean checkLocationPermissions() {
        boolean hasFineLocation = ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            boolean hasBackgroundLocation = ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_BACKGROUND_LOCATION) == PackageManager.PERMISSION_GRANTED;
            return hasFineLocation && hasBackgroundLocation;
        }
        return hasFineLocation;
    }

    private void requestLocationPermissions() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            ActivityCompat.requestPermissions(this,
                    new String[]{
                            Manifest.permission.ACCESS_FINE_LOCATION,
                            Manifest.permission.ACCESS_BACKGROUND_LOCATION
                    },
                    LOCATION_PERMISSION_REQUEST_CODE);
        } else {
            ActivityCompat.requestPermissions(this,
                    new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
                    LOCATION_PERMISSION_REQUEST_CODE);
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == LOCATION_PERMISSION_REQUEST_CODE) {
            if (checkLocationPermissions()) {
                startLocationService();
            } else {
                // 用户拒绝了权限,提示无法进行位置追踪
                // 可以弹出Toast或者对话框
            }
        }
    }

    private void startLocationService() {
        Intent serviceIntent = new Intent(this, MyService.class);
        startService(serviceIntent);
    }
}

关键修改说明

  • 前台服务:通过startForeground把Service转为前台服务,系统会认为这是用户关注的服务,不会轻易回收,同时显示一个低优先级通知避免打扰用户。
  • FusedLocationProviderClient:谷歌官方维护的定位API,比原生LocationManager更适配Android后台机制,能更稳定地获取位置更新。
  • 后台定位权限:Android 10+必须申请ACCESS_BACKGROUND_LOCATION,否则应用进入后台后会被禁止获取位置。
  • 去掉独立进程:去掉:my_service让Service和应用同进程,提升进程优先级,减少被回收的概率。

按照这些步骤修改后,你的应用关闭(退到后台)后,Service应该就能持续获取位置更新了。

内容的提问来源于stack exchange,提问作者Kanwarpreet Singh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 09:36:40