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

Android新手求助:如何在Service中运行onLocationChanged方法

解决Service中持续获取位置并生成地图标记的问题

作为Android新手,在Service里处理位置更新确实容易踩几个典型的坑,我来帮你一步步梳理和修正:

首先要规避的核心问题

  • Service不能直接操作UI控件:你的代码里有tvlattitude和tvlongitude这两个TextView,Service是后台组件,没有自己的UI上下文,直接持有这些控件引用会导致内存泄漏或者空指针异常,绝对不能这么做。
  • GoogleMap不应在Service中持有:mMap实例是和Activity/MapFragment的生命周期强绑定的,Service里直接使用它大概率会出问题——比如Activity已经销毁但Service还在运行,调用Map的方法就会崩溃。

修正后的实现思路

我们把职责拆分清楚,让每个组件干自己擅长的事:

  1. Service只负责后台持续获取位置更新
  2. 通过本地广播(LocalBroadcastManager)或者LiveData把位置数据传递给前台的Map Activity
  3. Map Activity接收位置数据后,在GoogleMap上添加标记

代码示例

1. 修正后的MyService类

public class MyService extends Service implements LocationListener {
    private GoogleApiClient mGoogleApiClient;
    private LocationRequest mLocationRequest;

    @Override
    public void onCreate() {
        super.onCreate();
        // 初始化GoogleApiClient
        buildGoogleApiClient();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        if (mGoogleApiClient != null && !mGoogleApiClient.isConnected()) {
            mGoogleApiClient.connect();
        }
        // Android 8.0+ 需设置前台服务,避免被系统杀死
        startForegroundServiceNotification();
        return START_STICKY; // 保证Service被意外杀死后能重启
    }

    private void startForegroundServiceNotification() {
        // 先创建通知渠道(Android 8.0+ 必需)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel("LOCATION_CHANNEL", "位置更新", NotificationManager.IMPORTANCE_LOW);
            NotificationManager manager = getSystemService(NotificationManager.class);
            manager.createNotificationChannel(channel);
        }
        // 构建前台通知
        Notification notification = new NotificationCompat.Builder(this, "LOCATION_CHANNEL")
                .setContentTitle("位置追踪中")
                .setContentText("正在持续获取位置数据")
                .setSmallIcon(R.drawable.ic_location)
                .build();
        startForeground(1, notification);
    }

    private synchronized void buildGoogleApiClient() {
        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .addConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() {
                    @Override
                    public void onConnected(@Nullable Bundle bundle) {
                        // 连接成功后开始请求位置更新
                        startLocationUpdates();
                    }

                    @Override
                    public void onConnectionSuspended(int i) {
                        mGoogleApiClient.connect();
                    }
                })
                .addOnConnectionFailedListener(connectionResult -> {
                    // 这里可以添加连接失败的提示逻辑
                })
                .addApi(LocationServices.API)
                .build();
    }

    private void startLocationUpdates() {
        mLocationRequest = new LocationRequest();
        mLocationRequest.setInterval(10000); // 10秒更新一次,可按需调整
        mLocationRequest.setFastestInterval(5000);
        mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);

        // 检查位置权限
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            return;
        }
        LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
    }

    @Override
    public void onLocationChanged(Location location) {
        // 获取到位置后,通过本地广播发送给Activity
        Intent intent = new Intent("LOCATION_UPDATED_ACTION");
        intent.putExtra("lat", location.getLatitude());
        intent.putExtra("lng", location.getLongitude());
        LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        // 停止位置更新,释放资源
        if (mGoogleApiClient != null && mGoogleApiClient.isConnected()) {
            LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
            mGoogleApiClient.disconnect();
        }
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null; // 不需要绑定服务时返回null
    }

    // LocationListener的其他方法空实现即可
    @Override
    public void onStatusChanged(String provider, int status, Bundle extras) {}
    @Override
    public void onProviderEnabled(String provider) {}
    @Override
    public void onProviderDisabled(String provider) {}
}

2. 接收位置并添加标记的Map Activity

public class MapActivity extends AppCompatActivity implements OnMapReadyCallback {
    private GoogleMap mMap;
    private BroadcastReceiver locationReceiver;

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

        // 初始化MapFragment
        SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
                .findFragmentById(R.id.map);
        mapFragment.getMapAsync(this);

        // 注册广播接收器,接收Service发来的位置数据
        locationReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                double lat = intent.getDoubleExtra("lat", 0);
                double lng = intent.getDoubleExtra("lng", 0);
                // 在地图上添加新标记
                addNewLocationMarker(lat, lng);
            }
        };
        LocalBroadcastManager.getInstance(this).registerReceiver(locationReceiver, new IntentFilter("LOCATION_UPDATED_ACTION"));
    }

    @Override
    public void onMapReady(GoogleMap googleMap) {
        mMap = googleMap;
        // 初始化地图初始位置(可按需修改)
        LatLng initialLoc = new LatLng(39.9042, 116.4074);
        mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(initialLoc, 12));
    }

    private void addNewLocationMarker(double lat, double lng) {
        if (mMap != null) {
            LatLng newLoc = new LatLng(lat, lng);
            mMap.addMarker(new MarkerOptions()
                    .position(newLoc)
                    .title("当前位置")
                    .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_BLUE)));
            // 可选:自动移动地图到新位置
            mMap.moveCamera(CameraUpdateFactory.newLatLng(newLoc));
        }
    }

    @Override
    protected void onStart() {
        super.onStart();
        // 启动位置追踪Service
        startService(new Intent(this, MyService.class));
    }

    @Override
    protected void onStop() {
        super.onStop();
        // 停止Service并注销广播
        stopService(new Intent(this, MyService.class));
        LocalBroadcastManager.getInstance(this).unregisterReceiver(locationReceiver);
    }
}

额外注意事项

  • 权限配置:别忘了在Manifest里添加必要权限:
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    <service android:name=".MyService" />
    
  • 运行时权限申请:在Activity里要先申请位置权限,用户同意后再启动Service,不然位置更新会失效。
  • 性能优化:位置更新间隔不要设置得太频繁,避免过度耗电,根据你的实际需求调整setInterval和setFastestInterval的数值。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 10:36:37