TCP Connection mit asyncronem Vorgang

  • Antworten:23
  • OffenNicht stickyNicht beantwortet
Pascal P.
  • Mod
  • Blogger
  • Forum-Beiträge: 10.210

24.03.2013, 12:41:21 via Website

Hallo,
ich will eine TCP Connection asyncron machen,da ich nebenbei auch noch c# programmiere will eich ein Server Client System machen.
Ich habe kiene Ahnung wie das in Java geht.
Ich bekomme zwar schon Daten über TCP Connection aber jetzt wil ich das ganze asynchon machen.
Miene TCP Connection CLass: (bitte nicht so sehr auf die Klammern achten hatte ein Formatierungsproblem)
1package de.net.tcp.connection;
2
3public class TCPClient extends Activity{
4
5 Context mContext; // Lege Variablen an
6 TCPActivity tcp;
7 Socket socket;
8 PrintWriter out = null;
9 BufferedReader in = null;
10
11
12
13 public TCPClient(Context c,TCPActivity tcpc)
14 {
15 tcp = tcpc; // Setze TCPActivity (Aktivity, von der diese Klasse aufgerufen wird).
16 mContext = c; // Setze context
17
18
19 }
20
21
22
23
24 public void connectSocket(){
25
26 try {
27
28
29 InetAddress serverAddr = InetAddress.getByName("192.168.0.102"); // Lege IP adresse an
30 socket = new Socket(serverAddr, 4444); // Verbinde mit Server (IP oben angegeben) und einem bestimmten ServerPort
31
32 }
33 catch (final UnknownHostException e) { // Falls der Host nicht extstiert
34 // TODO Auto-generated catch block
35 Log.e("TCP", "C: UnknownHostException", e);
36 e.printStackTrace();
37 }
38
39
40
41
42 catch(final Exception e) // oder sonst etwas nicht stimmt
43 {
44
45 Log.e("TCP", "C: Exception", e);
46 //Toast.makeText(mContext, "Error : " + e.toString(), Toast.LENGTH_LONG).show();
47 }
48
49
50 }
51
52
53
54 }
55
56
57
58
59
60
61
62
63 public void SendMessage(final String message) throws IOException // Anfrage an den Server senden
64 {
65 try {
66
67 Toast.makeText(mContext, "Sending Messsage = " + message, Toast.LENGTH_LONG).show();
68 out = new PrintWriter( new BufferedWriter( new OutputStreamWriter(socket.getOutputStream(), "UTF-8")),true); // Lege outWriter an
69 out.println(message); // Sende die Anfrage
70
71
72
73 Toast.makeText(mContext, "Anfrage gesendet.", Toast.LENGTH_LONG).show();
74 getMessage(); // Warte auf antwort
75
76 }
77 catch(Exception e) { // Falls etwas nicht stimmt
78 Log.d("TCP", "Error"+ e.fillInStackTrace() + e.toString());
79 //Toast.makeText(mContext, "Error" + e.toString(), Toast.LENGTH_LONG).show();
80 }
81 finally
82 {
83
84 //socket.close();
85
86 }
87
88
89
90
91 }
92
93 String finalText;
94
95 public void getMessage() // Warte auf Antwort vom Server !!!Hinweis: Diese Funktion Funktioniert nur, wenn schon eine anfrage an den Server gesendet wurde und sie noch nicht empfangen wurde!
96 {
97
98
99
100
101 try {
102 in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
103 // Warte auf ankommende Antworten
104
105
106 String text = "";
107
108 while ((text = in.readLine()) != null) { // Lese den einkommenden String
109 finalText += text;
110 }
111
112
113
114
115
116
117 tcp.SetText(finalText); // Setze in textView in der Main die Antwort
118 }
119 catch (IOException e) {
120 // TODO Auto-generated catch block
121 e.printStackTrace();
122 } }
123
124
125
126
127 }
128
129
130
131}
Kann mir jemand verraten, wie ich diese Klasse asynchon starten kann, wie zb mit einem AsyncTask.
PS: Habe mir schon etliche Beispiele angesehen, aber keines hat mir gefallen.


Bitte um antwort

Vielen Dank im Voraus

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

Antworten
  • Forum-Beiträge: 33

25.03.2013, 15:19:15 via Website

Hallo Pascal!

Ich habe asynchrone HTTP Requests mal für die Ansteuerung eines SmartHome Servers implementiert. Hier mein Code:

1/*
2 * Asynchronously send control commands to the Smart Home server.
3 */
4
5import java.io.BufferedReader;
6import java.io.IOException;
7import java.io.InputStreamReader;
8import java.net.URL;
9
10import org.apache.http.HttpResponse;
11import org.apache.http.client.HttpClient;
12import org.apache.http.client.methods.HttpGet;
13import org.apache.http.impl.client.DefaultHttpClient;
14import org.json.JSONArray;
15
16import android.os.AsyncTask;
17import android.util.Log;
18
19public class AsyncSHRequest extends AsyncTask<Object, Object, Object> {
20
21 // IP of the Smart Home server.
22 // ATTENTION: Could change in different environments.
23 String ip = "192.168.1.242";
24
25 protected Object doInBackground(Object... id) {
26
27 // Extract the device ID and the desired status of the device.
28 String shDeviceID = id[0].toString();
29 String status = id[1].toString();
30
31 BufferedReader in = null;
32 try {
33 HttpClient client = new DefaultHttpClient();
34 HttpGet request = new HttpGet();
35 URL uri = new URL("http", ip, "/preset?switch="+shDeviceID+"&value="+status);
36 Log.i("AsyncHttpConnection", "Request URI: " + uri);
37 request.setURI(uri.toURI());
38 HttpResponse response = client.execute(request);
39 in = new BufferedReader(new InputStreamReader(response.getEntity()
40 .getContent()));
41 StringBuffer sb = new StringBuffer("");
42 String line = "";
43 String NL = System.getProperty("line.separator");
44 while ((line = in.readLine()) != null) {
45 sb.append(line + NL);
46 }
47 in.close();
48 String page = sb.toString();
49 Log.i("TabScanNFC:scanTag", "Success!");
50 Log.i("AsyncWriteConfigToDB", "Response: " + page);
51
52 } catch (Exception e) {
53 Log.i("ERROR", e.toString());
54 }
55
56 if (in != null) {
57 try {
58 in.close();
59 } catch (IOException e) {
60 e.printStackTrace();
61 }
62 }
63
64 return null;
65 }
66
67 protected void onProgressUpdate(Integer... progress) {
68 // You are on the GUI thread, and the first element in
69 // the progress parameter contains the last progress
70 // published from doInBackground, so update your GUI.
71 }
72
73 protected void onPostExecute(JSONArray result) {
74 // Processing is complete.
75 }
76
77}

Aufgerufen wird das ganze dann z.B. so:

1// Get the ID to send it to the Smart Home server when flipping the switch.
2final String deviceID = device.getDevice_id_asString();
3
4// Add switch and do some cosmetics.
5final Switch sw = new Switch(getActivity());
6
7sw.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
8 // When the switch is flipped, send an HTTP request to the Smart Home server.
9 @Override
10 public void onCheckedChanged(CompoundButton arg0, boolean arg1) {
11 Log.i("Switched", sw.getText().toString());
12 String status = "";
13 if(sw.isChecked()) status = "on";
14 else status = "off";
15 new AsyncSHRequest().execute(deviceID, status);
16 }
17});

Ich hoffe, das hilft dir weiter. :)

Beste Grüße,
knucKles

Pascal P.

Antworten
Pascal P.
  • Mod
  • Blogger
  • Forum-Beiträge: 10.210

25.03.2013, 15:21:44 via Website

Danke das werde ich testen.
Aber kann ich auch andere Funktionen einbauen neben dem doInBackground ?
Ich würde nämich gerne in der Do in Background alles Initialisieren und dann andere Funktionen aufrufen, die dann aber auch in dem Thread des AsyncTask laufen.

— geändert am 25.03.2013, 15:24:21

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

Antworten
  • Forum-Beiträge: 1.793

25.03.2013, 23:10:04 via App

Nein, dass funktioniert nicht. Wenn du

deinAsyncTask.exec(...); aufrufst, wird intern doInBackground des AsyncTask aufgerufen, was anderes geht nicht. Es gibt aber noch andere Methoden, die du überschreiben kannst. (s. d.android.com), darin kannst du Aufgaben vor bzw. nach den doInBackground machen.

Grus

Liebe Grüße impjor.

Für ein gutes Miteinander: Unsere Regeln
Apps für jeden Einsatzzweck
Stellt eure App vor!

Antworten
Pascal P.
  • Mod
  • Blogger
  • Forum-Beiträge: 10.210

26.03.2013, 08:15:40 via Website

Danke, ich will im do in background warten, bis eine Datenverbindung aufgebaut wird, diese dann auslesen und dann sofort wider in den Wartemodus setzen.
Ich habe was von Interfaces gehört, kann ich mit diesen die bekommenen Daten aus dem AsyncTask eine andere Klasse übernehmen?

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

Antworten
  • Forum-Beiträge: 1.793

26.03.2013, 12:08:02 via Website

Danke, ich will im do in background warten, bis eine Datenverbindung aufgebaut wird, diese dann auslesen und dann sofort wider in den Wartemodus setzen.
Ist kein Problem, da die Benutzeroberfläche, nicht "stecken bleibt", ist ja ein anderer Thread,

Ich habe was von Interfaces gehört, kann ich mit diesen die bekommenen Daten aus dem AsyncTask eine andere Klasse übernehmen?
Ich versteh dich nicht ganz, was du hiermit meinst:wink:

Also interfaces sind eigentlich nur eine Information, was eine Klasse an Methoden besitzen muss. Bsp.: das OnClickListener - Intzerface beschreibt, dass die Klasse, die davon abgeleitet wird die Methode onClick(View v); überschreiben muss.

Gruß

Liebe Grüße impjor.

Für ein gutes Miteinander: Unsere Regeln
Apps für jeden Einsatzzweck
Stellt eure App vor!

Antworten
Pascal P.
  • Mod
  • Blogger
  • Forum-Beiträge: 10.210

26.03.2013, 12:29:32 via Website

Ok
Ich habe eine Async Task Klasse.
1class AsyncConnection implements AsyncTask
2{
3
4}

in dieser gibt es ja die Methode doInBackground().
Dort kommt ann der Code rein, der im anderen Thread ausgeführt werden soll.
Nun habe ich die Daten über mein Socket empfangen und dann will ich die Empfangen daten in einer anderen Klasse wieder benutzen.
Etwa so:
1doInBackground(Object... params)
2{
3
4//Baue verbindung auf etc.
5//Sende eine Message
6while(true) //Damit dieser Schritt immer wiederholt wird
7try{
8 out = new PrintWriter( new BufferedWriter( new OutputStreamWriter(socket.getOutputStream(), "UTF-8")),true); // Lege outWriter an
9 out.println(message); // Sende die Anfrage
10
11
12
13
14
15 }
16catch(Exception e) { // Falls etwas nicht stimmt
17 Log.d("TCP", "Error"+ e.fillInStackTrace() + e.toString());
18 //Toast.makeText(mContext, "Error" + e.toString(), Toast.LENGTH_LONG).show();
19 }
20 finally
21 {
22
23 //socket.close();
24
25 }
26
27 String finalText;
28
29
30 //Warte auf ahkommende Message
31
32
33
34 try {
35 in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
36 // Warte auf ankommende Antworten
37
38
39 String text = "";
40
41 while ((text = in.readLine()) != null) { // Lese den einkommenden String
42 finalText += text;
43 }
44catch(Exception e)
45{
46. Log.d("TCP", "Error"+ e.fillInStackTrace() + e.toString());
47}
48
49sendTextTootherClass(finalText);//Hier soll der empfangene Text in eine andere Klasse geschreiben werden (imUI Thread!)
50
51}//Ender der While Schleife

Die Funktion sendTextTootherClass() soll dein String um UI Thread in eine Klasse oder Activity schreiben.
dort soll aufgerrufen werden.
1onTextRecived(String text)
2{
3//hier kommt mein weitere Code rein.
4}

— geändert am 26.03.2013, 12:31:11

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

Antworten
  • Forum-Beiträge: 1.793

26.03.2013, 19:17:19 via App

Achso, verstehe.
Dann musst du ein eigenes Interface erstellen, welches so aussieht:

...
public void onTextRecieved(String s);
....

im AsyncTask speicherst du das:

private InterfaceName mInterface = null;


in der Methode, die den Text senden soll:
if (mInterface != null) {
mInterface.onTextRecieved(empfangener_Text);
}

Nun brauchst du nur noch einen setter für mInterface.

Gruß

Liebe Grüße impjor.

Für ein gutes Miteinander: Unsere Regeln
Apps für jeden Einsatzzweck
Stellt eure App vor!

Antworten
Pascal P.
  • Mod
  • Blogger
  • Forum-Beiträge: 10.210

26.03.2013, 20:08:02 via App

Danke für die Antwort.
Aber wie wie prüfe ich in meiner Activity, ob onTextRecived() ausgeführt wird?

— geändert am 26.03.2013, 20:08:17

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

Antworten
  • Forum-Beiträge: 1.793

26.03.2013, 20:23:50 via App

Wie bei einem onClickListener.
Ich sag mal du hast in deinem AsyncTask die Methode setInterface(...);

Dann schreibst du in der MainActivity:

deinAsynctask.setInterface(new InterfaceName() {
public void onTextRecieved(String s) {
//hier was machen
}
});

— geändert am 26.03.2013, 20:24:20

Liebe Grüße impjor.

Für ein gutes Miteinander: Unsere Regeln
Apps für jeden Einsatzzweck
Stellt eure App vor!

Antworten
Pascal P.
  • Mod
  • Blogger
  • Forum-Beiträge: 10.210

26.03.2013, 20:48:26 via App

Und wie macht man das mit der setInterface(...) Methode?

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

Antworten
Pascal P.
  • Mod
  • Blogger
  • Forum-Beiträge: 10.210

27.03.2013, 09:41:21 via Website

Danke

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

Antworten
Pascal P.
  • Mod
  • Blogger
  • Forum-Beiträge: 10.210

30.03.2013, 18:08:32 via Website

Nun habe ich ein weiteres Problem:
Ich rufe also onTextRecieved(String s) in der doInBackground Methode auf.
Kann es sein, dass die Methode on StringRecived() trotz Interface nicht im UI Thread Läuft?
Denn einen Toast kann ich mit meinem empfangenen String nicht erstellen, aber ich kann ihn in der Konsole ausgeben.
Wenn ich ein Toast ausgeben will zeigt LogCat diese Meldungen:


1FATAL EXCEPTION: AsyncTask #1
2java.lang.RuntimeException: An error occured while executing doInBackground()
3 at android.os.AsyncTask$3.done(AsyncTask.java:299)
4 at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:273)
5 at java.util.concurrent.FutureTask.setException(FutureTask.java:124)
6 at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:307)
7 at java.util.concurrent.FutureTask.run(FutureTask.java:137)
8 at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230)
9 at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
10 at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
11 at java.lang.Thread.run(Thread.java:856)
12Caused by: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
13 at android.os.Handler.<init>(Handler.java:121)
14 at android.widget.Toast$TN.<init>(Toast.java:361)
15 at android.widget.Toast.<init>(Toast.java:97)
16 at android.widget.Toast.makeText(Toast.java:254)
17 at de.net.tcp.connection.TCPClient.test(TCPClient.java:143)
18 at de.net.tcp.connection.TCPClient$1.makeToast(TCPClient.java:129)
19 at de.net.tcp.connection.GetMessage.doInBackground(GetMessage.java:63)
20 at android.os.AsyncTask$2.call(AsyncTask.java:287)
21 at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
22 ... 5 more

Kann mir jemand helfen?

— geändert am 30.03.2013, 18:09:11

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

Antworten
Pascal P.
  • Mod
  • Blogger
  • Forum-Beiträge: 10.210

30.03.2013, 18:25:50 via Website

Was heist das jetzt?
Wie bekomm ich den Sting in dem Main Thread ohne runOnUi thread?

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

Antworten
Pascal P.
  • Mod
  • Blogger
  • Forum-Beiträge: 10.210

30.03.2013, 18:36:01 via Website

geht das nicht ohne?
ich dachte es geht noch einfacher.

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

Antworten
Pascal P.
  • Mod
  • Blogger
  • Forum-Beiträge: 10.210

30.03.2013, 18:38:43 via Website

Danke es funktioniert prima :)

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

Antworten

Empfohlene Artikel