Keep Service Running

  • 23 Antworten
  • Letztes Antwortdatum
F

Flocke123

Ambitioniertes Mitglied
4
Ich schon wieder,

Netzwerk passt, Service passt, Notifikationen passen... teils.
Ist das Smartphone im Betriebszustand funktioniert alles einwandfrei.
Jedoch wenn es schlafen geht, kann ich vom Netzwerk keine Pakete mehr empfangen.
Google gibt mir hierzu das Schlagwort "WAKE_LOCK".
Also gut, machen wirs so...
Der Service, der im Hintergrund läuft
Code:
public class MyService extends Service {
		
	private boolean release = false;
	private NotificationManager mNotificationManager;
	private PowerManager pm;
	private WakeLock wl;
		
	public MyService() {
	}
.
.
.

Der AsyncTask, der innerhalb des Services erstellt wird
Code:
public class MyUdpListener extends AsyncTask<String, String, String> {
		
		DatagramSocket socket = null;
		
		@Override
		protected void onPreExecute() {
			Toast.makeText(getApplicationContext(), "Hüpfburg Udp Listener Started", Toast.LENGTH_LONG).show();
			pm = (PowerManager)getApplicationContext().getSystemService(Context.POWER_SERVICE);
			wl = pm.newWakeLock(PowerManager.ACQUIRE_CAUSES_WAKEUP, "UdpListenerWakeLock");		
			super.onPreExecute();
		}

Die App crashed aber beim Start des Services.
Wake Lock Permission ist im Manifest gesetzt.
Und der Emulator hat damit auch keine Probleme. Nur das echte Gerät.
Wodurch ich keine LogCat habe.
Ehrlich gesagt hab ich auch keine Ahnung wie der WakeLock zu handhaben ist.
Ich lese noch Dinge wie acquire() und release().

Ich denke was ich will ist eindeutig. Ich möchte die Notifikationen sofort empfangen, auch wenn das Geräte gerade schläft. Heißt, der Service muss weiterlaufen.

Wäre nett, wenn jemand hierzu ein paar Infos für mich hat.
Bisher wurde mir hier sehr geholfen :thumbup:

Gruß Flo
 
Was wird denn als Fehler ausgegeben, wenn sie crasht?

Der Logcat ist immer vorhanden, wenn du Debug im Handy an hast! Selbst im Sleep-Mode gibt es viele Ausgaben vom System. Und und ein Crash der App beendet auch nicht den Logcat. Debuggen tust du wirklich live übers reale Gerät oder packst du den Code erstmal zur APK und schiebst ihn rüber?

Nebenbei, welche Android Version nutzt du?
 
Hi Nexus,

ich schiebe die .apk aufs handy und führe sie dort aus. Also nix mit Debuggen.
auf dem meinen Galaxy S3 läuft Android 4.3.

Wie funktioniert denn das Debuggen auf dem Gerät?
Und wo finde ich dann die Logcat?

Gruß
 
Du nutzt als IDE sicherlich Eclipse, oder? Unter Window->Show View->Logcat

Das Debuggen geht ganz einfach:
1. Starte bei deinem Gerät USB-Debugging, welches sich in den Entwickleroptionen befindet
2. Verbinde das Gerät mit deinem PC
3. Öffne Eclipse und die Logcat-Konsole - Jetzt wirst du schon viele Ausgaben vom Gerät empfangen
4. Führe deine App via Eclipse aus, indem du Debug As->Android Application auswählst
5. Wähle dein Gerät als Ziel (Diese Auswahl erscheint nur, wenn mehrere Geräte an deinem Rechner angeschlossen sind oder du noch zusätzliche Emulatoren besitzt)

Ab Zeitpunkt des Starts der App siehst du, dass Logcat sich auf deine App fixiert und nur dessen Ausgaben anzeigt, zeitgleich wird die App auf deinem Gerät gestartet. Kann etwas dauern und wenn du die App zuvor schon mal installiert hast, gibt es eine Warnung, weil die App bereits existiert, aber das kannst du ignorieren und die App drüber installieren :)
 
  • Danke
Reaktionen: Flocke123
Sehr sehr cool! Funktioniert one wall free.

Jetzt seh ich auch den Fehler
05-09 10:41:29.545: E/AndroidRuntime(9065): java.lang.RuntimeException: Unable to start service com.example.myudpnotifymeclient.MyService@42678df0 with Intent { act=action.START cmp=com.example.myudpnotifymeclient/.MyService }: java.lang.IllegalArgumentException: Must specify a valid wake lock level.

Code:
public class MyUdpListener extends AsyncTask<String, String, String> {
		
		DatagramSocket socket = null;
		
		@Override
		protected void onPreExecute() {
			Toast.makeText(getApplicationContext(), "Hüpfburg Udp Listener Started", Toast.LENGTH_LONG).show();
			pm = (PowerManager)getApplicationContext().getSystemService(Context.POWER_SERVICE);
			wl = pm.newWakeLock(PowerManager.ACQUIRE_CAUSES_WAKEUP, "UdpListenerWakeLock"); [COLOR="Red"]<- Hier wirft er den Fehler!	[/COLOR]	
			super.onPreExecute();
		}

Must specify a wake lock level.
Tue ich das nicht mit
Code:
PowerManager.ACQUIRE_CAUSES_WAKEUP
?
 
Flocke123 schrieb:
Tue ich das nicht mit
Code:
PowerManager.ACQUIRE_CAUSES_WAKEUP
?

nein das ist nur ein zusätzliches Flag das du setzten kannst. Möglich sind laut Powermanager Beschreibung die Levels:

PARTIAL_WAKE_LOCK
SCREEN_DIM_WAKE_LOCK
SCREEN_BRIGHT_WAKE_LOCK
FULL_WAKE_LOCK
 
Achso.
Habe es mit PARTIAL_WAKE_LOCK versucht.
Jetzt stürzt die App zwar nicht mehr ab, aber Nachrichten empfangen wenn Bildschirm aus, ist auch noch nicht möglich.
ACQUIRE_CAUSES_WAKEUP. so wie ich das lese, würde das handy aufwachen, wenn ich die Methode wl.acquire() aufrufe.
Nur wird ja die Schleife, in der ich auf den Socket lausche, bei Screen Off gar nicht mehr bearbeitet.
Code:
@Override
		protected String doInBackground(String... arg0) {
			try {
				if (socket == null) {
					socket = new DatagramSocket(null);
					SocketAddress socketAddr = new InetSocketAddress(2050);
					socket.setReuseAddress(true);
					socket.setBroadcast(true);
					socket.bind(socketAddr);		
				}										
			} catch (SocketException e) {
				e.printStackTrace();
			}
			
			byte[] buf = new byte[1024];
			DatagramPacket packet = new DatagramPacket(buf, buf.length);
			
			while(release) {
				
				try {
					Log.i("MyUdpListener", "listening...");
					socket.receive(packet);
													
					String message = new String(packet.getData(), 0, packet.getLength());
					publishProgress(message);
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			return null;
		}
Muss ich eventuell speziell den Socket konfigurieren, damit der weiter bearbeitet wird? der Service an sich läuft ja noch weiter meines Erachtens weiter.
 
that really grinds my gears!
Während Stundenlanger Recherche über diesen Bug (meiner Meinung nach) bin ich auf unzählige Artikel und Kommentare von Usern gestoßen, die das selbe Problem haben/hatten.
Das Gerät fährt die CPU Leistung für WiFi auf ein Minimum während des Schlafmodus. Hat zur folge, das einfach keine UDP Packete mehr empfangen werden. Programmausführung bleibt bei socket.receive() stehen. Aktiviert man das Handy (LockScreen ist vollkommend ausreichend), werden ankommende Pakete wieder empfangen.
Jetzt können wir uns einen WiFiLock erstellen.
Google sagt dazu:
Allows an application to keep the Wi-Fi radio awake. Normally the Wi-Fi radio may turn off when the user has not used the device in a while. Acquiring a WifiLock will keep the radio on until the lock is released. Multiple applications may hold WifiLocks, and the radio will only be allowed to turn off when no WifiLocks are held in any application.

Mit dem WiFi Manager und der Konstanten WIFI_MODE_FULL_HIGH_PERF sollen wir die oben beschriebene Problematik lösen können:
Code:
WifiManager wMgr = (WifiManager) getSystemService(Context.WIFI_SERVICE);
		WifiManager.WifiLock wifiLock = wMgr.createWifiLock(WifiManager.WIFI_MODE_FULL_HIGH_PERF, "MyWifiLock");
		wifiLock.acquire();

scheint aber alles nix zu helfen.
Vielleicht definiere ich den Wifi Lock nur an der falschen stelle.
Zu Testzwecken habe ich meinen Code vereinfacht und einen simplen Thread erstellt, der auf Pakete lauschen soll.
Hier mal meine gesamte Klasse MyService

Code:
public class MyService extends Service {
		
	private boolean release = false;
	private NotificationManager mNotificationManager;
	DatagramSocket socket = null;
			
	public MyService() {
	}

		
	@Override
	public void onCreate() {
		Toast.makeText(this, "Hüpfburg Service Created", Toast.LENGTH_LONG).show();
		WifiManager wMgr = (WifiManager) getSystemService(Context.WIFI_SERVICE);
		WifiManager.WifiLock wifiLock = wMgr.createWifiLock(WifiManager.WIFI_MODE_FULL_HIGH_PERF, "MyWifiLock");
		wifiLock.acquire();

		PowerManager pMgr = (PowerManager) getSystemService(Context.POWER_SERVICE);
		PowerManager.WakeLock wakeLock = pMgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyWakeLock");
		wakeLock.acquire();	
		
		super.onCreate();
	}

	@Override
	public IBinder onBind(Intent intent) {
		// TODO: Return the communication channel to the service.
		throw new UnsupportedOperationException("Not yet implemented");
	}

	@Override
	public void onDestroy() {
		Toast.makeText(this, "Hüpfburg Service Destroyed", Toast.LENGTH_LONG).show();
		Log.d("MyService", "onDestroy");
		super.onDestroy();
	}
	
	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		
		if (intent.getAction().equals("action.START")) {
			Toast.makeText(getApplicationContext(), "OnStartCommand Equals Start", Toast.LENGTH_LONG).show();
			release = true;
			//MyUdpListener listener = new MyUdpListener();
			//listener.execute();
			listenUdp();
		
			
		} else if (intent.getAction().equals("action.STOP")) {
			Toast.makeText(getApplicationContext(), "OnStartCommand Equals Stop", Toast.LENGTH_LONG).show();
			release = false;
			
		}
		
		return super.onStartCommand(intent, flags, startId);
	}
	
	private void listenUdp() {
		new Thread(new Runnable() {
			@Override
			public void run() {				
				try {
					if (socket == null) {
						socket = new DatagramSocket(null);
						SocketAddress socketAddr = new InetSocketAddress(2050);
						socket.setReuseAddress(true);
						socket.setBroadcast(true);
						socket.bind(socketAddr);		
					}										
				} catch (SocketException e) {
					e.printStackTrace();
				}
				
				byte[] buf = new byte[1024];
				DatagramPacket packet = new DatagramPacket(buf, buf.length);
				
				while(release) {
					
					try {
						Log.i("MyUdpListener", "listening...");
						socket.receive(packet);
						String message = new String(packet.getData(), 0, packet.getLength());
						System.out.println(message);
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
				
			}
			
		}).start();
	}

Ich hoffe ich bekomme das iwie zum laufen....

Gruß Flo
 
Kurze Frage, läuft Dein Service überhaupt, wenn die App schlafen geht?


Normalerweise läuft ein Service im gleichen Prozess wie der MainThread. Er hat deshalb den gleichen Lifecycle. D.h. geht die App schlafen, geht auch der Service schlafen. Soweit ich weiß, verhindert WifiLock das nicht.

Die einzige Möglichkeit dieses zu verhindern, ist den Service in einen eigenen Prozess auszulagern. Eine einfache Möglichkeit wäre ein Remote Prozess. https://developer.android.com/reference/android/app/Service.html#RemoteMessengerServiceSample
 
Danke Markus.Tullius,

ich verstehe nur nicht, wie mir die Messenger Klasse bei meinem Problem helfen soll. Man findet hierzu auch relativ wenig im Internet. Vielleicht verstehe ich es auch einfach nur nicht.
Stehe immernoch auf den Schlauch. Es kann doch wahrhaftig nicht so schwer sein, einen Service laufen zu lassen, auch wenn das Handy schlafen geht.
Eine spezielle Unterklasse des Service + ein spezieller Aufruf des Service = Service läuft bis ich Stop sage... das kann doch nicht so schwer sein :cursing:
 
markus.tullius schrieb:
Kurze Frage, läuft Dein Service überhaupt, wenn die App schlafen geht?

Ich habe das ganze jetzt ein wenig umgebaut.
Der Broadcast Receiver ist nun ein WakefulBroadcastReceiver.

Code:
public class MyWidgetIntentReceiver extends WakefulBroadcastReceiver {

	private boolean started;
	private Context context;
	private final String PACKAGE_NAME = "com.example.myudpnotifymeclient";
	private final String SERVICE_CLASS_NAME = "com.example.myudpnotifymeclient.MyService";
	private final String TAG = "WidgetReceiver";
	private final String KEY = "ACTION";
	private final String KEY_START = "START";
	private final String KEY_STOP = "STOP";
	
	@Override
	public void onReceive(Context context, Intent intent) {
		this.context = context;		
		if(intent.getAction().equals("action.START")) {
			
			if (!isMyServiceRunning()) {
				startService();		
			} else {
				stopService();
			}
		}
	}
		
	private boolean isMyServiceRunning() {
	    ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
	    for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
	        if (MyService.class.getName().equals(service.service.getClassName())) {
	        	return true;
	        
	        } else {
	        	
	        }
	    }
	    return false;
	}
	
	
	private void startService() {
		Intent i = new Intent();
		i.setClassName(PACKAGE_NAME, SERVICE_CLASS_NAME);
		i.setAction(KEY_START);
		startWakefulService(context, i);
		Log.d(TAG, "serviceStarted()");
		
	}
}

den Service habe ich zu einen IntentService umgewandelt

Code:
public class MyService extends IntentService {
		
	private boolean release = true;
	private NotificationManager mNM;
	DatagramSocket mSocket = null;
	private Intent wakefulIntent;
	private final String KEY = "ACTION";
	private final String KEY_START = "START";
	private final String KEY_STOP = "STOP";
	private final String TAG = "MyService";

	
	public MyService() {
		super("MyService");
		
	}
	
	@Override
	protected void onHandleIntent(Intent intent) {
		Bundle extras = intent.getExtras();
		while(release) {
			
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
			Log.d(TAG, "running...");
		}
		
		MyWidgetIntentReceiver.completeWakefulIntent(intent);
		
	}
	
	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		
		if (intent.getAction().equals(KEY_START)) {
			Toast.makeText(getApplicationContext(), "Command Start", Toast.LENGTH_LONG).show();
			listenUdp();			
			
		} else if (intent.getAction().equals(KEY_STOP)) {
			Toast.makeText(getApplicationContext(), "Command Stop", Toast.LENGTH_LONG).show();
			release = false;
			
		}		
				
		return super.onStartCommand(intent, flags, startId);
	}
	
	private void listenUdp() {
		new Thread(new Runnable() {
			@Override
			public void run() {				
				try {
					if (mSocket == null) {
						mSocket = new DatagramSocket(null);
						SocketAddress socketAddr = new InetSocketAddress(2050);
						mSocket.setReuseAddress(true);
						mSocket.setBroadcast(true);
						mSocket.bind(socketAddr);		
					}										
				} catch (SocketException e) {
					e.printStackTrace();
				}
				
				byte[] buf = new byte[1024];
				DatagramPacket packet = new DatagramPacket(buf, buf.length);
				
				while(release) {
					
					try {
						Log.i("MyUdpListener", "listening...");
						mSocket.receive(packet);
						
						String message = new String(packet.getData(), 0, packet.getLength());
						System.out.println(message);
						
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
				
			}
			
		}).start();
	}

Ich sehe nun, dass der Service tatsächlich noch weiterläuft, aber die UDP Broadcast Pakete weiterhin nicht ankommen.
Meine Vermutung ist, dass das WLAN noch immer blockiert wird.

Mal sehn wies weiter geht.

Gruß Flo
 
Ich bin jetzt an einem Punkt angekommen, an dem ich mir ernsthaft überlege, ob ich nicht auf TCP umschwenken soll. Zumindest für Testzwecke.
Das Internet spuckt auch immer nur die selben Phrasen aus:
"you must create a wifi lock!", "make sure your wifi is running!" .... OMG WTF STFU! :thumbup:
ich habe jetzt jegliche Möglichkeiten versucht. MultiCastSockets, multiCastLocks, usw..... Nichts hat etwas an der aktuellen Problematik geändert: Screen Off verhindert das annehmen von UDP Broadcast Paketen.

Gruß Flocke
 
Ich hab jetzt nicht mehr alles im Kopf was davor steht...
Aber deine Android Settings sind richtig ja? Nicht das dein Handy wlan ausschaltet wenn du das display aus machst...

lg.
 
Das WLAN ist aktiv. Habe das in einer separaten Schleife geprüft. Wenn ich händisch das WLAN deaktiviere, erkennt das auch der Service. So kann ich sicher sein, dass es keine falschen Angaben vom Debugger sind.
 
Nach mehreren Beispielprojekten bin ich nun zu dem Entschluss gekommen, dass die Projektierung meines Systems mit TCP einfach nur ein mega OVERHEAD ist.

Des weiteren ist es schön zu beobachten, dass wenn es mal nicht um eine Frage wie "wie lese ich einen String aus einer ListView" oder "ändere die Farbe des Buttons" geht, die User entweder keinen Bock zu Antworten oder keine Ahnung haben.
Wobei ich selbst auch keine Ahnung hab, sonst würde ich ja nicht fragen.

Im Internet findet man sehr viel über dieses Problem, jedoch sind die Beiträge so veraltet und mit Beispielen veralteter API, sodass es keinen Sinn macht danach zu suchen. Und zu einem Schluss bzw. zu einer Lösung ist auch so ziemlich niemand gekommen. :thumbsup:

Gruß Flocke
 
Schon mal drüber nach gedacht warum keiner ne Antwort weiß? ^^
Weil es wahrscheinlich die meisten App Entwickler Bis jetzt einfach nicht brauchten. Wozu, zur Hölle, sollte man auf dem Handy ein (eigenen) Dienst haben der selbst mit standby Strom Frist?

Gesendet von meinem GT-I9300 mit der Android-Hilfe.de App
 
Über den Sinn und Zweck braucht man doch nicht zu diskutieren.
Es ist nunmal für mich notwendig, eine bestimmte Zeit auf Packete zu hören.

Die Frage ist doch, warum stellt Google Code und Klassen zur Verfügung, die GENAU DAS ermöglichen sollen, und diese dann nicht funktionieren.
Und jetzt kommt mir nicht mit GCM und so'n Zeuch. Wenn ich den Begriff "Cloud" schön höre stellen sich bei mir die Nackenhaare auf. Es gibt einfach Industrielle Bereiche in dieser Welt, die stetige Internetverbindungen meiden. Ja die gibt es wirklich noch.... Schlagwörter wie "Stuxnet" sagen euch bestimmt was. Und jetzt soll ich möglicherweise sensible Daten in die Wolken hauen, von der ich keine Ahnung hab, wer sich dazwischen hängen könnte.

Und da meine Idee und Denkansatz soo simple ist, nervt es mich um so mehr, dass es nicht funktioniert, aus welchen Gründen auch immer.

Danke Google, you make my Day
 
Laut dem ersten Link, den ich bei Google gefunden habe, könnte das ein Treiber-Problem bei Broadcom-Chipsätzen sein. Die aktivieren anscheinend einen Filter, sobald das Gerät in den Sleep-Modus wechselt. Der Filter lässt dann keine UDP-Broadcast-Pakete mehr durch.
 
Hab ich schon gelesen. Man glaubt es kaum, aber ich war sogar schon auf der dritten Seite der Google Suchergebnisse :ohmy:

Auf dem Gerät gibt es laufende Dienste, die ähnliche Aufgaben erfüllen, die aber für den Entwickler gesperrt sind. Was passiert? Die Entwickler wenden Hacks (zb. Rooting) an...

By The Way, mit Windoof oder Äpfel könnte ich meine Idee ohne weiteres umsetzen :scared:
Das sollte Google zu denken geben.
 
Flocke123 schrieb:
Und jetzt soll ich möglicherweise sensible Daten in die Wolken hauen, von der ich keine Ahnung hab, wer sich dazwischen hängen könnte.

Es ist nicht notwendig bei GCM irgendwelche Daten irgendwo hinzusenden.
Aber GCM ist nicht gerade realtime ;-)

BTW: Können beim Apfel Apps überhaupt Dinge im Hintergrund machen? Ich dachte das geht da nicht.

cu
 

Ähnliche Themen

AnnaBauer21
Antworten
14
Aufrufe
1.188
AnnaBauer21
AnnaBauer21
Zurück
Oben Unten