FacedLocationApi Background Location service stops receiving updates randomly

I am trying to use FusedLocationApi with a pending intention to receive period location updates so that I can send data to some server for processing. Everything is working. However, there are cases where the transmission simply stops receiving. I will need to restart the service again in order to continue.

I already have the onStartCommand service to return START_STICKY, so even if the application is killed, it should start the service again. In addition, I also added a boot receiver with the bootloader turned on, so if the phone died and the user restarted the phone, it will restart my service.

So, everything is fine and working, but just at some point, everything just stops. I noticed several times that when it stops working, the last place I got was NULL (I log every location update and error messages throughout my project).

Any ideas that search engines just stop working?

PS there is no connection failure, because I put a message and connect to this function and do not call. And this is not an Internet failure, since I am registering it. Once the Internet is restored, it will continue as usual / expected.

Thanks.

This is the main activity:

public class MainActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    ActionBar actionBar = getSupportActionBar();

    if (actionBar != null) {
        actionBar.setDisplayShowHomeEnabled(false);
        actionBar.setDisplayShowTitleEnabled(false);
        if (findViewById(android.R.id.home) != null) {
            findViewById(android.R.id.home).setVisibility(View.GONE);
        }

        LayoutInflater inflator = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        View view = inflator.inflate(R.layout.header_logo, null);

        ActionBar.LayoutParams params = new ActionBar.LayoutParams(ActionBar.LayoutParams.WRAP_CONTENT, ActionBar.LayoutParams.WRAP_CONTENT, Gravity.CENTER);
        actionBar.setDisplayShowCustomEnabled(true);
        actionBar.setCustomView(view, params);
    }

    setContentView(R.layout.activity_main);

    TextView textView = (TextView) findViewById(R.id.status_text);

    // init preferences and status handler
    MyStatusHandler.init(getApplicationContext(), textView);

    // init web service call class
    ...;

    // check for location services
    if (!isLocationEnabled(getApplicationContext())){
        String msg = "Location services not turned on";
        MyStatusHandler.setStatusText(msg);
    }
}

public static boolean isLocationEnabled(Context context) {
    int locationMode = 0;
    String locationProviders;

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){
        try {
            locationMode = Settings.Secure.getInt(context.getContentResolver(), Settings.Secure.LOCATION_MODE);

        } catch (Settings.SettingNotFoundException e) {
            e.printStackTrace();
        }

        return locationMode != Settings.Secure.LOCATION_MODE_OFF;

    }else{
        locationProviders = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.LOCATION_PROVIDERS_ALLOWED);
        return !TextUtils.isEmpty(locationProviders);
    }
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.menu_main, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle action bar item clicks here. The action bar will
    // automatically handle clicks on the Home/Up button, so long
    // as you specify a parent activity in AndroidManifest.xml.
    int id = item.getItemId();

    //noinspection SimplifiableIfStatement
    if (id == R.id.action_settings) {
        // create new intent activity for the settings page
        Intent i = new Intent(this, MySettingsActivity.class);
        startActivity(i);
        return true;
    }
    else if (id == R.id.action_about){
        // 1. Instantiate an AlertDialog.Builder with its constructor
        AlertDialog.Builder builder = new AlertDialog.Builder(this);

        // 2. Chain together various setter methods to set the dialog characteristics
        if (Constants.DEBUG_BUILD == true) {
            builder.setMessage("v." + MyStatusHandler.getReleaseVersionNum() + " dev Build: " + MyStatusHandler.getDevVersionNum())
                    .setTitle("About")
                    .setCancelable(false)
                    .setPositiveButton("OK", null);
        }
        else{
            builder.setMessage("v." + MyStatusHandler.getReleaseVersionNum())
                    .setTitle("About")
                    .setCancelable(false)
                    .setPositiveButton("OK", null);
        }

        // 3. Get the AlertDialog from create()
        AlertDialog dialog = builder.create();

        // show it
        dialog.show();

        return true;
    }

    return super.onOptionsItemSelected(item);
}

// check email entered
public boolean isSettingsEntered(){
    boolean result = true;

    if (MyStatusHandler.getEmailText().equals("") || MyStatusHandler.getPasswordText().equals("")){
        // 1. Instantiate an AlertDialog.Builder with its constructor
        AlertDialog.Builder builder = new AlertDialog.Builder(this);

        // 2. Chain together various setter methods to set the dialog characteristics
        builder.setMessage("Please ensure both email and password are entered in settings")
                .setTitle("Email and/or Password not set")
                .setCancelable(false)
                .setPositiveButton("OK",null);

        // 3. Get the AlertDialog from create()
        AlertDialog dialog = builder.create();

        // show it
        dialog.show();

        result = false;
    }

    return result;
}

/** Called when the user clicks the Opt in button */
public void startService(View view) {
    // Do something in response to button

    if (isSettingsEntered() && isLocationEnabled(getApplicationContext())) {
        // send opt in to web service
        ...;
        // start service
        startService(new Intent(this, BackgroundLocationService.class));

        // update status text
        String msg = "Connecting ...";
        MyStatusHandler.setStatusText(msg);
    }
}

/** Called when the user clicks the Opt out button */
public void stopService(View view) {
    // Do something in response to button

    if (isSettingsEntered() && isLocationEnabled(getApplicationContext())) {
        // send OptOut to web service
        ...;

        // update status text
        String msg = "Connecting ...";
        MyStatusHandler.setStatusText(msg);
    }
}

public static void ...(boolean isOptIn, Location location, boolean sendOptIn){
    if (sendOptIn)
    {
        // send opt in via async task
    }
    else{
       // send location via async task
    }
}

// Handle results returned to the FragmentActivity by Google Play services
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    // Decide what to do based on the original request code
    switch (requestCode) {
        case Constants.CONNECTION_FAILURE_RESOLUTION_REQUEST :
            // log the error
            MyStatusHandler.logDataToFile("Connection Failure Resolution Request - Result Code: "+String.valueOf(resultCode));
            // If the result code is Activity.RESULT_OK, try to connect again
            switch (resultCode) {
                case Activity.RESULT_OK :
                    // Try the request again
                    MyStatusHandler.logDataToFile("Attempting to re-start service");
                    // start service
                    startService(new Intent(this, BackgroundLocationService.class));
                    break;
            }
    }
}
}

Here is the help desk:

public class BackgroundLocationService extends Service implements
    GoogleApiClient.ConnectionCallbacks,
    GoogleApiClient.OnConnectionFailedListener,
    LocationListener {

public static final String TAG = BackgroundLocationService.class.getSimpleName();

private GoogleApiClient mGoogleApiClient;
private boolean mInProgress;

private LocationRequest mLocationRequest;

public void onCreate(){
    super.onCreate();

    mGoogleApiClient = new GoogleApiClient.Builder(this)
         .addConnectionCallbacks(this)
            .addOnConnectionFailedListener(this)
            .addApi(LocationServices.API)
            .build();
}

@Override
public int onStartCommand (Intent intent, int flags, int startId) {
    super.onStartCommand(intent, flags, startId);

    if(mGoogleApiClient.isConnected() || mInProgress)
        return START_STICKY;


    if(!mGoogleApiClient.isConnected() || !mGoogleApiClient.isConnecting() && !mInProgress) {
        mInProgress = true;
        mGoogleApiClient.connect();
    }

    return START_STICKY;
}

@Override
public IBinder onBind(Intent intent) {
    // TODO: Return the communication channel to the service.
    throw new UnsupportedOperationException("Not yet implemented");
}

@Override
public void onConnected(Bundle bundle) {
    mLocationRequest = LocationRequest.create()
            .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
            .setFastestInterval(Constants.FASTEST_INTERVAL)
            .setInterval(Constants.UPDATE_INTERVAL);

    PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0,
            new Intent(this, MyLocationHandler.class),
            PendingIntent.FLAG_CANCEL_CURRENT);

    if (mGoogleApiClient.isConnected()) {
        LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, pendingIntent);
    }
    else{
        MyStatusHandler.setStatusText("Google Client Failed");
    }
}

@Override
public void onConnectionSuspended(int i) {

}

@Override
public void onLocationChanged(Location location) {

}

@Override
public void onConnectionFailed(ConnectionResult connectionResult) {
    mInProgress = false;

    if (connectionResult.hasResolution()) {
        try {
            // Start an Activity that tries to resolve the error
            connectionResult.startResolutionForResult(null, Constants.CONNECTION_FAILURE_RESOLUTION_REQUEST);

            // * Thrown if Google Play services canceled the original
            // * PendingIntent

        } catch (IntentSender.SendIntentException e) {
            // Log the error
            e.printStackTrace();
        }
    } else {

        //* If no resolution is available, display a dialog to the
        // * user with the error.

        Log.i(TAG, "Location services connection failed with code " + connectionResult.getErrorCode());
        MyStatusHandler.setStatusText("Location services connection failed with code " + connectionResult.getErrorCode());
    }
}

@Override
public void onDestroy(){
    mInProgress = false;
    if (mGoogleApiClient.isConnected()) {
        LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
        mGoogleApiClient.disconnect();
    }
    super.onDestroy();
}
}

Here is the broadcast receiver:

public class MyLocationHandler extends BroadcastReceiver {

@Override
public void onReceive(Context context, Intent intent) {
    Location location = intent.getParcelableExtra(FusedLocationProviderApi.KEY_LOCATION_CHANGED);

    if (location != null && MyStatusHandler.getOptInStatus()) {
        // debug messages
        String msg = Double.toString(location.getLatitude()) + "," +
                Double.toString(location.getLongitude());
        Log.d("debug", msg);

        // log location to file
        MyStatusHandler.logDataToFile("Location: "+msg);

        // send Location to web service
        MainActivity....(MyStatusHandler.getOptInStatus(), location, false);
    }

    if (location == null){
        MyStatusHandler.logDataToFile("Location == NULL!");
    }
}
}

I set the interval to 5 minutes and Fast to 2 minutes. NOTE. I removed some function calls and code for web service operations.

, , , - . , OptInStatus , NULL.

- .

+4

Source: https://habr.com/ru/post/1620021/


All Articles