Je suis en train de créer une application similaire à l'application intégrée SMS.
Ce dont j'ai besoin:
Ce que j'ai essayé
- exécuter un service régulier qui fonctionnait parfaitement jusqu'à ce que Android tue le service
- en utilisant AlarmManager pour faire les 5 min. appel d'intervalle à un service. Mais je n'ai pas pu faire ce travail.
un service toujours actif l'arrière-plan
C'est impossible dans le vrai sens du terme, comme vous l'avez découvert. C'est aussi mauvais design .
toutes les 5 min. le service vérifie le emplacement actuel de l'appareil et appelle un service web
Utilisez AlarmManager
.
en utilisant AlarmManager, faites le 5 min. appel d'intervalle à un service. Mais je n'a pas pu faire ce travail.
Voici un exemple de projet montrant comment en utiliser un, ainsi que/ WakefulIntentService
afin que vous restiez éveillé tout en essayant de faire tout le travail du Web.
Si vous avez toujours des problèmes avec cela, posez une nouvelle question sur les choses spécifiques que vous rencontrez avec AlarmManager
qui vous causent du chagrin.
Une de mes applications fait quelque chose de très similaire. Pour réactiver le service après une période donnée, je recommande postDelayed()
Avoir un champ de gestionnaire:
private final Handler handler = new Handler();
et un recyclage Runnable
private final Runnable refresher = new Runnable() {
public void run() {
// some action
}
};
Vous pouvez déclencher vos notifications dans le runnable.
Lors de la construction du service, et après chaque exécution, démarrez comme suit:
handler.postDelayed(refresher, /* some delay in ms*/);
Dans onDestroy()
supprimer le message
handler.removeCallbacks(refresher);
Pour démarrer le service au démarrage, vous avez besoin d'un démarreur automatique. Cela va dans votre manifeste
<receiver Android:name="com.example.ServiceAutoStarter">
<intent-filter>
<action Android:name="Android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
et la ServiceAutoStarter
ressemble à ceci:
public class ServiceAutoStarter extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
context.startService(new Intent(context, UpdateService.class));
}
}
Empêcher le système d'exploitation de tuer le service est délicat. De plus, votre application peut avoir une valeur RuntimeException
et se bloquer, ou votre logique peut rester bloquée.
Dans mon cas, il a semblé utile de toujours actualiser le service à l'écran avec une variable BroadcastReceiver
. Donc, si la chaîne de mises à jour est bloquée, elle sera ressuscitée à mesure que l'utilisateur utilise son téléphone.
Dans le service:
private BroadcastReceiver screenOnReceiver;
Dans votre service onCreate()
screenOnReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
// Some action
}
};
registerReceiver(screenOnReceiver, new IntentFilter(Intent.ACTION_SCREEN_ON));
Puis annulez l'enregistrement de votre service sur onDestroy()
avec
unregisterReceiver(screenOnReceiver);
Vous pouvez le faire par une implémentation simple:
public class LocationTrace extends Service implements LocationListener{
// The minimum distance to change Updates in meters
private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 10; // 10 meters
private static final int TWO_MINUTES = 100 * 10;
// The minimum time between updates in milliseconds
private static final long MIN_TIME_BW_UPDATES = 1000 * 10; // 30 seconds
private Context context;
double latitude;
double longitude;
Location location = null;
boolean isGPSEnabled = false;
boolean isNetworkEnabled = false;
protected LocationManager locationManager;
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
this.context = this;
get_current_location();
// Toast.makeText(context, "Lat"+latitude+"long"+longitude,Toast.LENGTH_SHORT).show();
return START_STICKY;
}
@Override
public void onLocationChanged(Location location) {
if((location != null) && (location.getLatitude() != 0) && (location.getLongitude() != 0)){
latitude = location.getLatitude();
longitude = location.getLongitude();
if (!Utils.getuserid(context).equalsIgnoreCase("")) {
Double[] arr = { location.getLatitude(), location.getLongitude() };
// DO ASYNCTASK
}
}
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
@Override
public void onProviderEnabled(String provider) {
}
@Override
public void onProviderDisabled(String provider) {
}
/*
* Get Current Location
*/
public Location get_current_location(){
locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
isGPSEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
isNetworkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
if(!isGPSEnabled && !isNetworkEnabled){
}else{
if (isGPSEnabled) {
if (location == null) {
locationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER,
MIN_TIME_BW_UPDATES,
MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
if (locationManager != null) {
location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
if (location != null) {
latitude = location.getLatitude();
longitude = location.getLongitude();
// Toast.makeText(context, "Latgps"+latitude+"long"+longitude,Toast.LENGTH_SHORT).show();
}
}
}
}
if (isNetworkEnabled) {
locationManager.requestLocationUpdates(
LocationManager.NETWORK_PROVIDER,
MIN_TIME_BW_UPDATES,
MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
if (locationManager != null) {
if (location != null) {
latitude = location.getLatitude();
longitude = location.getLongitude();
// Toast.makeText(context, "Latgps1"+latitude+"long"+longitude,Toast.LENGTH_SHORT).show();
}
}
}
}
return location;
}
public double getLatitude() {
if(location != null){
latitude = location.getLatitude();
}
return latitude;
}
public double getLongitude() {
if(location != null){
longitude = location.getLongitude();
}
return longitude;
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onDestroy() {
if(locationManager != null){
locationManager.removeUpdates(this);
}
super.onDestroy();
}
}
Vous pouvez commencer le service par ceci:
/*--Start Service--*/
startService(new Intent(Splash.this, LocationTrace.class));
En manifeste:
<service Android:name=".LocationTrace">
<intent-filter Android:priority="1000">
<action Android:name="Android.location.PROVIDERS_CHANGED"/>
<category Android:name="Android.intent.category.DEFAULT"/>
</intent-filter>
</service>
par ces trois étapes, vous pouvez réveiller toutes les 5 minutes la plupart des appareils Android:
1. Définissez votre AlarmManager alternatif pour différentes API:
AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(getApplicationContext(), OwnReceiver.class);
PendingIntent pi = PendingIntent.getBroadcast(getApplicationContext(), 0, i, 0);
if (Build.VERSION.SDK_INT >= 23) {
am.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + (1000 * 60 * 5), pi);
}
else if (Build.VERSION.SDK_INT >= 19) {
am.setExact(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + (1000 * 60 * 5), pi);
} else {
am.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + (1000 * 60 * 5), pi);
}
2. Construisez votre propre BroadcastReceiver statique:
public static class OwnReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
//do all of your jobs here
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(context, OwnReceiver.class);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
if (Build.VERSION.SDK_INT >= 23) {
am.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + (1000 * 60 * 5), pi);
}
else if (Build.VERSION.SDK_INT >= 19) {
am.setExact(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + (1000 * 60 * 5), pi);
} else {
am.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + (1000 * 60 * 5), pi);
}
}
}
3. Ajoutez <receiver>
à AndroidManifest.xml
:
<receiver Android:name=".OwnReceiver" />