it-swarm.com.de

Wie führe ich einen Dienst immer im Hintergrund aus?

Ich bin gerade dabei, eine App zu erstellen, die der integrierten App SMS ähnelt.

Was ich brauche: 

  • ein Dienst, der immer im Hintergrund ausgeführt wird 
  • alle 5 min. Der Dienst prü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 bei der App SMS). 
  • wenn die Benachrichtigung angeklickt wird, wird der Benutzer zur App geleitet (genau wie die App SMS). 
  • 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 gut funktioniert hat, bis Android den Dienst beendet
- mit dem AlarmManager die 5 min. Intervallaufruf an einen Dienst. Aber ich konnte das nicht schaffen.

72
Thomas H

ein Dienst, der immer in .__ ausgeführt wird. der Hintergrund

Dies ist nicht möglich im wahrsten Sinne des Begriffs, wie Sie festgestellt haben. Es ist auch schlechtes Design .

alle 5 min. Der Dienst prüft die aktueller Standort des Geräts und ruft einen Webdienst auf

Verwenden Sie AlarmManager.

mit dem AlarmManager machen Sie die 5 Mindest. Intervallaufruf an einen Dienst. Aber ich konnte diese Arbeit nicht machen.

Hier ist ein Beispielprojekt , das zeigt, wie ein Projekt verwendet wird, zusammen mit der Verwendung von WakefulIntentService , damit Sie wach bleiben, während Sie versuchen, den gesamten Web-Service zu erledigen.

Wenn Sie weiterhin Probleme damit haben, öffnen Sie eine neue Frage zu den spezifischen Dingen, auf die Sie mit AlarmManager stoßen, die Ihnen Kummer bereiten.

33
CommonsWare

Eine meiner Apps macht etwas sehr Ähnliches. Um den Dienst nach einer bestimmten Zeit aufzuwecken, empfehle ich postDelayed()

Habe 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 in der Runable abfeuern.

Beim Service-Bau und nach jeder Ausführung starten Sie es wie folgt:

handler.postDelayed(refresher, /* some delay in ms*/);

Entferne in onDestroy() den Beitrag

handler.removeCallbacks(refresher);

Um den Dienst beim Booten zu starten, benötigen Sie einen Autostarter. Das geht in dein Manifest

<receiver Android:name="com.example.ServiceAutoStarter">
        <intent-filter>
            <action Android:name="Android.intent.action.BOOT_COMPLETED" />
        </intent-filter>
  </receiver>

und der 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 davon abzuhalten, den Dienst zu beenden. Ihre Anwendung kann auch einen RuntimeException haben und abstürzen, oder Ihre Logik kann zum Stillstand kommen. 

In meinem Fall schien es hilfreich zu sein, den Dienst auf dem Bildschirm immer mit einem BroadcastReceiver zu aktualisieren. Wenn also die Update-Kette blockiert wird, wird sie wiederbelebt, wenn der Benutzer das 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));

Heben Sie dann die Registrierung Ihres Dienstes auf onDestroy() mit auf

unregisterReceiver(screenOnReceiver);
26
Jim Blackler

Sie können dies mit einer einfachen 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 so 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>
3

mit diesen drei Schritten können Sie die meisten Android-Geräte alle 5 Minuten aufwecken:

1. stell deinen 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. <receiver> zu AndroidManifest.xml hinzufügen:

<receiver Android:name=".OwnReceiver"  />
0
MHSFisher