Text zu TextView hinzufügen

  • Antworten:6
  • Bentwortet
DerRKDCB
  • Forum-Beiträge: 34

05.02.2014, 20:04:10 via Website

Hallo liebe Community!

Ich will zu einer Textview einen Text hinzufügen (nicht ändern), hatte auch schon eine Idee, von der ich mir eigendlich sicher war, sie klappt...
Erstmal hier mein Quellcode:
1package de.derrkdcb.piremote;
2
3import java.io.InputStream;
4import java.util.Properties;
5
6import com.jcraft.jsch.ChannelExec;
7import com.jcraft.jsch.JSch;
8import com.jcraft.jsch.Session;
9
10import android.os.AsyncTask;
11import android.os.Bundle;
12import android.app.Activity;
13import android.text.method.ScrollingMovementMethod;
14import android.view.Menu;
15import android.view.View;
16import android.widget.TextView;
17
18public class MainActivity extends Activity {
19
20public TextView txtDebug;
21
22 @Override
23 protected void onCreate(Bundle savedInstanceState) {
24 super.onCreate(savedInstanceState);
25 setContentView(R.layout.activity_main);
26
27 txtDebug = (TextView)findViewById(R.id.txtDebug);
28 txtDebug.setMovementMethod(new ScrollingMovementMethod());
29
30
31 }
32
33 @Override
34 public boolean onCreateOptionsMenu(Menu menu) {
35 // Inflate the menu; this adds items to the action bar if it is present.
36 getMenuInflater().inflate(R.menu.main, menu);
37 return true;
38 }
39
40 public void Shutdown (View v) {
41 Shell ShutdownShell = new Shell();
42 ShutdownShell.execute("testuser", "192.168.1.1", "passwort");
43 }
44
45
46 private class Shell extends AsyncTask<String, String, Long> {
47
48 @Override
49 protected Long doInBackground(String... arguments) {
50
51 // Extract Arguments
52 String user = arguments[0];
53 String host = arguments[1];
54 int port = 22;
55 String password = arguments[2];
56
57 System.out.println("SSH connecting...");
58 txtDebug.setText(txtDebug.getText() + "\nSSH connecting...");
59
60 try
61 {
62 JSch jsch = new JSch();
63 Session session = jsch.getSession(user,host, port);
64 session.setPassword(password);
65
66 // Avoid asking for key confirmation
67 Properties prop = new Properties();
68 prop.put("StrictHostKeyChecking", "no");
69 session.setConfig(prop);
70
71 session.connect();
72
73 System.out.println("SSH connected!");
74 txtDebug.setText(txtDebug.getText() + "\nSSH connected!");
75
76
77 ChannelExec channel = (ChannelExec)session.openChannel("exec");
78 channel.setCommand("sudo shutdown -h 0");
79 channel.connect();
80
81 InputStream input = channel.getInputStream();
82 int data = input.read();
83 txtDebug.setText(txtDebug.getText() + "\n" + data);
84
85
86 channel.disconnect();
87
88 }
89 catch (Exception e)
90 {
91 System.out.println(e.getMessage());
92 txtDebug.setText(txtDebug.getText() + "\n" + e.getMessage());
93 }
94
95 return null;
96 }
97
98 }
99
100}

Ein Beispiel:
System.out.println("SSH connecting...");
txtDebug.setText(txtDebug.getText() + "\nSSH connecting...");

Bei
System.out.println("SSH connecting...");
schreibt die Konsole "SSH connecting..." was ja auch so sein soll. Aber bei der nächsten Zeile:
txtDebug.setText(txtDebug.getText() + "\nSSH connecting...");
Stürzt die App einfach ab.

Ich weiß nicht, ob direkt beim "txtDebug.setText(txtDebug.getText() + "\nSSH connecting...");" was nicht stimmt, oder das ganze mit dem AsynkTask was zu tun hat oder was weiß ich...
Tut mir leid, ich bin noch neu im Geschäft ;)

Ich danke euch für eure Hilfe!

Gruß, Robert

Antworten
Michele
  • Forum-Beiträge: 1.525

05.02.2014, 20:24:51 via Website

Was sagt dein LogCat, wenn deine App abstürzt?



LG

Antworten
impjor
  • Forum-Beiträge: 1.793

05.02.2014, 20:42:51 via App

Bitte ließ dir das Logcat durch!

Dort wird folgendes drinstehen: Only the original Thread can touch it's won views!
(oder so ähnlich.)

Also auf deutch: Nur der Thread, der eine View erstellt hat, darf diese ändern.

Da ein AsyncTask nichts anderes als ein Thread ist, darf er keine Views verändern.
Stattdessen muss er den UI-/Mainthread benachrichtigen, dass dieser die View verändern soll.

Es gibt da mehrere Möglichkeiten (leichteste zuerst):

1. Activity#runOnUiThread(...) aufrufen.
2. Einen Handler im UI-/Mainthread erstellen (z.B. onCreate) und im AsyncTask dann Handler#post(...) nutzen.
3. Im asyncTask onProgressUpdaate() überschreiben; dann publishProgress(...) aufrufen. publishProgress() ruft onProgressUpdate auf dem UI-/Mainthread auf.

LG

Liebe Grüße impjor.

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

DerRKDCB

Antworten
DerRKDCB
  • Forum-Beiträge: 34

05.02.2014, 21:08:57 via Website

Danke für eure Reaktion ^^

Die Logcat schreibt tatsächlich folgendes:
Caused by: android.view.ViewRootImpl$CalledFromWrongThreatException: Only the orginal thread that created a view hierarchy can touch its views.
Wie ja impjor schon gesagt hat, kann der AsyncTask die View nicht bearbeiten... leider komme ich mit deinen Möglichkeiten (noch) nicht zurecht, aber des Weiteren werde ich Google befragen. (es sei denn, jemanden ist gerade langweilig und würde den quellcode für mich abändern ;))

Falls ich wirklich nicht weiterkommen sollte, melde ich mit wieder.

Gruß, Robert

Antworten
impjor
  • Forum-Beiträge: 1.793

05.02.2014, 21:15:13 via App

Als Anregung für Variante 1: Deine AsyncTask-Klasse braucht eine Referenz auf die Activity. Also z.B. im Konstruktor verlangen.
Dann auf diese Activity die Methode runOnUiThread() aufrufen. Diese benötigt ein Runnable-Objekt. Also runOnUiThread( new Runnable()); Dann sollte deine IDE schon meckern: Runnable ist ein Interface, legt also nur fest welche Funktionen Objekte haben, ohne diese zu implementieren. Stattdessen müssen alle Unterklassen/Objekte selber die entsprechenden Methoden deklarieren und mit Code versehen, also
runOnUiThread(new Runnable() {
void run() {
}
}
);

Die Activity kümmert sich dann darum, dass sie die run() Methode auf dem Ui-Thread ausführt, der ja Views verändern darf.

LG

Liebe Grüße impjor.

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

Antworten
DerRKDCB
  • Forum-Beiträge: 34

05.02.2014, 21:42:04 via Website

Aha... das mag für dich alles selbstverständlich sein, aber bitte sei nachsichtig mit mir, wenn ich mich noch ein bisschen tollpatschig anstelle...

Ich hab jetz
System.out.println("SSH connecting...");
txtDebug.setText(txtDebug.getText() + "\nSSH connecting...");
durch
System.out.println("SSH connecting...");
runOnUiThread(new Runnable() {
public void run() {
txtDebug.setText(txtDebug.getText() + "\nSSH connecting...");
}
});
ersetzt. Schaut für mich zwar ziemlich quick and dirty aus, aber bis jetz funktionierts ganz gut (hab leider zurzeit keine Möglichkeit es unter Realbedingungen zu testen)

Danke für eure Hilfe!

Gruß, Robert

Edit:
Hier nochmal der ganze Code (Noch viel dirtiger ;P)
1package de.derrkdcb.piremote;
2
3import java.util.Properties;
4
5import com.jcraft.jsch.ChannelExec;
6import com.jcraft.jsch.JSch;
7import com.jcraft.jsch.Session;
8
9import android.os.AsyncTask;
10import android.os.Bundle;
11import android.app.Activity;
12import android.text.method.ScrollingMovementMethod;
13import android.view.Menu;
14import android.view.View;
15import android.widget.TextView;
16
17public class MainActivity extends Activity {
18
19public TextView txtDebug;
20public String out;
21
22 @Override
23 protected void onCreate(Bundle savedInstanceState) {
24 super.onCreate(savedInstanceState);
25 setContentView(R.layout.activity_main);
26
27 txtDebug = (TextView)findViewById(R.id.txtDebug);
28 txtDebug.setMovementMethod(new ScrollingMovementMethod());
29
30
31 }
32
33 @Override
34 public boolean onCreateOptionsMenu(Menu menu) {
35 // Inflate the menu; this adds items to the action bar if it is present.
36 getMenuInflater().inflate(R.menu.main, menu);
37 return true;
38 }
39
40 public void Shutdown (View v) {
41 Shell ShutdownShell = new Shell();
42 ShutdownShell.execute("pi", "192.168.178.53", "logitech1!");
43 }
44
45
46 private class Shell extends AsyncTask<String, String, Long>{
47
48 @Override
49 protected Long doInBackground(String... arguments) {
50
51 // Extract Arguments
52 String user = arguments[0];
53 String host = arguments[1];
54 int port = 22;
55 String password = arguments[2];
56
57 System.out.println("SSH connecting...");
58 runOnUiThread(new Runnable() {
59 public void run() {
60 txtDebug.setText(txtDebug.getText() + "\nSSH connecting...");
61 }
62 });
63
64
65 try
66 {
67 JSch jsch = new JSch();
68 Session session = jsch.getSession(user,host, port);
69 session.setPassword(password);
70
71 // Avoid asking for key confirmation
72 Properties prop = new Properties();
73 prop.put("StrictHostKeyChecking", "no");
74 session.setConfig(prop);
75
76 session.connect();
77
78 System.out.println("SSH connected!");
79 runOnUiThread(new Runnable() {
80 public void run() {
81 txtDebug.setText(txtDebug.getText() + "\nSSH connected!");
82 }
83 });
84
85
86
87 ChannelExec channel = (ChannelExec)session.openChannel("exec");
88 channel.setCommand("sudo shutdown -h 0");
89 channel.connect();
90
91
92 channel.disconnect();
93
94 }
95 catch (Exception e)
96 {
97 System.out.println(e.getMessage());
98 out = e.getMessage();
99 runOnUiThread(new Runnable() {
100 public void run() {
101 txtDebug.setText(txtDebug.getText() + "\n" + out);
102 }
103 });
104 }
105
106 return null;
107 }
108 }
109}

— geändert am 05.02.2014, 21:49:18

Antworten