TextView außerhalb einer Activity ansteuern

  • 13 Antworten
  • Neuester Beitrag
Diskutiere TextView außerhalb einer Activity ansteuern im Android App Entwicklung im Bereich Betriebssysteme & Apps.
A

audacity363

Ambitioniertes Mitglied
Guten Tag

in meiner App muss ich einen Server anpingen. Dies passiert zurzeit nur einmal da das ganze ja in einem Thread laufen muss. In der Main Activity warte ich mit .join() auf diesen und bekomme dann true oder false zurück. Darauf hin setzte ich ein TextView auf ONLINE oder OFFLINE. Nur bringt es natürlich nichts den Ping nur einmal durchzuführen. Würde das ganze gerne jede halbe Minute machen nur müsste ich dazu wissen wie kann man außerhalb einer Activity eine TextView ansprechen oder geht das überhaupt nicht?
 
A

Anojo

Neues Mitglied
Hi hi,

das Problem ist nicht die Activity sonder der Thread in dem du bist wenn du eine Internetverbindung aufbaust.
Android zwingt dich die Internetverbindung in einem separaten Thread zu machen, aber in diesem Thread darfst du nicht auf deine Haupt-Thread zugreifen wo deine Oberfläche drauf läuft bzw. geht das manchmal schon aber du läufst in irgend einen Fehler rein.

mit runOnUiThread geht das wieder...

Code:
runOnUiThread(new Runnable() {
			public void run() {

				//hier textView ändern
			}
		});
gruß Toni
 
Zuletzt bearbeitet:
A

audacity363

Ambitioniertes Mitglied
Wo genau meinst du das es hinkommt? Bei mir gibt Eclipse fehler aus. Hier mal die komplette Klasse:

Code:
package de.raspberrypi.steuerung;

import java.net.*;
import java.io.*;

public class Ping extends Thread
{
	public static final String PREFS = "PING";
	public boolean Server_Status;
	String empfangeneNachricht;
	String Server;
	Socket socket;
	int PORT;
	
    
    public Ping(String Server, int Port)
    {
    	this.Server = Server;
    	this.PORT = Port;
    }	
    runOnUiThread(new Runnable()
    {
	    public void run()
	    {
	    	try
	    	{
	    		java.net.Socket socket = new java.net.Socket(Server,PORT); // verbindet sich mit Server
	        	String zuSendendeNachricht = "Ping";
	        	schreibeNachricht(socket, zuSendendeNachricht);
	        	String empfangeneNachricht = leseNachricht(socket);
	        	System.out.println(empfangeneNachricht);
	        	if(empfangeneNachricht.equals("true"))
	        	{
	        		Server_Status = true;
	        	}
	        	else
	        	{
	        		Server_Status = false;
	        	}
	    	}
	    	catch(IOException e)
	    	{
	    		Server_Status = false;
	    	}
	    	
	    }
    });
    void schreibeNachricht(java.net.Socket socket, String nachricht) throws IOException 
    {
        PrintWriter printWriter =
           new PrintWriter(
               new OutputStreamWriter(
                   socket.getOutputStream()));
       printWriter.print(nachricht);
       printWriter.flush();
   }
   String leseNachricht(java.net.Socket socket) throws IOException 
   {
       BufferedReader bufferedReader =
           new BufferedReader(
               new InputStreamReader(
                   socket.getInputStream()));
       char[] buffer = new char[200];
       int anzahlZeichen = bufferedReader.read(buffer, 0, 200); // blockiert bis Nachricht empfangen
       String nachricht = new String(buffer, 0, anzahlZeichen);
       return nachricht;
   }
}
 
A

Anojo

Neues Mitglied
Welchen Fehler bekommst du?

Ich seh hier nirgends das du ein neuen Thread startest...
Deine Internet Sachen musst du in einem neuen Thread machen.

Ich Persönlich hätte eine Methode geschrieben der du nur das Ergebnis übergibst und die soll dann die TextView ändern.
 
A

audacity363

Ambitioniertes Mitglied
Also wie gesagt das ganze liegt in einer eigenen Klasse und nicht in der Main. Also eine komplett neue Datei. Das ist der Code von dem ping Thread wie man unschwer erkennen kann. Zurzeit rufe ich dem Thread einmal am Anfang der App auf warte dann mit .join () auf ihn und hole mir dann den boolean Server_Status. Daraufhin wird dann eine TextView entweder auf Online oder Offline gesetzt. Nur ich möchte halt das der Ping jede 30sec durchgeführt wird. Das heißt aber, dass ich nicht mehr auf ihn warten muss sondern intern eine TextView verändern. Der Aufruf ist doch vollkommen egal du musst doch eigentlich nur wissen das es ihn gibt. Den Fehler habe ich als Bild angehängt weil ich jetzt unterwegs bin.

Gesendet von meinem GT-I9100 mit der Android-Hilfe.de App
 

Anhänge

A

Anojo

Neues Mitglied
Wie gesagt ich würde gar nicht auf den Status warten sondern eine Methode schreiben in der MainAcktivity der in etwa so aussieht...

Code:
public void setStatus(boolean status){

runOnUiThread(new Runnable() {
			public void run() {

				if(status == true){
                                    textView.setText("Online")
                                 }else{
                                    textView.setText("Offline")
                                 }
			}
		});
}
und der übergibst du wenn der Thread fertig ist einfach dein Ergebnis...

Android will eben mit dem Thread verhindern das deine Anwendung auf eine eventuell langsame Internetverbindung warten muss, deshalb der neue Thread.
 
Z

Zoopa

Stammgast
runOnUiThread ist eine Methode der Klasse Activity.

Du musst also folgendes machen:

  1. Beim erstellen des Threads gibst du ihm eine Referenz auf deine Activity mit
  2. Auf dieser Referenz kannst du dann jederzeit runOnUiThread aufrufen

Kurzes Beispiel:

Code:
public class MyActivity extends Activity {
    //...
    
    //irgendwo in deiner Activity machst du dann so etwas
    Thread pingThread = new Ping("127.0.0.1", 8080, this);
    pingThread.start();

    //...
}
Dein Thread:
Code:
public class Ping extends Thread
{
    //...

    Activity myActivity;	
    
    public Ping(String Server, int Port, Activity myActivity)
    {
    	this.Server = Server;
    	this.PORT = Port;
        this.myActivity = myActivity;
    }

    public void run()
    {    
        //...

        myActivity.runOnUiThread(new Runnable() {
            public void run() {
                TextView myTextView = (TextView) myActivity.findViewById(...);
                myTextView.setText(...);
            }
        });
    }
Edit:
Anojo war viel schneller ;) Seine Möglichkeit funktioniert natürlich genauso. Ist wohl sogar sauberer, weil du dann den ganzen Code, der deine Activity betrifft, auch in deiner Activity-Klasse hast.

Edit2:
statt runOnUiThread gibt es auch die Methode post der Klasse View. Statt eine Referenz auf deine Activity könntest du dann einfach eine Referenz auf deine TextView mitgeben
 
Zuletzt bearbeitet:
A

audacity363

Ambitioniertes Mitglied
@Anojo warum das denn? Ich kann das ganze doch auch in dem Ping Thread. So muss ich wiederum zwei Threads starten und das würde wiederum für Geräte die ein weniger Leistung haben schlecht laufen. Das was du oben siehst ist ja nur ein Grundgerüst. Ich würde in den If/else dementsprechend die TextView ändern. Der Thread soll ja im nachhinein Endlos durchlaufen nur das am Ende eine halbe Minute mit Thread.sleep() gewartet wird.

@Zoopa Okey Danke so etwas habe ich gesucht.
 
A

Anojo

Neues Mitglied
Natürlich reicht das wenn du den Thread mit dem Ping nur ein mal startest...
Zoopa wollte dir nur zeigen wie du wieder auf deine Activity zugreifst.

Der ursprüngliche Beitrag von 14:09 Uhr wurde um 14:16 Uhr ergänzt:

Achso du hast mich gemeint...

wie gesagt du musst den Thread nur ein mal starten aber es darf nicht auf dem Haupt-Thread laufen weil Android das unterbindet.
 
A

audacity363

Ambitioniertes Mitglied
Ne das die Netzwerksachen in einem eigenen Thread laufen müssen ist ja kla aber ist ja jetzt auch egal Danke für die Hilfe von euch beiden es funktioniert ja jetzt.

Der ursprüngliche Beitrag von 14:24 Uhr wurde um 14:59 Uhr ergänzt:

Sow da bin ich jetzt normal: Habe das ganze jetzt mal ausprobiert nur bekomme ich jetzt eine android.os.NetworkOnMainThreadException. Diese bekomme ich allerdings nicht wenn das ganze im normalen run() liegt.
Kompletter Code für den Ping.
Code:
package de.raspberrypi.steuerung;

import java.net.*;
import java.io.*;

import android.app.Activity;
import android.widget.TextView;

public class Ping extends Thread
{
	public static final String PREFS = "PING";
	public boolean Server_Status;
	String empfangeneNachricht;
	String Server;
	Socket socket;
	int PORT;
	Activity myActivity;
	
	
    
    public Ping(String Server, int Port, Activity myActivity)
    {
    	this.Server = Server;
    	this.PORT = Port;
    	this.myActivity = myActivity;
    	
    }	
  
    public void run()
    {
    	myActivity.runOnUiThread(new Runnable()
    	{
    		
    		public void run()
    		{
    			TextView Server_status = (TextView) myActivity.findViewById(R.id.Server_Status);
    			while(true)
    			{
			    	try
			    	{
			    		java.net.Socket socket = new java.net.Socket(Server,PORT); // verbindet sich mit Server
			    		String zuSendendeNachricht = "Ping";
			    		schreibeNachricht(socket, zuSendendeNachricht);
			    		String empfangeneNachricht = leseNachricht(socket);
			    		System.out.println(empfangeneNachricht);
			    		if(empfangeneNachricht.equals("true"))
			    		{
			    			Server_status.setText("ONLINE");
				        }
			    		else
			    		{
			    			Server_status.setText("OFFLINE");
			    		}
			    	}
			    	catch(IOException e)
			    	{
			    		Server_status.setText("OFFLINE");
			    	}
			    	
			    	try 
			    	{
						Thread.sleep(30000);
					} 
			    	catch (InterruptedException e) 
					{
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
    			}
    		}
    	});
	    	
    }
    
    void schreibeNachricht(java.net.Socket socket, String nachricht) throws IOException 
    {
        PrintWriter printWriter =
           new PrintWriter(
               new OutputStreamWriter(
                   socket.getOutputStream()));
       printWriter.print(nachricht);
       printWriter.flush();
   }
   String leseNachricht(java.net.Socket socket) throws IOException 
   {
       BufferedReader bufferedReader =
           new BufferedReader(
               new InputStreamReader(
                   socket.getInputStream()));
       char[] buffer = new char[200];
       int anzahlZeichen = bufferedReader.read(buffer, 0, 200); // blockiert bis Nachricht empfangen
       String nachricht = new String(buffer, 0, anzahlZeichen);
       return nachricht;
   }
}
Server usw. werden alle richtig übergeben.

kompletter Fehler:
Code:
08-04 14:54:34.091: E/AndroidRuntime(8528): FATAL EXCEPTION: main
08-04 14:54:34.091: E/AndroidRuntime(8528): android.os.NetworkOnMainThreadException
08-04 14:54:34.091: E/AndroidRuntime(8528): 	at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1118)
08-04 14:54:34.091: E/AndroidRuntime(8528): 	at java.net.InetAddress.lookupHostByName(InetAddress.java:385)
08-04 14:54:34.091: E/AndroidRuntime(8528): 	at java.net.InetAddress.getAllByNameImpl(InetAddress.java:236)
08-04 14:54:34.091: E/AndroidRuntime(8528): 	at java.net.InetAddress.getAllByName(InetAddress.java:214)
08-04 14:54:34.091: E/AndroidRuntime(8528): 	at java.net.Socket.tryAllAddresses(Socket.java:108)
08-04 14:54:34.091: E/AndroidRuntime(8528): 	at java.net.Socket.<init>(Socket.java:177)
08-04 14:54:34.091: E/AndroidRuntime(8528): 	at java.net.Socket.<init>(Socket.java:149)
08-04 14:54:34.091: E/AndroidRuntime(8528): 	at de.raspberrypi.steuerung.Ping$1.run(Ping.java:41)
08-04 14:54:34.091: E/AndroidRuntime(8528): 	at android.os.Handler.handleCallback(Handler.java:615)
08-04 14:54:34.091: E/AndroidRuntime(8528): 	at android.os.Handler.dispatchMessage(Handler.java:92)
08-04 14:54:34.091: E/AndroidRuntime(8528): 	at android.os.Looper.loop(Looper.java:137)
08-04 14:54:34.091: E/AndroidRuntime(8528): 	at android.app.ActivityThread.main(ActivityThread.java:4921)
08-04 14:54:34.091: E/AndroidRuntime(8528): 	at java.lang.reflect.Method.invokeNative(Native Method)
08-04 14:54:34.091: E/AndroidRuntime(8528): 	at java.lang.reflect.Method.invoke(Method.java:511)
08-04 14:54:34.091: E/AndroidRuntime(8528): 	at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1027)
08-04 14:54:34.091: E/AndroidRuntime(8528): 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:794)
08-04 14:54:34.091: E/AndroidRuntime(8528): 	at dalvik.system.NativeStart.main(Native Method)
 
DagobertDokate

DagobertDokate

Experte
Ich bin mir fast sicher das du die GLEICHE FRAGE schon mal gestellt hast...
Ich zitiere mich mal selbst zzzZZzzzz
Hey ho,

1) Netzwerk Kommunikation in eigenen Thread ausgelagert?
2) Permissions gesetzte?

lg. Dagobert
lg. Dagobert
 
Z

Zoopa

Stammgast
du darfst nicht den ganzen Code innerhalb von runOnUiThread ausführen. Alles, was das Networking betrifft (Socket lesen/schreiben) muss ausserhalb sein. runOnUiThread führt den Code ja wie der Name schon sagt im UI-Thread aus, und dort darf nichts mit Networking sein.

Code:
public void run()
{
	while(true)
	{
    	    try
    	    {
    	        java.net.Socket socket = new java.net.Socket(Server,PORT); // verbindet sich mit Server
    		String zuSendendeNachricht = "Ping";
    		schreibeNachricht(socket, zuSendendeNachricht);
    		String empfangeneNachricht = leseNachricht(socket);
    		System.out.println(empfangeneNachricht);
    		
                //[B]erst innerhalb des IF willst du etwas machen, was das GUI betrifft[/B]
                if(empfangeneNachricht.equals("true"))
    		{
                    [B]myActivity.runOnUiThread(...);[/B]
	        }
    	}

        //...
}
 
A

audacity363

Ambitioniertes Mitglied
@DagobertDokate bitte ließ dir die vorherigen Beiträge mal durch. Daraus wirst du entnehmen können das es sich dieses mal anderes verhält.

@Zoopa ach so okey Danke werde es nachher mal ausprobieren, da ich schon wieder unterwegs bin, und mich dann nochmal melden.

Gesendet von meinem ARCHOS 101G10 mit der Android-Hilfe.de App
 
DagobertDokate

DagobertDokate

Experte
@DagobertDokate bitte ließ dir die vorherigen Beiträge mal durch. Daraus wirst du entnehmen können das es sich dieses mal anderes verhält.
Nö Exception und Grund sind der gleiche wie letztes mal -> Du hast den Netzverkehr nicht ausgelagert...
 
Ähnliche Themen - TextView außerhalb einer Activity ansteuern Antworten Datum
1
3
4