Schrittweises abändern des GUI während for-Schleife / pausieren einer for-Schleife

DorFey

Mitglied
Hallo Leute!

Ich habe mich an folgendem versucht:

Vokabelquiz erstellen mit 6 Antwortmöglichkeiten.

Kurzbeschreibung:

Richtige Vokabelpaare (n Paare) sind in Array gespeichert,
z.B.: verb (deutsch) = verbArr[n][0], verb (fremdsprache) = verbArr [n][1]

Ein zweites Array enthält den Platz der richtigen Antwort (zahlen 1 bis 6 wird jedem Button zugeordnet, 1==richtig, 2-6==falsch)
Dieses Array enthält alle möglichen 720 Permutationen der Zahlen 1 bis 6. => numArr [720][6].

Z.B:
numArr [2][0]=3
numArr [2][1]=4
numArr [2][2]=1
numArr [2][3]=5
numArr [2][4]=6
numArr [2][5]=2

Für das 3. Vokabelpaar liegt der richtige Wert somit am 3. Button.

Zu erratender Begriff ist immer der nächste Index w -> verbArr [w][0]
1 Button erhält (siehe numArray) = verbArr [w][1] = richtigen Werten, andere 5 Buttons erhalten zufällige Werte aus einem Teilbereich der Gesamtmenge (wobei immer nur jener Teil dafür herangezogen wird, wo nicht das richtige i liegt).

Folgende Problemstellung:
Ich habe eine for-Schleife aufgesetzt, welche das Ziel haben sollte nach jedem Schleifendurchlauf folgendes zu tun:

- Buttons einfärben (grün-richtig / rot-falsch) je nach gegebener Antwort
- Schleifendurchlauf für 500ms unterbrechen über Thread.sleep().
- Buttons auf Standardfarbe weiß zurückfärben und Buttons mit neuen Begriffen hinterlegen
- Buttons über setText mit neuen Werten belegen (das habe ich nicht mehr versucht einzubauen)

Aber:

Die for-Schleife läuft alle 720 Schleifendurchläufe durch und ändert anschließend das UI einmalig ab.
(Schleife wartet nicht auf Click, sondern rennt einfach durch). Habe versucht mir den aktuellen index über setText auf den 6. Button darzustellen und mir wurde
immer der letzte Arraywert angezeigt).

Thread.sleep(ms: 500) hilft auch nicht -> Programm macht dann einmalig 500ms * 720 Pause und friert das UI für diesen Zeitraum.
Ziel wäre gewesen 500ms warten -> UI Buttons zurückfärben -> auf Buttonclick warten -> UI Buttons rot/grün -> 500ms Pause etc.
Sodass die Änderung im UI schrittweise passiert.

Bei stackoverflow habe ich bei einem ähnlichen Problem gelesen:

1602437094335.png

Ich gehe davon aus, dass das unterbrechen und der spätere restart der for-Schleife per Buttonclick somit nur bedingt möglich ist und einen ganz anderen Lösungsansatz braucht?

Unten findet ihr den betreffenden Code-Ausschnitt:

Java:
.... 

private void threadCatcher(){
    try {
        Thread.sleep(500);
    } catch (InterruptedException ie) {
        Thread.currentThread().interrupt();
    }
}

// 

button_weiter.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {

button_verb1.setOnClickListener(this);
button_verb2.setOnClickListener(this);
button_verb3.setOnClickListener(this);
button_verb4.setOnClickListener(this);
button_verb5.setOnClickListener(this);
button_verb6.setOnClickListener(this);

for (int w = 0; w<720; w++){

                    if(numArr[w][0]==1){

                        switch (view.getId()) {
                            case R.id.button_verb1:
                                button_verb1.setBackground(getResources().getDrawable(R.drawable.my_button_main_true));
                                threadCatcher();
                                button_verb6.setText(String.valueOf(w));
                        
                            case R.id.button_verb2:
                                button_verb1.setBackground(getResources().getDrawable(R.drawable.my_button_main_true));
                                button_verb2.setBackground(getResources().getDrawable(R.drawable.my_button_main_false));
                                threadCatcher();
                                button_verb6.setText(String.valueOf(w));
                    
                            case R.id.button_verb3:
                                button_verb1.setBackground(getResources().getDrawable(R.drawable.my_button_main_true));
                                button_verb3.setBackground(getResources().getDrawable(R.drawable.my_button_main_false));
                                threadCatcher();
                                button_verb6.setText(String.valueOf(w));

                            case R.id.button_verb4:
                                button_verb1.setBackground(getResources().getDrawable(R.drawable.my_button_main_true));
                                button_verb4.setBackground(getResources().getDrawable(R.drawable.my_button_main_false));
                                threadCatcher();
                                button_verb6.setText(String.valueOf(w));

                            case R.id.button_verb5:
                                button_verb1.setBackground(getResources().getDrawable(R.drawable.my_button_main_true));
                                button_verb5.setBackground(getResources().getDrawable(R.drawable.my_button_main_false));
                                threadCatcher();
                                button_verb6.setText(String.valueOf(w));

                            case R.id.button_verb6:
                                button_verb1.setBackground(getResources().getDrawable(R.drawable.my_button_main_true));
                                button_verb6.setBackground(getResources().getDrawable(R.drawable.my_button_main_false));
                                threadCatcher();
                                button_verb6.setText(String.valueOf(w));
                            }}

                            else if(shuffleNumArr[w][0]==2){

                                switch (view.getId()) {
                                    case R.id.button_verb1:
                                        button_verb1.setBackground(getResources().getDrawable(R.drawable.my_button_main_false));
                                        button_verb2.setBackground(getResources().getDrawable(R.drawable.my_button_main_true));
                                        threadCatcher();
                                        button_verb6.setText(String.valueOf(w));

                                    case R.id.button_verb2:
                                        button_verb2.setBackground(getResources().getDrawable(R.drawable.my_button_main_true));
                                        threadCatcher();
                                        button_verb6.setText(String.valueOf(w));

                                    case R.id.button_verb3:
                                        button_verb2.setBackground(getResources().getDrawable(R.drawable.my_button_main_true));
                                        button_verb3.setBackground(getResources().getDrawable(R.drawable.my_button_main_false));
                                        threadCatcher();
                                        button_verb6.setText(String.valueOf(w));

                                    case R.id.button_verb4:
                                        button_verb2.setBackground(getResources().getDrawable(R.drawable.my_button_main_true));
                                        button_verb4.setBackground(getResources().getDrawable(R.drawable.my_button_main_false));
                                        threadCatcher();
                                        button_verb6.setText(String.valueOf(w));

                                    case R.id.button_verb5:
                                        button_verb2.setBackground(getResources().getDrawable(R.drawable.my_button_main_true));
                                        button_verb5.setBackground(getResources().getDrawable(R.drawable.my_button_main_false));
                                        threadCatcher();
                                        button_verb6.setText(String.valueOf(w));

                                    case R.id.button_verb6:
                                        button_verb2.setBackground(getResources().getDrawable(R.drawable.my_button_main_true));
                                        button_verb6.setBackground(getResources().getDrawable(R.drawable.my_button_main_false));
                                        threadCatcher();
                                        button_verb6.setText(String.valueOf(w));
                                    }}
    
    // ETC weiter so für alle 6 Buttons

Freu mich über alle Anregungen.
Liebe Grüße
 
Du Karteireiter im sogenannten UI Thread und blockiertes diesen. Damit die Änderungen sichtbar werden, muss aber das Fenster neu gemalt werden, was ebenfalls im UI Thread statt findet.

Daher wäre hier mein Lösungsvorschlag die Verwendung eines Timers, der Veränderungen anstößt. Dann hättest du z.B. Einen Timer, der alle x ms schauen soll, ob etwas geändert werden soll und dies dann ausführt.
Oder du erstellst einen neuen Thread (z.B. mit SwingWorker) und kannst da dann mit den sleep Aufrufen nur diesen Thread pausieren.

Schau Dir zu dieser Thematik z.B. http://openbook.rheinwerk-verlag.de/javainsel9/javainsel_19_026.htm an.
 
Hat nicht direkt was mit dem Problem zu tun, aber über diese Nutzung von Arrays sollte man schon lange hinaus sein, wenn man was mit GUIs macht. Das ganze kann man deutlich besser mit vernünftigen Objekten umsetzen, das merkwürdige if-else-switch-Konstrukt wird man damit auch los.
 
Hallo wieder einmal!


@mrBrown

Ich habe mich nun ein wenig mehr mit den Grundlagen vertraut gemacht und mich ein wenig besser in die Themenbereiche Objekte, Klassen, Datenkapselung eingearbeitet, wies mir hier schon von verschiedener Seite (auch in meinem 2. thread) empfohlen wurde.

Das Ergebnis davon war:

Ich hätte vor die Vokabel in Klassen mit gleichen Attributen zu unterteilen. Um auf die Attribute zugreifen zu können implementiere ich getter & setter-Methoden.

In der späteren Benutzeroberfläche führt jeder Button im Übermenü in eine separate Activity, welche die Vokabeln der Klasse abfrägt (also alle Objekte). Nach Ende der Activity werden die veränderten Objektattribute gespeichert.

Mein Klassen-Konzept:

Java:
package com.doriandev.greek;

public class Vokabel {

    //++++ VOKABELPAARE ++++

    private final String vocBasis;
    private final String vocTranslation;

    //++++ ZÄHLVARIABLEN ++++

    private final int index;
    private int wrongAttempts;
    private int correctAttempts;
    private int lastQuery;
    private int level;
    private boolean inBox1;
    private boolean inBox2;
    private boolean inBox3;
    private boolean longTermMem;

    //++++ KONSTRUKTOR ++++

    public Vokabel (int vocBasis, int vocTranslation, int index, int level, boolean inBox1, boolean inBox2, boolean inBox3, boolean longTermMem) {
    this.vocBasis = Integer.toString(vocBasis);
    this.vocTranslation = Integer.toString (vocTranslation);
    this.index = index;
    this.level = level;
    this.inBox1 = inBox1;
    this.inBox2 = inBox2;
    this.inBox3 = inBox3;
    this.longTermMem = longTermMem;
    }

    //++++ SETTER ++++

    public void setWrongAttempts(int wrongAttempts){
        this.wrongAttempts = wrongAttempts;
    }
    public void setCorrectAttempts(int correctAttempts){
        this.correctAttempts = correctAttempts;
    }
    public void setLastQuery (int lastQuery){
        this.lastQuery = lastQuery;
    }
    public void setInBox1 (boolean inBox1){
        this.inBox1 = inBox1;
    }
    public void setInBox2 (boolean inBox2){
        this.inBox2 = inBox2;
    }
    public void setInBox3 (boolean inBox3){
        this.inBox3 = inBox3;
    }
    public void setLongTermMem (boolean longTermMem){
        this.longTermMem = longTermMem;
    }

    //++++ GETTER ++++

    public String getVocBasis (){
        return vocBasis;
    }
    public String getVocTranslation (){
        return vocTranslation;
    }
    public int getIndex(){
        return index;
    }
    public int getWrongAttempts(){
        return wrongAttempts;
    }
    public int getCorrectAttempts(){
        return correctAttempts;
    }
    public int getLastQuery(){
        return lastQuery;
    }
    public int getLevel(){
        return level;
    }
    public boolean isInBox1(){
        return inBox1;
    }
    public boolean isInBox2(){
        return inBox2;
    }
    public boolean isInBox3(){
        return inBox3;
    }
    public boolean isLongTermMem(){
        return longTermMem;
    }
}

Java:
package com.doriandev.greek;

import android.os.Bundle;
import android.view.View;
import android.widget.Button;

import androidx.appcompat.app.AppCompatActivity;

public class verbActivity extends AppCompatActivity {

    Button button_verb1, button_verb2, button_verb3, button_verb4, button_verb5, button_verb6, button_weiter;
    Button tv_verben;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_verbs);

        this.getWindow().getDecorView().setSystemUiVisibility(
                View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                        | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                        | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                        | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                        | View.SYSTEM_UI_FLAG_FULLSCREEN
                        | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);

        tv_verben = (Button) findViewById(R.id.tv_verben);
        button_verb1 = (Button) findViewById(R.id.button_verb1);
        button_verb2 = (Button) findViewById(R.id.button_verb2);
        button_verb3 = (Button) findViewById(R.id.button_verb3);
        button_verb4 = (Button) findViewById(R.id.button_verb4);
        button_verb5 = (Button) findViewById(R.id.button_verb5);
        button_verb6 = (Button) findViewById(R.id.button_verb6);
        button_weiter = (Button) findViewById(R.id.button_weiter);

        int n =20;

        Vokabel[] vocList = new Vokabel[n];

        for(int i=0;i<vocList.length;i++){
            vocList[i] = new Vokabel(
                    this.getResources().getIdentifier("verbDE"+i, "string", getPackageName()),
                    this.getResources().getIdentifier("verbGR"+i, "string", getPackageName()),
                    i,
                    1,
                    true,
                    false,
                    false,
                    false);
        }
}}

Kann man das so in dieser Art aufsetzen, oder wird hier irgendetwas zu Problemen führen?

Was mir in dem Zusammenhang noch reichlich unklar ist (und ich parallel auch auf Ideensuche dazu bin):

1) Wie speichere Objekte und ihre Zustände (Abfragehäufigkeiten, etc.) dauerhaft ab, sodass sie nicht bei Activity-Start überschrieben werden?
2) Wie lege ich Spielerprofile an, in welchen diese Werte dauerhaft gespeichert werden? (ich nehme an das wird wieder eine Klasse?)
3) Wie vermeide ich lange Ladezeiten und hohen RAM-Bedarf?

@kneitzel

Danke für die Hilfestellung, ich arbeite mich gerade durch die Kapitel durch. Merke aber, dass mir dafür noch wesentliche Grundlagen fehlen. Sobald ich eine Idee zu einer möglichen Umsetzung habe, würde ich sie hier reinstellen.
 

Zurück
Oben