ChatClient im Hintergrund aktiv lassen

  • Antworten:20
strato
  • Forum-Beiträge: 11

31.10.2014, 12:14:27 via Website

Hi Leute,

ich beschäftige mich jetzt seit ca 1 Montat mit Android / Java Programmierung und komme eigentlich aus der Web-Welt ( PHP, JavaScript, etc )

Ich habe einen Chat-Server mit NodeJS geschrieben und bin gerade dabei einen AndroidClient zu schreiben.

Bis jetzt komme ich eigentlich auch gut vorran, Login, Senden und Empfange der Nachrichten klappt schon ohne Probleme =)

Jetzt bin ich an dem Punkt angekommen wo ich die Nachrichten natürlich auch Empfangen will wenn die App gerade nicht im vordergrund ist....

Ich habe jetzt schon viel dazu gelesen aber einiges noch nicht ganz verstanden bzw noch nicht entschieden welche die beste Möglichkeit ist.

Hier ein paar Infos:

Chat-Server ist mit NodeJS und socket.io geschrieben

Der Client ist mit Hilfe von github.com/nkzawa/socket.io-client.java implementiert.

Die Nachrichten werden nicht am Client gespeichert sondern nur am Server.

Im Moment Starte ich die Server-Verbindung in mit einem IntenService welche in mit der Funktion startService() starte. In dem Service wird die Verbindung dauerhaft aufrecht erhalten und die Nachrichten per Broadcast an die MainActivity gesendet.

Ich habe eigentlich gedacht das es so schon ganz gut klappt, die Nachrichten werden auch nachdem die App im Hintergrund ist noch empfangen aber wenn die APP Länger inaktiv ist wird die app trotzdem beendet..

Meine Frage ist jetzt wie ich den Service dauerhaft aktiv halten kann.

Soll ich Google GCM, den WakefulBroadcastReceiver, den AlarmManager oder was ganz anderes verwenden ?

Beste Grüße

strato

PS: Code könnte ich heute abend bei bedarf ergänzen.

Antworten
strato
  • Forum-Beiträge: 11

31.10.2014, 14:05:43 via Website

danke für die schnelle Antwort aber das hat mich jetzt nicht wirklich weiter gebracht...

Soweit ich gelesen habe ist eigentlich GCM die beste möglichkeit zwecks Akkulaufzeit ? Wenn es geht würde ich GCM aber gerne umgehen....

Zum Thema WakeLock hab ich gelesen das man das eigentlich meiden sollte da es die Akkulaufzeit startk beeinflusst oder ist das bei einer Socket Verbindung okey ?

Antworten
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

31.10.2014, 16:17:22 via App

Warum möchtest du GCM umgehen?
Das ist einer der Besten Google Dev dienste.
sonst musst du immer vom Client aus pollen also auch nicht gut Für den Akku.
Socketverbindungen würde ich aus dem Weg gehen wenn die App auch mit Mobilnetz laufen soll

LG Pascal //It's not a bug, it's a feature. :) ;)

Antworten
strato
  • Forum-Beiträge: 11

03.11.2014, 13:01:19 via Website

ich weiß das auf manchen Geräten wo die APP-Laufen soll keine Google-Play Store installiert ist und ich glaube gelesen zu haben das es eine Abhänigkeit ist.

Was spricht denn gegen eine Socketverbindung im Mobilnetz ? Bis jetzt läuft das eigentlich ganz gut, auch mit WLAN / Mobilnetz wechsel.

Das einzige Problem was ich wirklich habe ist die app im Hintergrund dauerhaft aktkiv zu lassen und das so Stromsparen wie möglich.

Antworten
Rafael K.
  • Forum-Beiträge: 2.359

03.11.2014, 14:09:44 via Website

Wenn Du GCM wirklich unbedingt umgehen willst, schau Dir doch mal eine quelloffene IMAP Implementierung an.
Die macht genau das.
K-9 Mail z.B.

AFAIK pollt aber auch IMAP per default alle 24 Minuten, um die Verbindung offen zu halten.

Ich würde mir das aber echt gut überlegen, denn GCM nimmt dir sehr viele Probleme ab.
Z.B. weiß ich nicht wie gut ein 08/15 Server mit so vielen offenen Sockets umgehen kann.

Antworten
strato
  • Forum-Beiträge: 11

03.11.2014, 18:49:44 via Website

also wenn es nicht sein MUSS würde ich den Service umgehen, wenn wirklich alles fehl schlägt werde es mir wohl doch genauer anschauen müssen ^^.

Wenn ich IMAP verwende habe ich aber keinen echtzeitchat mehr?

Mein eigentliches Problem besteht ja "nur" darin das ich nicht ganz verstehe wie ich meine Verbindung im Hintergrund aktiv halten kann... ohne das sie bei längerer inaktivität beendet wird

Grüße

strato

Antworten
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

03.11.2014, 19:05:13 via Website

Wenn du die Verbindung aktiv halten willst musst du
1. den Server pollen -> Nachteil: zieht Daten falls Mobil
2. läuft im Hintergrund -> Zieht Akku

Zu GCM:
Ziemlich viele Leute haben google und nutzen google Play.
Dann ist GCM (google Play halt eine vorraussetzung)
aber wenn du die App im PlayStore uploadest hat der User eh google Apps ergo macht das wenig Sinn ausser du lädst die App in einem Alternativ Store hoch -> nachteil: Weniger Downloads als im PS

LG Pascal

LG Pascal //It's not a bug, it's a feature. :) ;)

Antworten
strato
  • Forum-Beiträge: 11

03.11.2014, 19:26:32 via Website

Wie bereits erwähnt weiß ich das die app auf Geräten ohne Google Play laufen soll....

Es ist auch nicht beabsichtigt die app zu veröffentlichen sondern nur an bestimmte user zu verteilen und das nicht über irgendwelche stores...

Die Nachteile sind mir wie bereits erwähnt bewusst deswegen suche ich ja hier im Forum die beste Lösung, aber halt ohne GCM ^^

Antworten
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

03.11.2014, 19:41:33 via Website

Wie schon immer gesagt die Beste Lösung ist GCM das andere Zeugs halte ich bei dem heutigen Standart nicht mehr sinnvoll.
Zudem ist es kein hexenwerk sich die Google PlayServices anzubieten oder einen Downloadbutton in die App implementieren.

Du kannst auch sowas hier machen: http://www.eng.nene.ac.uk/~espen/CSY2026/AndroidCSY2026-Week21.htm

Aber da ist dann acuh pollen etc angesagt (auch wenn in einem Service)
Zudem muss der Server tcp oder udp unterstützen d.h. dann reicht ein einfacher http ( bzw. web) Server nicht.
Entweder musst du dann selber einen Server im lokalnetz aufsetzen (kostet Strom) und diesen über dyndns und Portforwarding veröffentlichen oder du benötigst einen Server mit TCP unterstützung, und sowas kann schnell mal teuer werden.

Alternativ kannst du auch externe chat apis nutzen: http://quickblox.com/developers/Android_XMPP_Chat_Sample
Wie das da mit benachrichtigung ist musst du mal lesen.

LG Pascal

LG Pascal //It's not a bug, it's a feature. :) ;)

Antworten
strato
  • Forum-Beiträge: 11

03.11.2014, 20:22:05 via Website

okey das schaut doch schon interessanter aus =)

das mit den Chat-API's fällt leider auch flach, da der Chat für den die APP entsteshen soll mit socket.io geschrieben ist und auf Websockets basiert...

Ich weiß nicht ob ich blind bin aber bei dem Link ( www.eng.nene.ac.uk/~espen/CSY2026/AndroidCSY2026-Week21.htm ) sehe ich auch nicht wie der Chat-Client im Hintergrund aktiv gehalten wird.

Die socketio-jave implementation pollt automatisch und kümmer sich um eine aktive Verbindung und baut bei abbruch sofort wieder eine auf

Antworten
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

03.11.2014, 20:46:16 via Website

Wenn du ein Socket hast (besser gesagt eine instanz davon)
kannst du das mit einem Service lösen, der immer im Hintergrund läuft und dein Socket aktiv hällt besser gesagt die Inszanz spechert, damit du wieder in der App darauf zugreifen kannst.
Ich will aber nochmal betonen dass diese Methode standart von vor (gefühlten) 8 Jahren ist und eigentlich auf Smartphones etc nicht benutzt werden sollte, aber wem sage ich das musst du ja selber wissen.

Wie gesagt schau dir mal einen Android Service an und dann kannst du sagen ob es das Richtige für dich ist.

LG Pascal

— geändert am 03.11.2014, 21:18:09

LG Pascal //It's not a bug, it's a feature. :) ;)

Antworten
strato
  • Forum-Beiträge: 11

03.11.2014, 21:09:30 via Website

Evlt werde ich nicht drum rum kommen, aber ich würde es gerne zu Lernzwecken erstmal ohne implementieren und die app soll halt auch von Usern ohne google play service verwendet werden^^

Im Moment verwende ich einen IntenService, hier mal ein auszug vom Code:

MainActivity:
private void startConnectionService() {
ComponentName componentName = new ComponentName(getApplicationContext().getPackageName(), ConnectionService.class.getName());

    Intent intent = new Intent();
    intent.setComponent(componentName);

    startService(intent);
}

IntenService:

public class ConnectionService extends IntentService {
Socket socket;

public ConnectionService() {
    super("ConnectionService");
}

@Override
protected void onHandleIntent(Intent intent) {
    socket = ConnectionManager.getInstance();

    socket.on("message", new Emitter.Listener() {
        @Override
        public void call(Object... args) {
            JSONObject object = (JSONObject) args[0];

            Intent intent = new Intent("newmessage");
            intent.putExtra("messageData", object.toString());

            LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);

            Vibrator vibrator = (Vibrator) getBaseContext().getSystemService(Context.VIBRATOR_SERVICE);
            vibrator.vibrate(500);
        }
    });
}

}

Aber so wird die app nach einiger Zeit doch beendet...

Oder muss ich hier den startWakefulService verwenden ?

Und evtl. zusätzlich einen AlarmManager verwenden um zu prüfen ob die Verbindung schon da ist?

Wie gesagt beschäftige ich mich erst seit ca 1 Monat mit Java / Android Programmierung und hoffe das mein Ansatz so richtig ist

Antworten
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

03.11.2014, 21:21:59 via App

Warum wird die App beendet bzw. wie (force close/exception etc)?
Wo initialisiert du das socket( kannst auch serverdaten weglassen)?
Vlt. geht ja irgendwas ins timeout.
Vlt ist es sinvoll nach einiger Zeit eine Art "ping" oder Heartbeat zu schicken damit die Conection nicht resettet wird.

LG Pascal //It's not a bug, it's a feature. :) ;)

Antworten
strato
  • Forum-Beiträge: 11

03.11.2014, 21:37:14 via Website

Warum die App beendet wird weiß ich nicht, gibt es Möglichkeiten das genauer heraus zu finden ?

Wenn ich die app mit dem Home-Button in den Hintergrund versetze, werden Nachrichten noch empfangen ( auch so nach 30 Minuten+), aber so ca. nach 1 - 2 Stunden inaktivität nicht mehr...
(Das sind geschätzte Zeiten, genau kann ich es leider nicht sagen)

Die implementation sendet automatisch einen Heartbeat und versucht eigentlich mit allen mitteln eine Verbindung herzustellen, selbst wenn die Verbindung abgebrochen wurde

Hier der Code für die Verbindung:

public class ConnectionManager {

private static Socket connection;

private ConnectionManager() {

}

public static Socket getInstance(TokenManager tokenManager) {
if (connection == null) {

        try {
            connection = IO.socket(Globals.HOST);
        } catch (URISyntaxException e) {
            e.printStackTrace();
        }
    }

    return connection;
}

}

Oben beim ConnectionManager fehlt noch ein:

socket.connect();

direkt nach

socket = ConnectionManager.getInstance();

Hier nochmal der Link zu der Library die ich verwende: github.com/nkzawa/socket.io-client.java

— geändert am 03.11.2014, 21:39:41

Antworten
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

04.11.2014, 00:00:51 via App

Ah ok hatte übersehen dass du die Lib verwendest...
Wie wäre es denn einfach mal ein Log schreiben zu lassen vlt bekommst du das dann ja raus.
Oder in LogCat wird was angezeigt dafür muss dein Device aber die ganze zeit im Debugmodus am usb hängen.
Wenn es immer an einer bestimmten Zeit auftritt lässt es sich vielleicht über ein manuelles reset über einen Timer lösen.

LG Pascal //It's not a bug, it's a feature. :) ;)

Antworten
strato
  • Forum-Beiträge: 11

04.11.2014, 08:12:20 via Website

also ist mein Ansatz richtig und eigentlich müsste es gehen?

Dann werde ich das mit dem Log schreiben mal probieren, das Handy ein paar Stunden am PC hängen zu lassen wird ein bisschen schwierig ^^

Antworten
Rafael K.
  • Forum-Beiträge: 2.359

04.11.2014, 12:11:18 via Website

Du sollst ja auch nicht IMAP verwenden, sondern schauen, wie ein IMAP Client auf Android implementiert ist.
IMAP Push-Mail bei K-9 Mail funktioniert ja bestens, also wird irgendein schlauer Programmierer, alle deine Probleme dort schonmal gelöst haben ;)

strato

Wenn ich IMAP verwende habe ich aber keinen echtzeitchat mehr?

Mein eigentliches Problem besteht ja "nur" darin das ich nicht ganz verstehe wie ich meine Verbindung im Hintergrund aktiv halten kann... ohne das sie bei längerer inaktivität beendet wird

Grüße

strato

Antworten
strato
  • Forum-Beiträge: 11

03.12.2014, 07:00:53 via Website

die imap library war mir ein bisschen zu kompliziert für den anfang deswegen habe ich ein bisschen weiter gesucht und habe folgendes beispiel gefunden: http://github.com/schwiz/android-websocket-example

An sich klappte erstmal alles wieder super, aber dann ist mir aufgefallen das Android die Verbindung im Standby-Modus ohne Event o.ä unterbricht und wenn man in den normalen betrieb zurück kehrt wieder aktiviert....

Hier mal mein kompletter Service-Code: http://pastebin.com/0ASnm9L6

Das Problem ist das dadurch im Standby-Modus keine Nachricht empfangen werden können und mein Client beim wieder aufwachen, warum auch immer, sicher erneut verbindet...

Beste Grüße

strato

— geändert am 03.12.2014, 07:07:50 durch Moderator

Antworten
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

03.12.2014, 07:09:47 via App

Ich habe deine Links mal anklickbar gemacht :)



Du benutzt doch schon WakeLock deswegen weiss ich nich was der Fehler ist.
Versuch mal onResume und onPause noch auszuwerten.

LG Pascal //It's not a bug, it's a feature. :) ;)

Antworten
strato
  • Forum-Beiträge: 11

03.12.2014, 16:47:34 via Website

danke für die Verlinkung =)

soweit ich gelesen habe gibt es bei Services onStop / onResume oder was meinst du genau ?

okey ich habe mir gerade nochmal genauer die Ausgaben angeschaut, hier mal ein auszug aus LogCat:

.......
12-03 10:37:52.400 872-872/com.example.strato.test D/Chat﹕ Ping-Event
12-03 10:37:58.400 872-872/com.example.strato.test D/Chat﹕ websocket is already connected
12-03 10:37:58.400 872-872/com.example.strato.test D/Chat﹕ Ping-Event
12-03 10:38:04.410 872-872/com.example.strato.test D/Chat﹕ websocket is already connected
12-03 10:38:04.410 872-872/com.example.strato.test D/Chat﹕ Ping-Event
12-03 10:38:10.420 872-872/com.example.strato.test D/Chat﹕ websocket is already connected
12-03 10:38:10.420 872-872/com.example.strato.test D/Chat﹕ Ping-Event
12-03 10:38:16.400 872-872/com.example.strato.test D/Chat﹕ websocket is already connected
12-03 10:38:16.410 872-872/com.example.strato.test D/Chat﹕ Ping-Event
12-03 10:38:22.410 872-872/com.example.strato.test D/Chat﹕ websocket is already connected
12-03 10:38:22.410 872-872/com.example.strato.test D/Chat﹕ Ping-Event
12-03 10:38:28.410 872-872/com.example.strato.test D/Chat﹕ websocket is already connected
12-03 10:38:28.410 872-872/com.example.strato.test D/Chat﹕ Ping-Event
12-03 10:38:28.630 872-1182/com.example.strato.test D/Chat﹕ Websocket disconnected
12-03 10:38:28.640 872-872/com.example.strato.test D/Chat﹕ Ping-Event
12-03 10:38:28.950 872-1192/com.example.strato.test D/Chat﹕ Connected to websocket
12-03 10:38:28.950 872-1192/com.example.strato.test D/Chat﹕ Connected to websocket
12-03 10:38:34.410 872-872/com.example.strato.test D/Chat﹕ websocket is already connected
12-03 10:38:34.410 872-872/com.example.strato.test D/Chat﹕ Ping-Event
12-03 10:38:34.430 872-1194/com.example.strato.test D/Chat﹕ recieved ping callback
12-03 10:38:40.410 872-872/com.example.strato.test D/Chat﹕ websocket is already connected
12-03 10:38:40.410 872-872/com.example.strato.test D/Chat﹕ Ping-Event
12-03 10:38:40.430 872-1196/com.example.strato.test D/Chat﹕ recieved ping callback
12-03 10:38:46.410 872-872/com.example.strato.test D/Chat﹕ websocket is already connected
12-03 10:38:46.410 872-872/com.example.strato.test D/Chat﹕ Ping-Event
12-03 10:38:46.420 872-1197/com.example.strato.test D/Chat﹕ recieved ping callback
12-03 10:38:52.400 872-872/com.example.strato.test D/Chat﹕ websocket is already connected
12-03 10:38:52.400 872-872/com.example.strato.test D/Chat﹕ Ping-Event
12-03 10:38:52.420 872-1199/com.example.strato.test D/Chat﹕ recieved ping callback
12-03 10:38:58.410 872-872/com.example.strato.test D/Chat﹕ websocket is already connected
12-03 10:38:58.410 872-872/com.example.strato.test D/Chat﹕ Ping-Event
12-03 10:38:58.420 872-1201/com.example.strato.test D/Chat﹕ recieved ping callback
12-03 10:39:04.400 872-872/com.example.strato.test D/Chat﹕ websocket is already connected
12-03 10:39:04.400 872-872/com.example.strato.test D/Chat﹕ Ping-Event
12-03 10:39:04.420 872-1202/com.example.strato.test D/Chat﹕ recieved ping callback
......

nach dem ich die AVD in den Standby-Modus versetze wird das ping-event soweit ich sehe auch nicht mehr ausgeführt

Ohne ein weiteres Event sehe ich am Server das mein Client disconnected wurde

Nach dem disconnect gehe ich wieder in den normalen Betrieb und dann startet auch das ping-event wieder, aber Nachrichten kommen trotzdem nicht mehr an obwohl der output "already connceted" ist

nach ein paar sekunden kommt dann plötzlich das disocnnect event

und dann wird zwei mal hinter einander ein connect event ausgeführt

ich verstehe leider nicht was bzw warum das passiert....

— geändert am 03.12.2014, 16:50:36

Antworten