Wie Orientierungsänderung behandeln ?

M

maksimilian

Ambitioniertes Mitglied
0
Hallo Ihr,
auf das Thema wurde teilweise bereits in meinem Thread "Wie in onDestroy() reagieren ?" eingegangen, möchte das Thema aber hier breiter aufstellen. Der Lifecycle einer Activity ist mir bekannt.

Ich habe eine App, in welcher eine Oberfläche bedient wird und die Starts von Threads erfolgt, in welchen in unendlichen Schleifen Ereignisse verarbeitet werden (WLAN-Watchdog, TCP-Client). Die Threads werden nur im ersten onCreate gestartet. Den Wechsel von Portrait zu Landscape möchte ich selber behandeln, weshalb im Manifest android:configChanges die Option Orientation nicht enthält.
Jetzt folgende Fragen:

1. Wie sichere ich Inhalte von TextViews, um sie im nächsten durch die Orientierungsänderung verursachten onCreate wieder herzustellen ?

2. Werden durch die Orientierungsänderung die Threads beendet (onDestroy ) ? Wenn nicht, wirkt sich die Orientierungsänderung auf sie aus ?

maksimilian
 
Zu 1 würde ich sagen schaue dir mal onSaveInstanceState() und onRestoreInstanceState() an.

2. Threads sollten eigentlich weiter laufen. Die App wird ja nicht beendet.

Wie es sich auf dein Layout auswirkt kannst nur du wissen denn nur du weißt was du damachst.
 
Die langlaufenden Threads würde ich in einem Service starten. Die sollten zwar nicht beendet werden beim destroy/create cycle, aber du hast halt keine gültige Referenz mehr drauf, mit der du was machen könntest.
 
Die Klasse wird beim drehen des Handys nicht beendet. Wenn doch ist ein Fehler im Code oder Layout.
Mit einer Instanzvariablen hätte er immer die Instanz auf den Thread.

Bemerkung ein Service läuft meines Wissens im Mainthread.
 
jogimuc schrieb:
Zu 1 würde ich sagen schaue dir mal onSaveInstanceState() und onRestoreInstanceState() an.
onSaveInstance verwende ich bereits, um einige Variable in einem Bundle sichern. Es wäre aber ein etwas umständliches Verfahren, dies auch für den Inhalt von TextViews zu tun (für jeden Inhalt ein eigener Key).

jogimuc schrieb:
2. Threads sollten eigentlich weiter laufen. Die App wird ja nicht beendet.
Das nehme ich auch an. Hier habe ich noch nicht genau hingeschaut. Mir fällt zunächst auf, dass nach Orientierungsänderung im Logcat die in die Threads eingefügten Traces (Log.d) nicht mehr vorkommen.
 
Ich habe inzwischen mit einigen Test-Apps experimentiert, komme aber nicht weiter. Zumindest ist mir klar, dass sich Threads von Orientierungsänderungen nicht stören lassen. Ich habe jetzt mal einen Effekt herausgegriffen und demonstriere ihn in einer einfachen App.
Es wird in der MainActivity ein Thread gestartet, welcher einen Zähler mit runOnUiThread() in eine TextView ausgibt. Sobald das Handy von Porträt nach Landscape wechselt wird die Ausgabe eingefroren, obgleich der Zähler weiterläuft. Wie erreiche ich, dass der Thread bei Orientierung UI nicht verliert ?

Code:
public class MainActivity extends AppCompatActivity {
    TextView textInfo;
    Integer onCreateCalls = 0;
    static final String CALLS = "calls";
    static final String INFO = "info";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textInfo = (TextView) findViewById(R.id.Info);
        if (savedInstanceState != null) {
            onCreateCalls = savedInstanceState.getInt(CALLS);
            textInfo.setText(savedInstanceState.getCharSequence(INFO));
        }
        if (onCreateCalls == 0) {
            Thread ServerThread = new Thread(new MyThread());
            ServerThread.start();
        }
        onCreateCalls += 1;
    } // onCreate
//
    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putInt(CALLS, onCreateCalls);
        outState.putCharSequence(INFO, textInfo.getText().toString());
    }
    //
    @Override
    protected void onResume() {super.onResume(); }
    @Override
    protected void onStart() {super.onStart();}
    @Override
    protected void onRestart() {super.onRestart(); }
    @Override
    protected void onPause() {super.onPause();}
    @Override
    protected void onStop() {super.onStop(); }
    @Override
    protected void onDestroy() {super.onDestroy();}
    //
    public class MyThread implements Runnable {
       Integer i=0;
        @Override
        public void run() {
            while(i <100) {
                i +=1;
                try {
                    sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                runOnUiThread(new Runnable() {
                    //@Override
                    public void run() {
                        textInfo.setText(i.toString());
                    }
                }); // runOnUiThread
            } // while
        } // run
    } // MyThread
}
 
Bist du dir sicher das der Thread weiter läuft? Benutze ein log um zu prüfen.
Setze überall sinnvolle logs im das Verhalten zu sehen.
 
Ich habe das Weiterlaufen des Zählers anhand von Traces überprüft. Diese habe ich der Übersichtlichkeit halber in der Darstellung entfernt!
 
Ist die Verwendung von ViewModel und LIveData sinnvoll. Leider fehlen mir (noch) Grundlagen, um das selbst an meinem Beispiel auszuprobieren. Kann mir da jemand helfen ?
 
Hallo ein möglich im Thread mittels runonuithraed Ausgaben zu machen nach dem drehen könnte sein die ID im Thread neu zusuchen mit findViewById vor der Ausgabe.
Beiträge automatisch zusammengeführt:

maksimilian schrieb:
Ist die Verwendung von ViewModel und LIveData sinnvoll. Leider fehlen mir (noch) Grundlagen, um das selbst an meinem Beispiel auszuprobieren. Kann mir da jemand helfen ?

Kommt immer darauf an was du machen willst wozu du es brauchst.

Wenn du auf dein Ausgabe Problem beim Handy dehen abspielt da wird es dir nicht viel nutzen.
Denn nach dem drehen wird das Layout neugeladen und es werden neue Instanzen von den views erstellt.

Denn Sinn und Nutzen von Viewmode sehe ich in Daten die auch In anderen Activity Fragmenten verfügbar gemacht werden sollen.



Frage zu deinem Handy dreh Problem. Hast du für horizontal und vertikal verschiedene Layouts? Oder nur eine Layout XML Datei.
 
Zuletzt bearbeitet:
In meiner produktiven App stelle ich in onCreate() verschiedene Layouts ein, abhängig von Orientierung und Display-Größe.
Wenn mir geholfen werden soll, bräuchte ich mal konkreten Code und nicht nur Hinweise auf irgendwas. Wie beispielsweise finde ich in runOnUiThread() die View-Id von activity_main ? Kann die über das Bundle mit put/get übergeben werden ?
 
Hello maksimilian,
viele deiner Probleme lösen sich über viewmodel von ganz alleine...die Probleme beim Orientierungswechsel, die Werte von verschiedenen Fragments beziehen uvm. viewmodel ist sozusagen ein singleton und lifecycleaware - du musst dich um nichts kümmern.

Erstelle eine Klasse und erweitere sie mit ViewModel:
public class MainViewModel extends ViewModel {
}
Leg dort deine verschiedenen Werte ab die du in deinen Ansichten (also Views) benötigst und erstelle getter & setter dazu.

In der Activity machst du:
MainViewModel mainViewModel = new ViewModelProvider(this).get(MainViewModel.class);

und dann kannst du über mainViewModel.... auf deine Getter/Setter zugreifen.

Wenn du in Fragments deine Werte brauchst, über:
MainViewModel mainViewModel = new ViewModelProvider( requireActivity() ).get(MainViewModel.class);
Gruß
Michael
 
Danke, Michael, für den Tipp. Werde ich ausprobieren, wenn ich weiß, wie mit einem ViewModel umzugehen ist :)
 
Hallo ob ihm das Thema ViewModle wirklich hilft?
Er will in einen Thread der auch nach dem Handy drehen weiter läuft eine Ausgabe auf dem UI machen.
Da beim drehen des Handys wird die onCreate wider durchlaufen , und somit das Layout neu geladen und neue Instanzen der Views erstellt. Der Bezug in den weiter laufenden Thread zum Viewelement ist weg und es erfolgt keine Ausgabe auf dem Bildschirm.
Auch der Bezug zu dem Thread ist weg .
Eine einfache Möglichkeit ist die Variable vom Thread und TextView als Klassenvariable
Static Instanzvariable zu erstellen.

Oder Handler zu benutzen und nicht RunOnUIThread.

Code:
public class MainActivity extends AppCompatActivity {

    static TextView textInfo;
    static Thread serverThread;

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

        textInfo = (TextView) findViewById(R.id.txtinfo);

        if (serverThread == null) {
            serverThread = new Thread(new MyThread());
            serverThread.start();
            Log.d("test","Thread wurde gestartet");
        }
    }


    public class MyThread implements Runnable {
        Integer i=0;
        @Override
        public void run() {
            while(i <100) {
                i +=1;
                try {
                    sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                runOnUiThread(new Runnable() {
                    //@Override
                    public void run() {
                        textInfo.setText(i.toString());
                    }
                }); // runOnUiThread
            } // while
        } // run
    } // MyThread

}
 
Zuletzt bearbeitet:
@jogimuc : hm..also das ViewModel würde nach einem Orientierungswechsel auf jeden Fall den Inhalt der UI wiederherstellen können. Das ViewModel wird dadurch nämlich nicht neu erstellt - somit bleiben die Values darin gespeichert genauso wie du es mit onSaveInstanceState beschrieben hast, nur eben einfacher ...das ist ja der Sinn von dem Ding.
 
wie du im code sehen kannst will er aus dem Thread heraus den Bildschirm Aktualisieren.
in der onCrate macht er keine Ausgabe kein setText().
da nüsst ihm das viewModel auch nicht.

Der Thread hat die Intstanz der view verloren mit der static Variablen kann er auf die neue Instanz wider zugreifem im Thread.
es geht nicht um die werte die erhalten bleiben sollen sondern um die Instanz der View. Und die braucht er in Thread .
Beiträge automatisch zusammengeführt:

was du über das viewmodel sagst ist richtig. aber er will aus dem laufenden Thread auf den ui eine Ausgabe machen. wo es in der zwichenzeit eine neue Instanz der view gibt. was der Thread nicht mit bekommt.

Auch die nicht static textview variable hat eine neue Instanz neuen Platz im Speicher bekommen. Bein neu erstellen der Kasse beim Handy drehen.
 
Zuletzt bearbeitet:
Eine Möglichkeit könnte es sein ohne static auszukommen.
Die Instanz Variablen textview im Model zu halten. Auch den Thread selber im Model zu halten. Dem Thread die Instanz des Viewmodel im Konstruktor mitzugeben. Damit der Thread auch auf die neue textview Instanz über getter zugreifen kann.
Natürlich muss die onCreate die View mit findViewById suchen und mit einen setter dem Viewmodel übergeben.

So könnte es gehen. Values will er nicht im Model speichern.
 
@jogimuc :) verstehe
 

Ähnliche Themen

C
  • CoderboyPB
Antworten
3
Aufrufe
915
swa00
swa00
OnkelLon
Antworten
13
Aufrufe
1.924
OnkelLon
OnkelLon
L
Antworten
15
Aufrufe
890
jogimuc
J
Zurück
Oben Unten