Ich bin gerade dabei, eine App zu erstellen, die der integrierten SMS-App ähnelt.
Was ich brauche:
- Ein Dienst, der immer im Hintergrund ausgeführt wird
- alle 5 min. Der Dienst überprüft den aktuellen Standort des Geräts und ruft einen Webdienst auf
- Wenn bestimmte Kriterien erfüllt sind, sollte der Dienst eine Benachrichtigung generieren (genau wie die SMS-App).
- Wenn Sie auf die Benachrichtigung klicken, wird der Benutzer zur App weitergeleitet (genau wie bei der SMS-App).
- Wenn die App installiert ist, sollte der Dienst gestartet werden
- Wenn das Gerät neu gestartet wird, sollte der Dienst gestartet werden
Was ich versucht habe:
- Ausführen eines regulären Dienstes
, der einwandfrei funktioniert hat, bis Android den Dienst beendet - Verwenden des AlarmManagers, um die 5 Minuten zu erstellen. Intervallaufruf an einen Dienst. Aber ich konnte diese Arbeit nicht machen.
quelle
Toast
) und die Alarme beginnen.PendingIntent
wird jeder vorhandene Alarm dafür gelöschtPendingIntent
. Beachten Sie darüber hinaus, dass dies ein Beispiel aus einem Buch ist und absichtlich nicht versucht wird, alle Szenarien anzusprechen.Eine meiner Apps macht etwas sehr ähnliches. Um den Service nach einer bestimmten Zeit zu aktivieren, empfehle ich
postDelayed()
Haben Sie ein Handlerfeld:
private final Handler handler = new Handler();
und eine Auffrischung
Runnable
private final Runnable refresher = new Runnable() { public void run() { // some action } };
Sie können Ihre Benachrichtigungen im Runnable auslösen.
Beim Serviceaufbau und nach jeder Ausführung wie folgt beginnen:
handler.postDelayed(refresher, /* some delay in ms*/);
In
onDestroy()
entfernen Sie den Beitraghandler.removeCallbacks(refresher);
Um den Dienst beim Booten zu starten, benötigen Sie einen Autostarter. Dies geht in Ihrem Manifest
<receiver android:name="com.example.ServiceAutoStarter"> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED" /> </intent-filter> </receiver>
und das
ServiceAutoStarter
sieht so aus:public class ServiceAutoStarter extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { context.startService(new Intent(context, UpdateService.class)); } }
Es ist schwierig, das Betriebssystem daran zu hindern, den Dienst zu beenden. Auch Ihre Bewerbung kann eine haben
RuntimeException
und abstürzen, oder Ihre Logik kann ins Stocken geraten.In meinem Fall schien es hilfreich zu sein, den Dienst auf dem Bildschirm immer mit einem zu aktualisieren
BroadcastReceiver
. Wenn die Aktualisierungskette ins Stocken gerät, wird sie wiederbelebt, wenn der Benutzer sein Telefon verwendet.Im Dienste:
private BroadcastReceiver screenOnReceiver;
In Ihrem Dienst
onCreate()
screenOnReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { // Some action } }; registerReceiver(screenOnReceiver, new IntentFilter(Intent.ACTION_SCREEN_ON));
Dann heben Sie die Registrierung Ihres Dienstes
onDestroy()
mit aufunregisterReceiver(screenOnReceiver);
quelle
AlarmManager
wird ausreichen.Sie können dies durch eine einfache Implementierung tun:
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(); } }
Sie können den Service folgendermaßen starten:
/*--Start Service--*/ startService(new Intent(Splash.this, LocationTrace.class));
Im Manifest:
<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>
quelle
Mit diesen drei Schritten können Sie die meisten Android-Geräte alle 5 Minuten aktivieren:
1. Stellen Sie Ihren alternativen AlarmManager für verschiedene APIs ein:
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. Erstellen Sie Ihren eigenen statischen BroadcastReceiver:
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. hinzufügen
<receiver>
zuAndroidManifest.xml
:<receiver android:name=".OwnReceiver" />
quelle
Wenn Sie möchten, dass Ihr Dienst ausgeführt wird, bedeutet dies meiner Meinung nach immer, dass er nicht gestoppt wird, wenn die App beendet wird. Wenn Ihre App ausgeführt wird oder sich im Hintergrund befindet, wird Ihr Dienst trotzdem ausgeführt. Wenn Sie die App beenden, während ein Dienst ausgeführt wird, wird die Funktion onTaskRemoved ausgelöst.
@Override public void onTaskRemoved(Intent rootIntent) { Log.d(TAG, "onTaskRemoved: removed"); Calendar calendar = Calendar.getInstance(); calendar.setTimeInMillis(System.currentTimeMillis() + 10000); ((AlarmManager) getSystemService(Context.ALARM_SERVICE)).setExact(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), PendingIntent.getService(getApplicationContext(), 0, new Intent(getApplicationContext(), RegisterReceiverService.class), 0)); super.onTaskRemoved(rootIntent); }
Sobald Sie die App beendet haben, wird der Dienst nach 10 Sekunden gestartet. Hinweis: Falls Sie verwenden möchten
AlarmManager.ELAPSED_REALTIME_WAKEUP
Die Mindestzeit, nach der Sie den Dienst neu starten können, beträgt 15 Minuten.
Denken Sie daran, dass Sie den Dienst auch beim Neustart mit BroadcastReceiver starten müssen.
quelle