Android сервис иногда перестает работать, когда приложение находится в фоновом режиме - PullRequest
0 голосов
/ 07 января 2020

Я пытаюсь создать приложение, которое приветствует пользователя в новом городе, когда он пересекается, и чтобы сделать приложение практичным, оно работает в фоновом режиме, и поэтому я создал его внутри службы. Моя проблема в том, что когда он работает, он непредсказуем. Иногда он не приветствует пользователя в городе, но позже он приветствует пользователя во множестве городов одновременно (те, которые были пройдены ранее). И иногда это работает просто отлично, особенно сразу после того, как приложение выходит на задний план. Как мне заставить это работать все время? Вот мой код.

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>

Любая помощь ценится и спасибо!

...