Android selben Service mehrmals Aufrufen

droidStep

Mitglied
Hallo leute :meld:
ich programmiere schon etwas länger android apps, allerdings brauche ich jetzt zum ersten mal die service klasse. Ich möchte eine app programmieren bei der man ereignisse erstellen kann zu welcher uhrzeit was geschehen soll. dazu brauche ich eine activity in der man neue ereignisse hinzufügen kann und einen service der dies dann zur gegebenen uhrzeit ausführt. Das klappt schon ganz gut bis auf dass wenn ich zb einen service für 16:30 festgelegt habe und anschließend einen zweiten um 17:00 dann wird der erste einfach "überschrieben" und nur der zweite wird ausgeführt. Beide werden von derselben service klasse ausgeführt. Liegt vielleicht hierbei das problem?

die Methode die den Service erstellt:
Java:
private void createService(int function, int hour, int minute, int on_or_off){
    	int extra = function*2+on_or_off;
    	
    	Intent intent = new Intent(AddEreignisActivity.this, EasyManagerService.class);
    	intent.putExtra("function", extra);
    	PendingIntent pendingIntent = PendingIntent.getService(AddEreignisActivity.this, 0, intent, 0);
    	
    		
    	AlarmManager alarmManager = (AlarmManager)getSystemService(ALARM_SERVICE);
  	           
    	Calendar calendar = Calendar.getInstance();
    	int hour_dif = hour-calendar.get(Calendar.HOUR_OF_DAY);
    	int minute_dif = minute-calendar.get(Calendar.MINUTE);
    	int second_dif = -calendar.get(Calendar.SECOND);
    	calendar.add(Calendar.HOUR_OF_DAY, hour_dif);
    	calendar.add(Calendar.MINUTE, minute_dif);
    	calendar.add(Calendar.SECOND, second_dif);
    	
    	alarmManager.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
    }

wenn ich nun diese methode 2 mal mit zb anderen zeitwerten aufrufe wird nur der zuletzt erstellte service ausgeführt.

Und ich hätte nocheine frage: geht es dass ich einen service erstelle der regelmäßig (also zb jeden montag um 17:00) ausgeführt wird?

danke schonmal für eure antworten 🙂
 
Hallo,

also das mit dem AlarmManager sieht erstmal gut aus. Allerdings beim PedingIntent.getService, gibst du als Flags 0 an, keine Ahnung was für Auswirkungen das hat.

Schau mal hier nach den Flags: PendingIntent | Android Developers

Spontan würde das Flag Update current am besten passen. Dann läuft dein Service zwar auch nur einmal, aber wenn er schon läuft wird einfach die onStart Methode dann aufgerufen ohne ihn nochmal zu kreieren.

EDIT: Ne warte mal, genau das ist das Problem was du ja hast, das der alte einfach überschrieben wird.

Vielleicht doch FLAG_ONE_SHOT? Obwohl ich nciht so ganz verstehe was das jetzt macht.
 
Zuletzt bearbeitet:
Was genau hast du vor? Warum willst du einem Service in zeitlichen Abständen Intents senden?

So ganz sinnvoll erscheint mir das im Moment nämlich nicht.

Und wie genau läuft der Service? Es gibt nämlich immer nur einen und dieser eine Service muss in onStartCommand auf eintrudelnden Intents reagieren. (oder du verwendest einen Binding, aber das ist noch ungeeigneter)
 
Zuletzt bearbeitet:
Vielleicht doch FLAG_ONE_SHOT? Obwohl ich nciht so ganz verstehe was das jetzt macht.

jetzt startet auch nur der 2. service allerdings wird das extra vom 1. service übergeben ???:L


Was genau hast du vor? Warum willst du einem Service in zeitlichen Abständen Intents senden?

So ganz sinnvoll erscheint mir das im Moment nämlich nicht.

Und wie genau läuft der Service? Es gibt nämlich immer nur einen und dieser eine Service muss in onStartCommand auf eintrudelnden Intents reagieren. (oder du verwendest einen Binding, aber das ist noch ungeeigneter)

der service soll zb um 15:00 wlan einschalten (was im extra "function" gespeicher ist) und um zb 17:00 wlan wieder ausschalten.
was ist ein binding genau bin mit google schon drauf gestoßen weiss aber nich genau was das ist. hat was mit der onBind() methode zu tun oder?
 
OK, dann solltest du das vielleicht als IntentService und nicht als Service abbilden. Der Unterschied zwischen IntentService und Service ist der, dass der IntentService sich vollkommen autark um den eigenen Lifecycle kümmert und sich eine Job-Queue aufbaut falls mehrere Intents auf einmal reintrudeln. Die werden dann seriell hintereinander in einem eigenen Thread ausgeführt.

Warum ist das gut? In deiner Service-Implementierung ist der Hund drin. Du willst ja nicht jedes Mal einen neuen Service öffnen, was ja so gar nicht funktioniert, du brauchst einen einzigen Service der zu bestimmten Zeitpunkten Aktionen durchführt. Wie diese Aktionen aussehen definierst du am besten anhand des Intents. Da steht dann z.B. der Name der Klasse drinnen die instanziert werden soll oder einfach nur die Request-ID als Integer und der IntentService reagiert darauf.

Java:
public class MyIntentService extends IntentService {
  public static final String REQUEST_ID = "REQUEST_ID";

  // [...] default methoden die gebraucht werden. Weiß ich nicht auswendig

  // diese methode wird aufgerufen sobald der intent eintrudelt. 
  // Wann er eintrudelt regelst du mit dem Alarm-Manager
  // und den PendingIntents.
  public void onHandleIntent(Intent job) {
    int reqID = job.getExtras().getInt(REQUEST_ID);

    switch(reqID) {
      case 0: // [...] wlan aufdrehen
         break; 
      case 1: // [...] zeug runterladen
         break;
    }
  }
}
 
logcat:
Code:
07-09 14:55:42.493: D/dalvikvm(20439): GC_CONCURRENT freed 108K, 2% free 9183K/9351K, paused 2ms+3ms
07-09 14:55:42.608: D/dalvikvm(20439): GC_CONCURRENT freed 255K, 4% free 9406K/9735K, paused 3ms+2ms
07-09 14:56:09.283: D/dalvikvm(20439): newInstance failed: no <init>()
07-09 14:56:09.288: D/AndroidRuntime(20439): Shutting down VM
07-09 14:56:09.288: W/dalvikvm(20439): threadid=1: thread exiting with uncaught exception (group=0x40c421f8)
07-09 14:56:09.298: E/AndroidRuntime(20439): FATAL EXCEPTION: main
07-09 14:56:09.298: E/AndroidRuntime(20439): java.lang.RuntimeException: Unable to instantiate service my.easy.manager.EasyManagerService: java.lang.InstantiationException: can't instantiate class my.easy.manager.EasyManagerService; no empty constructor
07-09 14:56:09.298: E/AndroidRuntime(20439): 	at android.app.ActivityThread.handleCreateService(ActivityThread.java:2249)
07-09 14:56:09.298: E/AndroidRuntime(20439): 	at android.app.ActivityThread.access$1600(ActivityThread.java:127)
07-09 14:56:09.298: E/AndroidRuntime(20439): 	at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1213)
07-09 14:56:09.298: E/AndroidRuntime(20439): 	at android.os.Handler.dispatchMessage(Handler.java:99)
07-09 14:56:09.298: E/AndroidRuntime(20439): 	at android.os.Looper.loop(Looper.java:137)
07-09 14:56:09.298: E/AndroidRuntime(20439): 	at android.app.ActivityThread.main(ActivityThread.java:4507)
07-09 14:56:09.298: E/AndroidRuntime(20439): 	at java.lang.reflect.Method.invokeNative(Native Method)
07-09 14:56:09.298: E/AndroidRuntime(20439): 	at java.lang.reflect.Method.invoke(Method.java:511)
07-09 14:56:09.298: E/AndroidRuntime(20439): 	at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:790)
07-09 14:56:09.298: E/AndroidRuntime(20439): 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:557)
07-09 14:56:09.298: E/AndroidRuntime(20439): 	at dalvik.system.NativeStart.main(Native Method)
07-09 14:56:09.298: E/AndroidRuntime(20439): Caused by: java.lang.InstantiationException: can't instantiate class my.easy.manager.EasyManagerService; no empty constructor
07-09 14:56:09.298: E/AndroidRuntime(20439): 	at java.lang.Class.newInstanceImpl(Native Method)
07-09 14:56:09.298: E/AndroidRuntime(20439): 	at java.lang.Class.newInstance(Class.java:1319)
07-09 14:56:09.298: E/AndroidRuntime(20439): 	at android.app.ActivityThread.handleCreateService(ActivityThread.java:2246)
07-09 14:56:09.298: E/AndroidRuntime(20439): 	... 10 more
 
als ich noch keinen Konstruktor hatte wurde ich dazu aufgefordert einen hinzuzufügen und als ich ihn automatisch hinzufügen lies erschien das hier:
Java:
public EasyManagerService(String name) {
		super(name);
		// TODO Auto-generated constructor stub
	}

wenn ich den parameter entferne und statt super(name) super(null) schreibe gehts auch nicht und super() kann ich nicht weglassen
 
Ich weiß, das ist ganz angenehm wenn einer so blöd ist und einem die Doku übersetzt, aber in Zukunft schau doch einfach nach wofür das gut ist.

Der Konstruktor mit einem String-Parameter ist dafür da, um einen Namen zu setzen. Also musst du in deinem Konstruktor ohne Parameter super aufrufen mit einem Namen. Denn kannst du dir aussuchen. Der qualifizierte Typname bietet sich an.

Java:
public EasyManagerService() {
  super(EasyManagerService.class.getName());
}
 
ok danke
ich will ja nich auf die nerven gehn aber jetzt gehts immernoch nich:
logcat:
Code:
07-09 15:15:33.263: I/Process(21806): Sending signal. PID: 21806 SIG: 9
07-09 15:16:36.503: I/dalvikvm(22436): Turning on JNI app bug workarounds for target SDK version 10...
07-09 15:16:36.618: D/AndroidRuntime(22436): Shutting down VM
07-09 15:16:36.618: W/dalvikvm(22436): threadid=1: thread exiting with uncaught exception (group=0x40c421f8)
07-09 15:16:36.618: E/AndroidRuntime(22436): FATAL EXCEPTION: main
07-09 15:16:36.618: E/AndroidRuntime(22436): java.lang.RuntimeException: Unable to start service my.easy.manager.EasyManagerService@414e9608 with Intent { flg=0x4 cmp=my.easy.manager/.EasyManagerService (has extras) }: java.lang.NullPointerException
07-09 15:16:36.618: E/AndroidRuntime(22436): 	at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:2388)
07-09 15:16:36.618: E/AndroidRuntime(22436): 	at android.app.ActivityThread.access$1900(ActivityThread.java:127)
07-09 15:16:36.618: E/AndroidRuntime(22436): 	at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1222)
07-09 15:16:36.618: E/AndroidRuntime(22436): 	at android.os.Handler.dispatchMessage(Handler.java:99)
07-09 15:16:36.618: E/AndroidRuntime(22436): 	at android.os.Looper.loop(Looper.java:137)
07-09 15:16:36.618: E/AndroidRuntime(22436): 	at android.app.ActivityThread.main(ActivityThread.java:4507)
07-09 15:16:36.618: E/AndroidRuntime(22436): 	at java.lang.reflect.Method.invokeNative(Native Method)
07-09 15:16:36.618: E/AndroidRuntime(22436): 	at java.lang.reflect.Method.invoke(Method.java:511)
07-09 15:16:36.618: E/AndroidRuntime(22436): 	at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:790)
07-09 15:16:36.618: E/AndroidRuntime(22436): 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:557)
07-09 15:16:36.618: E/AndroidRuntime(22436): 	at dalvik.system.NativeStart.main(Native Method)
07-09 15:16:36.618: E/AndroidRuntime(22436): Caused by: java.lang.NullPointerException
07-09 15:16:36.618: E/AndroidRuntime(22436): 	at android.app.IntentService.onStart(IntentService.java:116)
07-09 15:16:36.618: E/AndroidRuntime(22436): 	at my.easy.manager.EasyManagerService.onStart(EasyManagerService.java:47)
07-09 15:16:36.618: E/AndroidRuntime(22436): 	at android.app.IntentService.onStartCommand(IntentService.java:130)
07-09 15:16:36.618: E/AndroidRuntime(22436): 	at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:2371)
07-09 15:16:36.618: E/AndroidRuntime(22436): 	... 10 more
 
07-09 15:16:36.618: E/AndroidRuntime(22436): Caused by: java.lang.NullPointerException
07-09 15:16:36.618: E/AndroidRuntime(22436): at android.app.IntentService.onStart(IntentService.java:116)
07-09 15:16:36.618: E/AndroidRuntime(22436): at my.easy.manager.EasyManagerService.onStart(EasyManagerService.java:47)

Exceptions, wenn du Glück hast, sagen dir eh alles was du brauchst. Diese tut es. Da ist was null was nicht null sein soll in Zeile 47 von EasyManagerService.java.
 
hab das problem gelöst indem ich bei

Java:
@Override
	public void onStart(Intent intent, int startId){
		super.onStart(intent, startId);
		
	}

des
Java:
super.onStart(intent, startId);

rausgenommen habe.
darf ich das?
naja jetzt funktionierts ohne absturz allerdings wird immernoch nur die 2. aufgabe ausgeführt

[EDIT]hab ne bessere lösung gefunden:
Java:
@Override
    public int onStartCommand(Intent intent, int flags, int startId) {

		super.onStartCommand(intent, startId, startId);
		
     	return START_STICKY;
	}
[/EDIT]

ich versteh zwar nicht was das bedeutet aber ich hab nach langem googlen das hier gefunden und es funktioniert ^^
 
Zuletzt bearbeitet:
ich weiss jetzt warum der service nicht 2 mal "aufgerufen" sondern nur "überschrieben" wird

Java:
AlarmManager alarmManager = (AlarmManager)getSystemService(ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC, calendar.getTimeInMillis(), pendingIntent);

in der definition von alarmManager.set() steht "If there is already an alarm for this Intent scheduled (with the equality of two intents being defined by filterEquals(Intent)), then it will be removed and replaced by this one. "

bedeutet doch dass er den ersten intent einfach überschreibt wenn ich diese methode ein zweites mal aufzufe oder?

aber wie umgehe ich das jetzt am besten?
 
bedeutet doch dass er den ersten intent einfach überschreibt wenn ich diese methode ein zweites mal aufzufe oder?
Ja, so sehe ich das auch. Ziemlich blöd wenn du mich fragst. Wie das zu überschreiben ist, ist eine gute Frage. Ich glaube du musst da einen Workaround bauen.

Also wenn du so einen Alarm setzen willst, musst du erst einmal den neuen Alarm speichern. Dann setzt du per AlarmManager den neuen Alarm wenn er vor dem frühesten der anderen Alarme sitzt.

Wenn dann ein Alarm feuert, setzt du im Service anhand deiner gespeicherten Liste den Intent neu und löscht den Eintrag aus deiner Datenbank/File/was auch immer.

Möglicherweise sind die Leute auf Stackoverflow gescheiter, frag dort auch mal anch.
 
ok an sowas ähnliches hatte ich auch schon gedacht, hab aber gehofft es geht auch einfacher und sicherer. Dann werd ichs mal so machen.

Danke nochmal für die Hilfe ! 🙂
 

Zurück
Oben