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

如何用AlarmManager实现每分钟重复执行经纬度上传任务?

实现AlarmManager每分钟重复上传经纬度到MySQL的方案

Hey there! Let's get your Android app to send location data to MySQL every minute using AlarmManager. Here's a step-by-step solution tailored to your existing code:

1. 创建LocationUploadReceiver(广播接收器)

我们需要一个独立组件来处理周期性的位置获取和上传任务,因为AlarmManager即使在Activity不在前台时也能触发事件,广播接收器是后台执行这类任务的理想选择。

public class LocationUploadReceiver extends BroadcastReceiver {
    private static final String TAG = "LocationUploadReceiver";
    private RequestQueue requestQueue;
    private String insertURL = "http://190.147.68.37/app/myapp_save.php";

    @Override
    public void onReceive(Context context, Intent intent) {
        // 初始化Volley请求队列(避免重复创建)
        if (requestQueue == null) {
            requestQueue = Volley.newRequestQueue(context);
        }

        // 先检查位置权限
        if (ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION)
                != PackageManager.PERMISSION_GRANTED) {
            Log.d(TAG, "位置权限未授予,跳过本次上传");
            return;
        }

        // 使用FusedLocationProviderClient获取当前位置
        FusedLocationProviderClient fusedLocationClient = LocationServices.getFusedLocationProviderClient(context);
        fusedLocationClient.getLastLocation()
                .addOnCompleteListener(task -> {
                    if (task.isSuccessful() && task.getResult() != null) {
                        Location location = task.getResult();
                        uploadLocationToServer(location);
                    } else {
                        Log.d(TAG, "获取位置失败: " + task.getException());
                    }
                });
    }

    private void uploadLocationToServer(Location location) {
        double latitude = location.getLatitude();
        double longitude = location.getLongitude();

        StringRequest request = new StringRequest(Request.Method.POST, insertURL,
                response -> Log.d(TAG, "位置上传成功"),
                error -> Log.e(TAG, "上传错误: " + error.getMessage())) {
            @Override
            protected Map<String, String> getParams() throws AuthFailureError {
                Map<String, String> parameters = new HashMap<>();
                // 直接传递位置数值,比从TextView取文本更可靠
                parameters.put("latitude", String.valueOf(latitude));
                parameters.put("longitude", String.valueOf(longitude));
                return parameters;
            }
        };

        requestQueue.add(request);
    }
}

2. 在AndroidManifest.xml中注册广播接收器

在<application>标签内添加以下代码,让系统识别你的接收器:

<receiver android:name=".LocationUploadReceiver" />

3. 更新MapActivity配置AlarmManager

修改onCreate方法,并添加启动/停止闹钟的方法:

首先补充全局变量(部分你已经定义过):

private AlarmManager alarmManager;
private PendingIntent pendingIntent;
private static final long INTERVAL_MINUTE = 60 * 1000; // 1分钟的毫秒值

然后在onCreate中权限获取完成后初始化闹钟:

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

    // 初始化现有视图和Volley队列
    t_latitude = findViewById(R.id.t_latitude);
    t_longitude = findViewById(R.id.t_longitude);
    requestQueue = Volley.newRequestQueue(getApplicationContext());

    // 权限授予后启动定时上传
    if (mLocationPermissionsGranted) {
        startLocationUploadAlarm();
    }
}

添加以下方法到MapActivity:

private void startLocationUploadAlarm() {
    alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
    Intent intent = new Intent(this, LocationUploadReceiver.class);
    pendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_IMMUTABLE);

    // 适配Android 12+的闹钟设置,确保Doze模式下也能触发
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        alarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP,
                SystemClock.elapsedRealtime() + INTERVAL_MINUTE,
                pendingIntent);
    } else {
        alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
                SystemClock.elapsedRealtime(),
                INTERVAL_MINUTE,
                pendingIntent);
    }

    Toast.makeText(this, "位置定时上传已启动", Toast.LENGTH_SHORT).show();
}

private void stopLocationUploadAlarm() {
    if (alarmManager != null && pendingIntent != null) {
        alarmManager.cancel(pendingIntent);
        Toast.makeText(this, "位置定时上传已停止", Toast.LENGTH_SHORT).show();
    }
}

// 可选:当Activity销毁时停止上传(根据需求决定是否启用)
@Override
protected void onDestroy() {
    super.onDestroy();
    // stopLocationUploadAlarm();
}

4. 优化现有onLocationChanged方法

你当前的方法重复调用findViewById,并且依赖TextView文本上传,我们优化它以匹配新逻辑:

public void onLocationChanged(Location location) {
    // 更新UI显示位置
    t_longitude.setText("Longitude: " + location.getLongitude());
    t_latitude.setText("Latitude: " + location.getLatitude());

    // 可选:位置变化时立即上传(配合定时上传)
    uploadLocationToServer(location);
}

// 给MapActivity添加即时上传的辅助方法
private void uploadLocationToServer(Location location) {
    double latitude = location.getLatitude();
    double longitude = location.getLongitude();

    StringRequest request = new StringRequest(Request.Method.POST, insertURL,
            response -> Log.d(TAG, "即时位置上传成功"),
            error -> Log.e(TAG, "即时上传错误: " + error.getMessage())) {
        @Override
        protected Map<String, String> getParams() throws AuthFailureError {
            Map<String, String> parameters = new HashMap<>();
            parameters.put("latitude", String.valueOf(latitude));
            parameters.put("longitude", String.valueOf(longitude));
            return parameters;
        }
    };

    requestQueue.add(request);
}

重要注意事项

  • Android 12+权限: 后台位置访问需要额外申请ACCESS_BACKGROUND_LOCATION权限,在getLocationPermission()的权限数组中添加:
    String[] permissions = {Manifest.permission.ACCESS_FINE_LOCATION, 
                            Manifest.permission.ACCESS_COARSE_LOCATION,
                            Manifest.permission.ACCESS_BACKGROUND_LOCATION};
    
  • Doze模式适配: 使用setExactAndAllowWhileIdle确保设备在Doze模式下闹钟仍能触发,保证任务可靠性。
  • 电池优化: 建议引导用户将你的应用排除在电池优化之外,避免系统杀死后台任务。
  • 位置准确性: 如果getLastLocation()返回null(常见于GPS未被使用过的情况),可以考虑在接收器中临时请求位置更新,或使用LocationRequest配合FusedLocationProviderClient获取更稳定的位置。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 06:56:00