TCPClient - Asynchroner Empfang von Zeichen

  • Antworten:8
Peter Pan
  • Forum-Beiträge: 4

12.02.2012, 18:22:18 via Website

Hallo zusammen,

ich bin neu in der Android-App-Programmierung und wollte als erstes einen TCPClienten für einen fertigen TCPServer auf .NET-Basis schreiben. Der Server funktioniert mit verschiedenen Programmen und kann somit als Fehlerquelle ausgeschlossen werden. Leider bekomme ich es nicht hin, dass das Tablet Zeichen zu jeder Zeit empfangen kann. Vielleicht könnt ihr mal über den Code schauen und mir Tips geben, woran das liegen könnte.

1package de.test.hello;
2
3import java.io.BufferedReader;
4import java.io.BufferedWriter;
5import java.io.DataOutputStream;
6import java.io.IOException;
7import java.io.InputStreamReader;
8import java.io.OutputStreamWriter;
9import java.io.PrintWriter;
10import java.net.Socket;
11import java.net.UnknownHostException;
12
13
14
15import android.app.Activity;
16import android.app.AlertDialog;
17import android.os.Bundle;
18import android.view.View;
19import android.view.View.OnClickListener;
20import android.widget.Button;
21import android.widget.EditText;
22import android.widget.ScrollView;
23import android.widget.TextView;
24
25public class HelloWorkshopActivity extends Activity implements OnClickListener, Runnable {
26 /** Called when the activity is first created. */
27
28 private TextView _lblMessages;
29 private ScrollView _scrollMessages;
30 private HelloWorkshopActivity x;
31
32 private Button ConnectButton;
33 private Button SendButton;
34 private Button DisconnectButton;
35
36 public void onCreate(Bundle savedInstanceState) {
37 super.onCreate(savedInstanceState);
38 setContentView(R.layout.main);
39 ConnectButton = (Button)findViewById(R.id.Connect);
40 ConnectButton.setOnClickListener(this);
41 SendButton = (Button)findViewById(R.id.Send);
42 SendButton.setOnClickListener(this);
43 DisconnectButton = (Button)findViewById(R.id.Disconnect);
44 DisconnectButton.setOnClickListener(this);
45
46 _lblMessages = (TextView) findViewById(R.id.lblMessages);
47 _scrollMessages = (ScrollView)findViewById(R.id.scrollMessages);
48 _addMessage("HALLO");
49 _addMessage("TEST");
50 }
51
52 @Override
53 public void onClick(View v) {
54 EditText nameField = (EditText) findViewById(R.id.name_field);
55 String name = nameField.getText().toString();
56 if (name.length() == 0) {
57 new AlertDialog.Builder(this)
58 .setMessage(R.string.error_name_missing)
59 .setNeutralButton(R.string.error_ok, null)
60 .show();
61 return;
62 }
63 if (v == ConnectButton){
64 try {
65 connectTOTCP();
66 }
67 catch (Exception e ){
68 new AlertDialog.Builder(this)
69 .setMessage("FEHLER TCPCONNECT")
70 .setNeutralButton(R.string.error_ok, null)
71 .show();
72 }
73 }
74 if (v == SendButton){
75 try {
76 out.write(name);
77 out.flush();
78 }
79 catch (IOException e) {
80 }
81 }
82 if (v == DisconnectButton){
83 try {
84 out.write("/DISCONNECT");
85 out.flush();
86 } catch (IOException e) {
87 // TODO Auto-generated catch block
88 //e.printStackTrace();
89 }
90 }
91 }
92
93 public Socket clientSocket;
94 public BufferedReader in;
95 public BufferedWriter out;
96
97 public void connectTOTCP() {
98 try {
99 clientSocket = new Socket("192.168.2.115", 1522);
100 in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
101 out = new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream()));
102 out.write("/CONNECT|CLIENTAndroid");
103 out.flush();
104 Thread t1 = new Thread(this);
105 t1.start();
106
107 } catch (UnknownHostException e) {
108 new AlertDialog.Builder(this)
109 .setMessage("FEHLER HIer")
110 .setNeutralButton(R.string.error_ok, null)
111 .show();
112 } catch (IOException e) {
113 new AlertDialog.Builder(this)
114 .setMessage("FEHLER da")
115 .setNeutralButton(R.string.error_ok, null)
116 .show();
117 }
118
119 }
120
121 public void run(){
122 EditText nameField = (EditText) findViewById(R.id.name_field);
123 String name = nameField.getText().toString();
124 try{
125 while (true){
126 String s = in.readLine();
127 _addMessage(s);
128 out.write(s);
129 }
130 }
131 catch (Exception e){
132 //nameField.setText("FEJLER RECEIVE");
133 }
134 }
135
136
137 private void _addMessage(String text)
138 {
139 String messages = _lblMessages.getText().toString();
140 messages += text + "\n";
141 _lblMessages.setText(messages);
142 _scrollMessages.fullScroll(View.FOCUS_DOWN);
143 }
144
145}

Ich habe alles mögliche versucht, aber irgendwie will nichts funktionieren. Wenn jemand ein anderes Beispiel hat, bei dem es funktioniert, bitte zeigen. :D
Mir reicht es schon wenn ich weiss, dass die Zeichen empfangen werden. Die Art und Weise, wie sie angezeigt werden, ist zunächst vollkommen egal.


Dann habe ich noch ein andere grundlegenderere Frage:
Ich benutze als Entwicklungsumgeben Eclipse mit der ANDROID SDK. Kann ich irgendwie auch Haltepunkte etc einfügen, um zu sehen, wo ich im ausführenden Programm bin?


Ich bin für jede Hilfe dankbar

Antworten
Markus B.
  • Forum-Beiträge: 636

12.02.2012, 20:55:10 via Website

Hi,
also ich habe dein Code mal überflogen und so ziemlich alle Exceptions werden bei dir gecatched aber du behandelst diese nicht. Das hat unweigerlich zur Folge das du nichts siehst ...
Fang doch einfach mal damit an den Exceptions zu loggen und dann zu schauen was genau dir da um die Ohren fliegt. Das passende Stichwort wäre hier android.util.Log.
Zum Thema Eclipse:
Eclipse liefert Debugger mit und hier gleich noch ein Beispiel wie dieser zu nutzten ist.

Wenn es nicht weiterhilft melde dich noch mal :)

Gruß,
Markus

Antworten
Peter Pan
  • Forum-Beiträge: 4

13.02.2012, 07:46:30 via Website

Hey,

also das mit android.util.log hat schonmal sehr gut funktioniert. Danke für den Tip. Das mit den Haltepunkten irgendwie trotzdem nicht, aber das kann durch das logging ja behoben werden.

Jetzt habe ich rausgefunden, dass der Fehler in der run-routine kommt. Allerdings habe ich keine Ahnung wieso. Sobald ich verbinde und der Thread gestartet wird, geht er in den catch-Bereich.

Hat noch keiner einen Chat gehabt, wo vom Server zu jeder Zeit Meldungen an den Client geschickt werden?

Im moment bin ich irgendwie ratlos, warum er in der run-routine einen fehler bekommt.

Zu dem ganzen TRY-CATCH... Wenn ich das weglasse, mault Eclipse rum, dass ich die Befehle mit Try-catch surrounden soll.

Antworten
Markus B.
  • Forum-Beiträge: 636

13.02.2012, 08:20:54 via App

Hi, Exceptions werden unter Java halt so behandelt. Da führt kein Weg dran vorbei und das ist auch gut so.
Paste doch mal für den Anfang die Logausgabe mit dem Fehler hier rein.

Gruß,
Markus

Antworten
Peter Pan
  • Forum-Beiträge: 4

13.02.2012, 17:07:19 via Website

Ja hatte komplette verdrängt, dass ich mir die Fehlermeldung anzeigen lassen kann:

das ist sie:
android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.


Bei google konnte ich nicht entscheiden, welche Seite mein Problem beschreibt? Kann mir einer von euch dabei helfen? oder sagen ob ich irgendwas vergessen/nicht beachtet habe?

Antworten
Peter Pan
  • Forum-Beiträge: 4

13.02.2012, 17:13:47 via Website

So ich habe nun festgestellt, dass es hiermit zusammen hängt

_addMessage(s);

Wahrscheinlich weil es der UI-Thread ist. Wie kann ich das beheben?

Antworten
Markus B.
  • Forum-Beiträge: 636

13.02.2012, 18:07:05 via App

Hi, such mal nach thread und Händler. Damit kannst du es machen.
Ein Code Beispiel kann ich dir erst später am Abend geben.

Gruß,
Markus

Antworten
Markus B.
  • Forum-Beiträge: 636

14.02.2012, 00:32:45 via Website

Hi,
du kannst z.B. sowas machen:

1private Handler _guiThreadHandler;
2
3 @Override
4 public void onCreate(Bundle savedInstanceState)
5 {
6 ....
7 _guiThreadHandler = new Handler();
8 }
9
10public void run()
11{
12 _guiThreadHandler.post(new Runnable()
13 {
14 public void run()
15 {
16 final TextView statusText = (TextView) MPlayer.this.findViewById(R.id.status_text);
17 statusText.setText("Blub");
18 }
19 });
20}

Gruß,
Markus

Antworten
Philip M.
  • Forum-Beiträge: 90

14.02.2012, 14:36:20 via Website

Du kannst dir auch mal die Klasse AsyncTask anschauen. Hier hast du drei verschiedene Methoden.

- onPreExecute: Hier machst du alles, was vor dem ausführen des Threads gemacht werden soll
- doInBackground: Das hier ist der Thread, welcher Asynchron zum UI-Thread läuft. Hier kann und darf nichts an de UI verändert werden
- onPostExecute: Hier kannst du alles machen, was nach dem durchlaufen des Threads gemacht werden soll

Hier kannst du auf einen Handler verzichten. Außerdem gibt die Methode doInBackground einen beliebigen Typen zurück (Rückgabetyp ist generisch), welchen du in der Methode onPostExecute als Parameter übergeben bekommst.

Heißt, du kannst das Ergebnis welches du im Thread erreichst in der onPostExecute Methode verarbeiten.

Ist meiner Meinung nach übersichtlicher und einfacher hand zu haben.

Antworten