Я пытаюсь создать приложение, которое приветствует пользователя в новом городе, когда он пересекается, и чтобы сделать приложение практичным, оно работает в фоновом режиме, и поэтому я создал его внутри службы. Моя проблема в том, что когда он работает, он непредсказуем. Иногда он не приветствует пользователя в городе, но позже он приветствует пользователя во множестве городов одновременно (те, которые были пройдены ранее). И иногда это работает просто отлично, особенно сразу после того, как приложение выходит на задний план. Как мне заставить это работать все время? Вот мой код.
MainActivity. java
package com.example.drivingwelcomer;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import android.Manifest;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.location.Address;
import android.location.Geocoder;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.location.LocationProvider;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.StrictMode;
import android.speech.tts.TextToSpeech;
import android.util.Log;
import android.widget.TextView;
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;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.android.gms.tasks.Task;
import java.io.IOException;
import java.util.List;
import java.util.Locale;
public class MainActivity extends AppCompatActivity {
private TextView tvLocation;
private Intent intent;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
openPermissions();
tvLocation = findViewById(R.id.tvLocation);
intent = new Intent(this, DrivingWelcomerService.class);
startService(intent);
Log.d("test", "test");
}
@Override
protected void onDestroy() {
super.onDestroy();
stopService(intent);
}
private void openPermissions() {
if (ContextCompat.checkSelfPermission( this,android.Manifest.permission.ACCESS_COARSE_LOCATION )
!= PackageManager.PERMISSION_GRANTED )
{
ActivityCompat.requestPermissions(
this,
new String [] { android.Manifest.permission.ACCESS_COARSE_LOCATION },
303
);
}
if (ContextCompat.checkSelfPermission( this,android.Manifest.permission.ACCESS_FINE_LOCATION )
!= PackageManager.PERMISSION_GRANTED )
{
ActivityCompat.requestPermissions(
this,
new String [] { android.Manifest.permission.ACCESS_FINE_LOCATION },
304
);
}
}
private void allowNetworkUsageInMainThread() {
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
}
}
DrivingWelcomerService. java
package com.example.drivingwelcomer;
import android.app.Service;
import android.content.Intent;
import android.location.Address;
import android.location.Geocoder;
import android.location.Location;
import android.os.Build;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.Process;
import android.speech.tts.TextToSpeech;
import android.util.Log;
import android.widget.Toast;
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;
import java.io.IOException;
import java.util.List;
import java.util.Locale;
public class DrivingWelcomerService extends Service {
private FusedLocationProviderClient fusedLocationClient;
private Address lastAddress;
private Geocoder geocoder;
private TextToSpeech tts;
private LocationCallback locationCallback;
private Looper serviceLooper;
private ServiceHandler serviceHandler;
public final String TAG = "DRIVINGWELCOMERSERVICEDEBUG";
// Handler that receives messages from the thread
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
}
}
@Override
public void onCreate() {
// Start up the thread running the service. Note that we create a
// separate thread because the service normally runs in the process's
// main thread, which we don't want to block. We also make it
// background priority so CPU-intensive work doesn't disrupt our UI.
HandlerThread thread = new HandlerThread("ServiceStartArguments",
Process.THREAD_PRIORITY_FOREGROUND);
thread.start();
// Get the HandlerThread's Looper and use it for our Handler
serviceLooper = thread.getLooper();
serviceHandler = new ServiceHandler(serviceLooper);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
fusedLocationClient =
LocationServices.getFusedLocationProviderClient(getApplicationContext());
geocoder = new Geocoder(getApplicationContext());
TextToSpeech.OnInitListener listener = new MyTTSListener();
tts = new TextToSpeech(getApplicationContext(), listener);
LocationRequest locationRequest = LocationRequest.create()
.setInterval(60000)
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setSmallestDisplacement(200);
locationCallback = new MyLocationCallback();
fusedLocationClient.requestLocationUpdates(locationRequest,
locationCallback, null);
Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();
// For each start request, send a message to start a job and deliver the
// start ID so we know which request we're stopping when we finish the job
Message msg = serviceHandler.obtainMessage();
msg.arg1 = startId;
serviceHandler.sendMessage(msg);
// If we get killed, after returning from here, restart
return START_STICKY;
}
@Override
public IBinder onBind(Intent intent) {
// We don't provide binding, so return null
return null;
}
@Override
public void onDestroy() {
Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();
}
private class MyLocationCallback extends LocationCallback {
@Override
public void onLocationResult(LocationResult locationResult) {
Location l = locationResult.getLastLocation();
double latitude = l.getLatitude();
double longitude = l.getLongitude();
try {
List<Address> results =
geocoder.getFromLocation(latitude, longitude, 1);
if (!results.isEmpty()) {
Address result = results.get(0);
String currCity = result.getLocality();
if (lastAddress == null) {
// Start Asynctask to play welcoming voice
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
tts.speak("Welcome to " + currCity, TextToSpeech.QUEUE_FLUSH,
null, null);
} else {
tts.speak("Welcome to " + currCity, TextToSpeech.QUEUE_FLUSH,
null);
}
} else {
String prevCity = lastAddress.getLocality();
if (!prevCity.equals(currCity)) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
tts.speak("Welcome to " + currCity, TextToSpeech.QUEUE_FLUSH,
null, null);
} else {
tts.speak("Welcome to " + currCity, TextToSpeech.QUEUE_FLUSH,
null);
}
}
}
lastAddress = result;
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
private class MyTTSListener implements TextToSpeech.OnInitListener {
@Override
public void onInit(int status) {
if (status == TextToSpeech.SUCCESS) {
int result = tts.setLanguage(Locale.US);
if (result == TextToSpeech.LANG_MISSING_DATA ||
result == TextToSpeech.LANG_NOT_SUPPORTED) {
}
}
else {
// Init failed
}
}
}
}
Manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.drivingwelcomer">
<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">
<service android:name=".DrivingWelcomerService" />
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"></uses-permission>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"></uses-permission>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"></uses-permission>
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
</manifest>
Любая помощь ценится и спасибо!