能否在TimerTask中调用requestLocationUpdates?求正确实现方案
Hey there, let’s work through getting your location tracking up and running reliably every 5 minutes. I’ve tackled similar issues before, so let’s break this down into actionable steps, including fixes for common pitfalls you might be hitting.
1. First: Ditch the Deprecated API
The LocationServices.FusedLocationApi you’re using is no longer supported—this could be a major reason your code isn’t working! Google recommends using FusedLocationProviderClient instead, which is more stable and easier to integrate. Let’s start with that switch.
Add Dependencies & Permissions
First, make sure your build.gradle (Module level) has the latest location dependency:
dependencies { implementation 'com.google.android.gms:play-services-location:21.0.1' }
Then, add required permissions to your AndroidManifest.xml (adjust based on your target Android version):
<!-- For Android 9 and below --> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <!-- For Android 10+ (required for background tracking) --> <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
2. Initialize Location Client & Callback
Set up the location client and callback in a Service (better for background tracking) or Activity:
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 LocationTrackingService extends Service { private FusedLocationProviderClient fusedLocationClient; private LocationCallback locationCallback; @Override public void onCreate() { super.onCreate(); fusedLocationClient = LocationServices.getFusedLocationProviderClient(this); // Configure location request (we'll use one-time updates for periodic tasks) LocationRequest locationRequest = LocationRequest.create(); locationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY); locationRequest.setNumUpdates(1); // Get only one location per trigger // Set up callback to handle location results locationCallback = new LocationCallback() { @Override public void onLocationResult(LocationResult locationResult) { if (locationResult == null || locationResult.getLastLocation() == null) { return; } // Extract location data double lat = locationResult.getLastLocation().getLatitude(); double lng = locationResult.getLastLocation().getLongitude(); // Save to database (run on background thread!) saveLocationToDatabase(lat, lng); } }; } // Database save logic (use background thread to avoid ANRs) private void saveLocationToDatabase(double lat, double lng) { Executors.newSingleThreadExecutor().execute(() -> { // Replace with your actual database insert code // Example: AppDatabase.getInstance(this).locationDao().insert(new LocationEntry(lat, lng)); }); } // Helper method to trigger a single location update public void triggerLocationUpdate() { if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { return; // Bail if permissions aren't granted } fusedLocationClient.requestLocationUpdates( LocationRequest.create(), locationCallback, Looper.getMainLooper() ); } @Nullable @Override public IBinder onBind(Intent intent) { return null; } }
3. Schedule 5-Minute Updates (Reliable Method)
TimerTask is unreliable for Android background tasks—system can kill it when your app is inactive. Instead, use WorkManager (Google’s recommended tool for periodic background work):
Add WorkManager Dependency
implementation "androidx.work:work-runtime:2.8.1"
Create a Worker Class
public class LocationWorker extends Worker { public LocationWorker(@NonNull Context context, @NonNull WorkerParameters params) { super(context, params); } @NonNull @Override public Result doWork() { // Start the location service and trigger an update Intent intent = new Intent(getApplicationContext(), LocationTrackingService.class); ContextCompat.startForegroundService(getApplicationContext(), intent); ((LocationTrackingService) getApplicationContext()).triggerLocationUpdate(); return Result.success(); } }
Schedule the Periodic Task
In your Activity or Application class, set up the 5-minute repeat:
PeriodicWorkRequest locationWorkRequest = new PeriodicWorkRequest.Builder( LocationWorker.class, 5, TimeUnit.MINUTES, // Repeat every 5 minutes 1, TimeUnit.MINUTES) // Flex window (adjust for system constraints) .build(); WorkManager.getInstance(getApplicationContext()).enqueue(locationWorkRequest);
4. If You Insist on Using TimerTask (Not Recommended!)
If you really want to stick with TimerTask, here’s how to do it correctly (note: this will fail in background on newer Android versions):
private Timer locationTimer; private void startTimer() { locationTimer = new Timer(); locationTimer.scheduleAtFixedRate(new TimerTask() { @Override public void run() { // Run on UI thread (location updates require main looper) runOnUiThread(() -> { if (ContextCompat.checkSelfPermission(YourActivity.this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { // Trigger location update ((LocationTrackingService) getApplicationContext()).triggerLocationUpdate(); } }); } }, 0, 5 * 60 * 1000); // Start immediately, repeat every 5 minutes } // Clean up timer when activity is destroyed @Override protected void onDestroy() { super.onDestroy(); if (locationTimer != null) { locationTimer.cancel(); } }
5. Common Fixes for Your Original Issue
- Permissions: Always check runtime permissions before requesting location updates—your app might be missing them.
- Background Restrictions: Android 12+ blocks background tasks from
TimerTask—use WorkManager instead. - Database Threading: Never run database operations on the main thread—use an Executor or Coroutines.
- API Deprecation: The old
FusedLocationApihas known bugs—switch toFusedLocationProviderClientto resolve most issues.
内容的提问来源于stack exchange,提问作者Raghul krishnan

