Solucionado (ver solução)
Solucionado
(ver solução)
2
respostas

Continuar recebendo a localização GPS, em background, mesmo após a App ser fechada

Estou construindo uma App que recebe a localização do usuário, porém preciso receber a localização mesmo quando essa é fechada, criei um Service mesmo assim quando a app é fechada perco a localização.

public class GPSService extends Service {
private LocationListener locationListener;
private LocationManager locationManager;


@Override
public IBinder onBind(Intent intent) {
    return null;
}

@Override
public void onCreate() {
    iniciaNavegacao();
    super.onCreate();
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    return START_STICKY;
}

@Override
public void onDestroy() {
    super.onDestroy();
    if (locationManager != null) {
        locationManager.removeUpdates(locationListener);
    }
}

@SuppressLint("MissingPermission")
public void iniciaNavegacao() {
    locationListener = new LocationListener() {
        @Override
        public void onLocationChanged(Location location) {
            Log.i("teste de localizacao", "Localizacao: " + location.toString());

            float velocidade = location.getSpeed();
            Double velocidadeEmKm = velocidade * 3.6;
            Intent intent = new Intent("atualizacao_localizacao");
            intent.putExtra("latitude", location.getLatitude());
            intent.putExtra("longitude", location.getLongitude());
            intent.putExtra("velocidade", velocidadeEmKm);
            sendBroadcast(intent);
        }

        @Override
        public void onStatusChanged(String provider, int status, Bundle extras) {

        }

        @Override
        public void onProviderEnabled(String provider) {

        }

        @Override
        public void onProviderDisabled(String provider) {
            Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            startActivity(intent);
        }
    };
    locationManager = (LocationManager) getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
    locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener);
}
}
2 respostas

Código da Activity

public class NavegacaoActivity extends AppCompatActivity {


private String[] permissoes = new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION};
private TextView txtLat, txtLong, txtVelocidade, txtParcial;
private FloatingActionButton fab;
private Boolean seguirCronometro = false; // será utilizado ao inserir o cronometro
private BroadcastReceiver broadcastReceiver;

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

    txtLat = findViewById(R.id.txtLatitude);
    txtLong = findViewById(R.id.txtLongitude);
    txtVelocidade = findViewById(R.id.txtVelocidade);
    txtParcial = findViewById(R.id.txtParcial);

    fab = findViewById(R.id.fabIniciarTreino);

    Permissoes.validarPermissoes(permissoes, this, 1);

    txtParcial.setText("Não passou");

    fab.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if (seguirCronometro == false) {
                // inicia cronometro e muda o icone
                Intent intent = new Intent(getApplicationContext(), GPSService.class);
                startService(intent);
                seguirCronometro = true;
                fab.setImageResource(R.drawable.ic_stop_white_24dp);
            } else if (seguirCronometro == true) {
                // para o cronometro, muda o icone e oferece a opção de salvar no firebase( mostrará a lista de voltas no teste)
                Intent intent = new Intent(getApplicationContext(), GPSService.class);
                stopService(intent);
                seguirCronometro = false;
                fab.setImageResource(R.drawable.ic_play_arrow_white_24dp);
            }
        }
    });
}

@Override
protected void onResume() {
    super.onResume();
    if (broadcastReceiver == null) {
        broadcastReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                txtLat.setText(String.valueOf(intent.getExtras().get("latitude")));
                txtLong.setText(String.valueOf(intent.getExtras().get("longitude")));
                txtVelocidade.setText(String.valueOf(intent.getExtras().get("velocidade")));
            }
        };
    }
    registerReceiver(broadcastReceiver, new IntentFilter("atualizacao_localizacao"));
}

@Override
protected void onDestroy() {
    super.onDestroy();
    if (broadcastReceiver != null) {
        unregisterReceiver(broadcastReceiver);
    }
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    for (int permissaoResultado : grantResults) {
        if (permissaoResultado == PackageManager.PERMISSION_DENIED) {
            //Alerta
            alertaValidacaoPermissao();
        }
    }
}

private void alertaValidacaoPermissao() {
    AlertDialog.Builder builder = new AlertDialog.Builder(this);
    builder.setTitle(getResources().getString(R.string.permissoes_negadas));
    builder.setMessage(getResources().getString(R.string.mensagem_permissoes_negadas));
    builder.setCancelable(false);
    builder.setPositiveButton(getResources().getString(R.string.confirmar_permissoes_negadas), new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialogInterface, int i) {
            Permissoes.validarPermissoes(permissoes, NavegacaoActivity.this, 1);
        }
    });

    builder.setNegativeButton(getResources().getString(R.string.negar_permissoes_negadas), new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            finish();
        }
    });
    AlertDialog dialog = builder.create();
    dialog.show();
}}
solução!

Esse código parece funcionar em versões mais antigas do Android. Atualmente, qualquer Service rodando em background deve indicar isso para o usuário por meio de uma notificação, do contrário o sistema matará esse Service quando a aplicação for fechada.

A junção de uma notificação com um Service é o que chamamos de foreground Service.

Quer mergulhar em tecnologia e aprendizagem?

Receba a newsletter que o nosso CEO escreve pessoalmente, com insights do mercado de trabalho, ciência e desenvolvimento de software