Android Auf ImageView aus einem anderen Thread zugreifen liefert Fehlermeldung (App stürzt ab)

insidERR

Mitglied
Hallo zusammen.
Bin noch recht neu in der Java/Android Welt.

Ich erstelle eine App in der ein ImageView (Bild mit einem roten WiFi Symbol) über einem anderen ImageView (Fotoanzeige) liegt.
Da die App auf WLAN angewiesen ist, will ich ein Hintegrundthread erstellen, welcher alle 3 Sekunden den aktuellen WiFiStatus abruft und bei unterschreitung eines Pegels ein ImageView (Bild mit einem roten WiFi Symbol) einblendet.
Ich starte aus "onCreate" den Hintegrundthread (WiFiUeberwachung), welcher in der Endlosschleife den Status abruft.
Je nach Wert, will ich das besagte ImageView ein bzw. ausblenden.
Dieser Thread blendet beim Start das ImageView aus. Wenn es aber wieder eingeblendet werden soll, stürzt die App ab und meldet
"android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views."
Bei Stackoverflow gibt es verschiedene Lösungsansätze wie z.B. den hier.
Da komme ich aber nicht weiter. Wenn dort die while(true) Schleife einbaue, friert die App schon beim Start ein.
Hat jemand ne Idee, wie man den folgenden (meinen) Code anpassen kann.

Java:
    .
    .
    .
    public ImageView WiFiWarning;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
.
.
        WiFiWarning=findViewById(R.id.WiFi_Warning);
        
        //einmalige Prüfung der WiFi Verbindung (klappt perfekt)
        if(CheckWiFiQuality()<4){WiFiWarning.setVisibility(View.VISIBLE);}else{WiFiWarning.setVisibility(View.INVISIBLE);}
        
        //alle 3 Sekunden den Status prüfen und bei Bedarf WiFiWarning ein/ausblenden
        WiFiUeberwachung(3000,4);


Java:
    //Thread für eine kontinuierliche Überwachung der WiFi Verbindung
    public void WiFiUeberwachung(long warteZeit, int minSignalstaerke){
        AsyncTask.execute(() -> {
            try {
                while(true) {
                    Thread.sleep(warteZeit); //warte X Sekunden
                    //in der folgenden Zeile schmiert die App ab, wenn das ImageView(WiFiWarning) eingeblendet werden soll. Ausblenden klappt wie gewollt.
                    if(CheckWiFiQuality()<minSignalstaerke){WiFiWarning.setVisibility(View.VISIBLE);}else{WiFiWarning.setVisibility(View.INVISIBLE);}
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
    }

    //Liefert als Antwort eine Zahl zwischen 1 und 5 (1=ganz schlecht, 5 sehr gut)
    private int CheckWiFiQuality()
    {
        WifiManager wifiManager = (WifiManager) this.getSystemService(Context.WIFI_SERVICE);

        // Level of a Scan Result
        List<ScanResult> wifiList = wifiManager.getScanResults();
        for (ScanResult scanResult : wifiList) {
            int level = WifiManager.calculateSignalLevel(scanResult.level, 5);
            System.out.println("Level is " + level + " out of 5");
            return level;
        }

        return level;
    }

Hat jemmand ne Idee?
Danke
 

LimDul

Top Contributor
Vorneweg, ich hab von Android keine Ahnung, aber generell gilt bei allen UI-Frameworks:

* Auf UI Elemente darf nur aus dem zentralen UI Thread (in Swing z.B. der Event Dispatching Thread) zugegriffen werden.

Ansonsten kann es zu vielen Problemen keinen, weil zwei Threads gleichzeitig UI-Elemente ändern. Je nach UI Framework wird das mehr oder weniger stark forciert.

Hier gibt es auf Stackoverflow ein Beispiel: https://stackoverflow.com/questions/5185015/updating-android-ui-using-threads, was auf folgende Methode verweist: https://developer.android.com/reference/android/app/Activity#runOnUiThread(java.lang.Runnable)
 

Jw456

Top Contributor
Du kannst nicht aus einem Thread auf view Element zugreifen.
Benutze dazu runonuithraed.
Um im Thread auf den UI zukommen.

Eine weitere Möglichkeit ist. Handler zubenutzen
 

insidERR

Mitglied
Du kannst nicht aus einem Thread auf view Element zugreifen.
Benutze dazu runonuithraed.
Um im Thread auf den UI zukommen.

Eine weitere Möglichkeit ist. Handler zubenutzen
Hallo Jw456,
vielen Dank für den Hinweiß mit dem "RunOnUIthread".
Meistens sind einem die Befehle unbekannt und man hat einfach keinen Plan, wonach man suchen soll.
Der erste Suchtreffer brachte mich auf diese Seite mit dem Beispielcode.
Habe jetzt meinen Code etwas angepasst und nun läufts wie gewollt.

Java:
    //Thread für eine kontinuierliche Überwachung der WiFi Verbindung
    public void WiFiUeberwachung(long warteZeit, int minSignalstaerke){
        new Thread() {
            public void run() {
                while (true) {
                    try {
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                if(CheckWiFiQuality()<minSignalstaerke){
                                    WiFiWarning.setVisibility(View.VISIBLE);
                                }else{
                                    WiFiWarning.setVisibility(View.INVISIBLE);}
                            }
                        });
                        Thread.sleep(warteZeit);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }.start();
    }

@LimDul dir auch danke für deine Rückmeldung
 

KonradN

Super-Moderator
Mitarbeiter
Evtl. nur ein kleiner Hinweis: Dieses new Runnable() { ist seit Java 8 so eher unüblich. Der Code ist zu aufgebläht und schwer lesbar.

Hier kommen Lambda Expressions und Methoden Referenzen ins Spiel: Runnable ist ein funktionales Interface, d.h. es wird nur eine Methode gefordert. Somit reicht es, dass Du eine Methode mit passender Signatur hast. Das hat den Vorteil, dass der Code, den Du da geschrieben hast, auch gleich eine Beschreibung bekommt. Was macht er? Sowas wie changeWiFiWarningVisibility.

Du hast also eine Methode:
Java:
public void changeWiFiWarningVisibility() {
    if(CheckWiFiQuality()<minSignalstaerke) {
        WiFiWarning.setVisibility(View.VISIBLE);
    } else {
        WiFiWarning.setVisibility(View.INVISIBLE);
    }
}

Und der Aufruf wäre hier dann einfach: runOnUiThread(this::changeWiFiWarningVisibility);

Oder - wenn man es als Lambda Expression haben möchte:
runOnUiThread( () -> changeWiFiWarningVisibility());
(Das ist üblich, wenn da Parameter unterschiedlich sind und daher keine Methodenreferenz gehen würde)
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
Alex/89 ImageView mit einem Bild von der SD Karte füllen Android & Cross-Platform Mobile Apps 5
missy72 Android ImageView Aus- Einblenden und Ressource ändern Android & Cross-Platform Mobile Apps 1
ImageView wird nicht angezeigt Android & Cross-Platform Mobile Apps 4
W Pixel Farbe in eine andere Farbe ändern im ImageView von ein Icon Android & Cross-Platform Mobile Apps 14
W Rand ändern beim ImageView bei Picasso Android & Cross-Platform Mobile Apps 1
W Bild aus dem Internet in View bzw. ImageView laden (Fragment) Android & Cross-Platform Mobile Apps 2
S Image dynamisch anhand von id in ImageView anpassen Android & Cross-Platform Mobile Apps 4
A Android Studio: ImageView verpixelt Android & Cross-Platform Mobile Apps 2
J ImageView: Bilder in niedriger Grafik anzeigen lassen Android & Cross-Platform Mobile Apps 2
J ImageView zeigt kein Bild an, Andere Elemente jedoch sichtbar Android & Cross-Platform Mobile Apps 3
D Android ImageView zeichnen Android & Cross-Platform Mobile Apps 2
M Android ImageView verliert ScaleTyp Android & Cross-Platform Mobile Apps 2
N Save Image to DB and set ImageView Android & Cross-Platform Mobile Apps 1
W ImageView wird nicht angezeigt Android & Cross-Platform Mobile Apps 19
AllBlack Auf der Suche nach einem App-Entwickler Android & Cross-Platform Mobile Apps 1
ruutaiokwu Android In einem Android-“Spinner”-Element GLEICHZEITIG Bild (links) UND Text (rechts) anzeigen Android & Cross-Platform Mobile Apps 0
ruutaiokwu Wie fügt man bei Android Studio .jar-Libraries zu einem Android-Java-Projekt hinzu? Android & Cross-Platform Mobile Apps 33
L Eingaben in der MainActivity einem Service übergeben Android & Cross-Platform Mobile Apps 0
M mehrere URLs in einem AsyncTask abarbeiten Android & Cross-Platform Mobile Apps 2
M Android App → Problem mit dem Speichern von einem Bitmap–Objekt. Android & Cross-Platform Mobile Apps 1
G GPS in einem Service abfragen Android & Cross-Platform Mobile Apps 2
J wie sicher ist der Quellcode in einem apk? bzw wie schützt man ihn? Android & Cross-Platform Mobile Apps 6
B Android In einem View der ersten Activity zweite anzeigen Android & Cross-Platform Mobile Apps 2
A Android Von einem Thread auf anderen zugreifen Android & Cross-Platform Mobile Apps 3
W Android Bestimmen von welchem Typ die Objekte in einem ArrayAdapter sind Android & Cross-Platform Mobile Apps 3
X Android Befehle an einem PC-Programm schicken Android & Cross-Platform Mobile Apps 4
N Textview macht immer nach einem Beistrich einen Abstand Android & Cross-Platform Mobile Apps 6
S Android binäre Daten zwischen Android und einem Java-Server Android & Cross-Platform Mobile Apps 5
B Programm aus einem Buch funzt nicht! Android & Cross-Platform Mobile Apps 16
B Zeilen zählen in einem Textfile Android & Cross-Platform Mobile Apps 1
G Schriftgröße in einem TextField ändern Android & Cross-Platform Mobile Apps 2
A Problem beim Subtrahieren eines Double von einem Double Android & Cross-Platform Mobile Apps 5
U ein texteingabefeld auf einem Canvas . Android & Cross-Platform Mobile Apps 2
M Java Midlet -> in einem ChoiceGroup ein TextField zur Wah Android & Cross-Platform Mobile Apps 2
G Java Programme auf einem PDA Android & Cross-Platform Mobile Apps 1
M Activity einer anderen App mit result Android & Cross-Platform Mobile Apps 2
J Android Zugriff auf eine Datei, diese von einer anderen App erstellt wurde? Android & Cross-Platform Mobile Apps 11
F Projekt mit GIT auf anderen Rechner umgezogen Android & Cross-Platform Mobile Apps 2
L Android Marker mit Icons versehen und mit anderen icons clustern lassen Android & Cross-Platform Mobile Apps 0
H Android Aufrufen von "setContentView" in einer anderen Klasse Android & Cross-Platform Mobile Apps 3
S Auf Methode zugreifen von anderen Klassen Android & Cross-Platform Mobile Apps 6
G eine Methode einer anderen Activity aufrufen Android & Cross-Platform Mobile Apps 9
A Kann nicht in TextView einer anderen Klasse schreiben - wieso? Android & Cross-Platform Mobile Apps 9
M Wie in einer anderen "nicht canvas" klasse zeichne Android & Cross-Platform Mobile Apps 5

Ähnliche Java Themen


Oben