ListView mit eigenem Layout zeigt im Querformat Items doppelt an

J

JoEntwickler

Fortgeschrittenes Mitglied
5
Hallo,

ich habe ein Problem mit der Listview.

Ich habe für die Items ein eigenes Layout und einen eigenen ArrayAdapter. Das funktioniert auch sehr gut und wird super angezeigt. Nur wenn ich dann das Handy in den Querformat nehme lädt es ein paar Items doppelt und ein paar garnicht. Es sieht auch jedes mal ein bisschen anders aus.

Hatte jemand auch schon dieses Problem?

Liebe Grüße
 
Idee: Du handlest den configuration change nicht korrekt. Verwendest du Fragments und machst FragmentTransaction.add statt replace?
Dann wird beim drehen des Schirms das Fragment NOCHMAL drauf gehauen, das alte bleibt stehen.

Andere Idee: Deine Datenstruktur, in der deine Items sind überlebt den Change und du machst quasi ein zweites mal add auf einer Liste oder so.
 
Also wir haben eine ArrayAdapterklasse die von ArrayAdapter<String> erbt. Da werden dann die Daten übergeben.
Die Klasse wird dann in der onCreate Methode erstellt und der ListView zugewiesen. Ich denke mal, dass beim Drehen die onCreate Methode dann nochmal ausgeführt wird, aber wenn ich bei der Listview nochmal setAdapter mache müsste der ja die alten Daten überschrieben.
Das komische ist, dass es nur im queren so verbuggt ist. Wenn ich es dann wieder hochkant halte dann wird es wieder angezeigt wie es soll.
 
Hi, manchmal hilft es einfach die Methode

@override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
}
in der Activity zu implementieren. Frage mich nicht warum.

Und sonst muss du die Soße in der Methode verarbeiten.

Doku dazu:
Handle configuration changes | Android Developers
 
Zuletzt bearbeitet:
Guck dir mal die Architecture Components an. Ein ViewModel könnte dein Problem lösen =)

lg. Dagobert
 
Hallo,
also die Methode onConfigurationChanged löst das Problem leider nicht.

Mir ist aufgefallen, dass es nur auftritt wenn man scrollen muss. Beim hoch und runterscrollen ändern sich die Items irgendwie ständig.
@DagobertDokate hättest du villeicht mal ein Beispiel für ein Viewmodell?

Liebe Grüße
 
Hallo
Also einfach nur die Methode onConfigurationChanged“ zu Implementieren reicht sicher nicht.
Da musst du auch die Orientation abfragen und je nach dem darauf regieren.
Eine Callback Methode überschreiben und nur die super Klasse aufrufen sonnst nichts, ist das gleiche als wenn du sie nicht überschreibst. Bringt dir gar nicht. Da musste auch in der Methode was machen wenn das einen sinn haben soll.



Arber viel mehr würde mich mal dein Layout interessieren was du für die Liste benutzt.
Ist es eine Custom Liste mit eigenen Layout und auch ein Layout für die Listen- Einträge ?
Zeige auch mal deinen Adapter .
Ist dein Layout auch richtig in Gedehter Lage sichtbar? Wird auch alles angezeigt?
Haste auch mal dein Layout im Querformat geprüft ob es da auch richtig angezeigt wird?
Notfals ein eigenes Layout für Querformat erstellen.


Ohne Code kommen wir hier nicht weiter.

Ja beim drehen des Handys wird die Activity beendet und wieder neu gestartet dabei wird auch die onCreate , onResume durchlaufen.
aber wenn ich bei der Listview nochmal setAdapter mache müsste der ja die alten Daten überschrieben
.
Ja das müsste und wird er auch aber wo Erstellst und Lädst du deine ArrayListe mit den Daten? Die solltest du vorher immer Löschen . Zumindest wenn sie Global erstellt ist. Mit Lokalen Variablen müsste es gehen.


ArrayList<String> list = new ArrayList<String>();
for (int i = 0; i < values.length; ++i) {
list.add(values);
}


DeinArrayAdapter adapter = new DeinArrayAdapter(this,
android.R.layout.simple_list_item_1, list);
listview.setAdapter(adapter




Wenn du die Cursor Pos in der Liste beim drehen behalten willst, musst du die in der onSaveInstanceState Methode selber speichern, und in RestoreInstanceState wieder auslesen und im Adapter setzen.



Guck dir mal die Architecture Components an. Ein ViewModel könnte dein Problem lösen =)
Das kann man alles machen muss man nicht bei mir funktionieren Listen ohne dies auch gedreht.
Das muss auch ohne solchen Sachen gehen. macht es doch nicht noch komplizierter



Nochmal Ohne etwas Quellcode Ist es schwer für uns .
Das dies hier noch keiner angefordert hat wundert mich.



Ps. der Tipp von @deek
war eigentlich super dem wurde leider nicht nachgegangen.
ist eigentlich das was ich auch sage.
Andere Idee: Deine Datenstruktur, in der deine Items sind überlebt den Change und du machst quasi ein zweites mal add auf einer Liste oder so.]
 
Zuletzt bearbeitet:
jogimuc schrieb:
Hallo
Also einfach nur die Methode onConfigurationChanged“ zu Implementieren reicht sicher nicht.
Da musst du auch die Orientation abfragen und je nach dem darauf regieren.
Eine Callback Methode überschreiben und nur die super Klasse aufrufen sonnst nichts, ist das gleiche als wenn du sie nicht überschreibst. Bringt dir gar nicht. Da musste auch in der Methode was machen wenn das einen sinn haben soll.

Manchmal habe ich das Gefühl, dass hier die Antworten nicht wirklich gelesen werden.

Sehr interessant finde ich deine Ausführung zu dem Thema super(). Frage mich manchmal, warum es die Methode überhaupt gibt. Und was passiert, wenn in onConfigurationChanged kein super steht. :)
Ich habe nur erzählt, das es manchmal hilft, denke es liegt an der Reihenfolge der Aufrufe. Und sonst muss man den steinigen Weg gehen.

Beim Wechsel der ‎Orientierung wird das Layout neu gezeichnet. Das heißt ihr müsst den alten Status speichern (beim Adapter gibt es eine Methode, welche die aktuell angezeigte Items zurück gibt. Der beste Ort dafür ist onConfigurationChanged.

Dann muss man die richtigen Stelle des Livecycle des Activity bzw Fragment abpassen, und zeichnet die Liste neu. Ich würde am liebsten eine Methode nennen, aber das hängt ein bisschen davon ab, wie du dein ListView erzeugst.

Kann man alles im Link Handle configuration changes  |  Android Developers nachlesen.

Ich mache das mit 5 in einander geschachtelten Fragment, bei denen beim Wechsel das Layout komplett ausgetauscht wird.
 
>Sehr interessant finde ich deine Ausführung zu dem Thema super(). Frage mich manchmal, warum es die Methode überhaupt gibt. Und was passiert, wenn in onConfigurationChanged kein super steht. :)

Für was die es gibt hast du doch schon selber beantwortet.
Die Methode wird auch wenn sie nicht Überschrieben wird in der Superklasse aufgerufen.
Wenn du die Methode Überschreibst wird dann deine aufgerufen und nicht mehr die der Superklasse. Mit dem aufruf der Methode mit dem vorgestellten super wird die ursprüngliche Methode der Superklasse aufgerufen. Das ist das Prinzip von Verketteten Methoden nach OOP.
Wenn man das super nicht aufruft was da passiert kann man im Vorfeld nicht so genau sagen, es wird halt nur der Code ausgeführt der in deiner Methode steht. Wenn in der Supermethode nichts wichtiges gemacht wird, geht es manchmal auch ohne ist aber keine Garantie und im normal fall handelt man sich da nur ärger ein. Wird ja auch so von Google empfohlen.
Ansonsten bleibt nur ein blick in den Quellcode, um zu wissen was in der SuperMethodde gemacht wird.

>Ich habe nur erzählt, das es manchmal hilft, denke es liegt an der Reihenfolge der Aufrufe. Und sonst muss man den steinigen Weg gehen.

Richtig das hast du. Aber er hat es so gelesen das es reicht nur deinen Code einzufügen, und er hat sich gewundert das es nichts gebracht hat. Dies wollte ich ihm noch mal verdeutlichen. Das nur ein einfaches Implemtieren der Methode nichts bringen kann.
Da sind wir uns ja einig.

>Manchmal habe ich das Gefühl, dass hier die Antworten nicht wirklich gelesen werden.

Ja das Denke ich manchmal auch und es wird versucht es immer komplizierter zu machen.

Sein Problem wird einerseits bei den Layouts liegen.
Sowie beim laden der Liste oder besser ein löschen der Liste vor dem neu laden. Auch könnte sein selbst erstellten Adapter nicht sauber programmiert sein. Mit Fragmenten wird es wohl nichts zu tunen haben, da er scheinbar nicht damit arbeitet. Sonst währe er darauf ein gegangen.
Zum speichern des Zustandes der Liste gibt es verschiedene Möglichkeiten das war aber eigentlich gar nicht das Thema.


Aber ohne Code können wir nur raten..
 
Zuletzt bearbeitet:
Sorry das ich kein Code hingeschrieben hab.

Einmal mein Layout:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".Einstellungen"
android:background="@color/background">

<include layout="@layout/toolbar"></include>

<ListView
android:id="@+id/lvSettingOptions"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@+id/toolbar"/>

</RelativeLayout>

Hiermit fülle ich dann die Arraylist:
listView = findViewById(R.id.lvSettingOptions);
CashflowSettingsListAdapter settingsListAdapter = new CashflowSettingsListAdapter(this, getResources().getStringArray(R.array.settingOptions),
R.array.settingOptionIcons);
listView.setAdapter(settingsListAdapter);


Und hier meine Adapter Klasse:
public class CashflowSettingsListAdapter extends ArrayAdapter<String> {

private List<String> settingOptions;
private Activity context;
private TypedArray images;
private int iconArrayLength;

public CashflowSettingsListAdapter(Activity context, String [] settingOptions, int iconArrayId) {
super(context, R.layout.listview_item_settings);
this.context = context;
this.settingOptions = Arrays.asList(settingOptions);
images = context.getResources().obtainTypedArray(iconArrayId);
this.iconArrayLength = context.getResources().getIntArray(iconArrayId).length;
}

@override
public int getCount() {
return settingOptions.size();
}

@override
public long getItemId(int i) {
return 0;
}

@override
public View getView(final int i, View view, ViewGroup viewGroup) {
View row = view;
if(row == null) {
LayoutInflater inflater = context.getLayoutInflater();
row = inflater.inflate(R.layout.listview_item_settings, viewGroup, false);
TextView tvSettingsOption = row.findViewById(R.id.tvSettingsOptionText);
tvSettingsOption.setText(settingOptions.get(i));
ImageView ibSettingsOptionIcon = row.findViewById(R.id.ibSettingsOptionIcon);
if (images != null && i < iconArrayLength) {
ibSettingsOptionIcon.setImageResource(images.getResourceId(i, -1));
}
}
return row;
}

}


Liebe Grüße
 
Hallo

Also du musst in deinem Adapter auch die Liste dem Konstruktorder der Superklasse mit übergeben.

Ich würde die Liste nicht im Adapter erstellen sondern ihn gleich übergeben ist auch so üblich. Also erzeuge die Liste außerhalb zB in der onCreate und über gib die dem Adapter.
Die Methoden getCount(),getItemId() brauchst du dann auch nicht überschreiben.
Denn er hat ja die liste selber.


Code:
//  zB. in der onCreate oder in einem Listner
//  ArrayList<String> list = new ArrayList<>();
//  listView = findViewById(R.id.lvSettingOptions);
//  list = Arrays.asList(getResources().getStringArray(R.array.settingOptions)));
//  CashflowSettingsListAdapter settingsListAdapter = new CashflowSettingsListAdapter(this,list,R.array.settingOptionIcons);
//  listView.setAdapter(settingsListAdapter);

public class CashflowSettingsListAdapter extends ArrayAdapter<String> {

private ArrayList<String> settingOptions = new ArrayList<>();
private Activity context;
private TypedArray images;
private int iconArrayLength;

public CashflowSettingsListAdapter(Activity context, ArrayList<String> list, int iconArrayId) {
   super(context, R.layout.listview_item_settings,list);
   this.context = context;
   this.settingOptions = list;
   images = context.getResources().obtainTypedArray(iconArrayId);
   this.iconArrayLength = context.getResources().getIntArray(iconArrayId).length;
}

@override
public View getView(final int i, View view, ViewGroup viewGroup) {
   View row = view;
   if(row == null) {
      LayoutInflater inflater = context.getLayoutInflater();
      row = inflater.inflate(R.layout.listview_item_settings, viewGroup, false);
      TextView tvSettingsOption = row.findViewById(R.id.tvSettingsOptionText);
      tvSettingsOption.setText(settingOptions.get(i));
      ImageView ibSettingsOptionIcon = row.findViewById(R.id.ibSettingsOptionIcon);
      if (images != null && i < iconArrayLength) {
         ibSettingsOptionIcon.setImageResource(images.getResourceId(i, -1));
      }
   }
  return row;
}

}


Zu deinem Layout
zu dieser Zeile (android:layout_below="@+id/toolbar")
Ich hoffe das du nicht in dem Includeten Layout auch die Id mit + erstellst.
Eigentlich hatte mich auch dein ListItem Layout interessiert vor allen ob das auch im Querformat richtig angezeigt wird.
 
Zuletzt bearbeitet:
Es wären vielleicht noch Screenshots interessant wie das ganze aussieht und der komplette Code deiner Activity/Fragment. Und bitte in code tags, damit es besser lesen kann.
 
  • Danke
Reaktionen: swa00
So ich noch mal.
Deine Images würde ich etweder in einer zweiten Liste übergeben, oder du erstellst dir für deine Liste einen Datendype mittels einer Klasse.
Dann bist du auch fexibler als mit den Resoursen.
 
Hier meine Activity. Also es sollen Einstellungen sein:
Code:
public class Einstellungen extends AppCompatActivity {

    private Toolbar toolbar;
    private ActionBar actionbar;
    private TextView tvToolbarTitle;
    private ListView listView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_einstellungen);
        toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        actionbar = getSupportActionBar();
        actionbar.setDisplayHomeAsUpEnabled(true);
        actionbar.setTitle("");
        tvToolbarTitle = findViewById(R.id.tvToolbarTitle);
        tvToolbarTitle.setText(R.string.settings);
        listView = findViewById(R.id.lvSettingOptions);
        CashflowSettingsListAdapter settingsListAdapter = new CashflowSettingsListAdapter(this, getResources().getStringArray(R.array.settingOptions),
                R.array.settingOptionIcons);
        listView.setAdapter(settingsListAdapter);
        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
                switch (i) {
                    case 0:
                        startActivity(new Intent(Einstellungen.this, EinstellungenWaehrungen.class));
                        break;
                    case 1:
                        startActivity(new Intent(Einstellungen.this, EinstellungenSprachen.class));
                        break;
                    case 2:
                        startActivity(new Intent(Einstellungen.this, EinstellungenHilfen.class));
                        break;
                    case 3:
                        startActivity(new Intent(Einstellungen.this, EinstellungenErinnerungen.class));
                        break;
                    case 4:
                        Intent intentOpenInfoWidgetSettings = new Intent(Einstellungen.this, EinstellungenCashflowInfoWidget.class);
                        intentOpenInfoWidgetSettings.putExtra(Keys.WIDGET_TYPE, "infoWidget");
                        startActivityForResult(intentOpenInfoWidgetSettings, 0);
                        break;
                    case 5:
                        TotalExams.openPlayStore(Einstellungen.this);
                        break;
                    case 6:
                        final LayoutInflater dialoginflater2 = getLayoutInflater();
                        final View dialogview2 = dialoginflater2.inflate(R.layout.dialog_about_us, null);
                        final AlertDialog.Builder dialogbuilder2;
                        dialogbuilder2 = new AlertDialog.Builder(Einstellungen.this);
                        dialogbuilder2.setView(dialogview2);
                        dialogbuilder2.create().show();
                        break;
                    case 7:
                        final LayoutInflater dialoginflater3 = getLayoutInflater();
                        final View dialogview3 = dialoginflater3.inflate(R.layout.dialog_data_protection, null);
                        final AlertDialog.Builder dialogbuilder3;
                        dialogbuilder3 = new AlertDialog.Builder(Einstellungen.this);
                        dialogbuilder3.setView(dialogview3);
                        dialogbuilder3.create().show();
                        break;
                    case  8:
                        final LayoutInflater dialoginflater4 = getLayoutInflater();
                        final View dialogview4 = dialoginflater4.inflate(R.layout.dialog_imprint, null);
                        final AlertDialog.Builder dialogbuilder4;
                        dialogbuilder4 = new AlertDialog.Builder(Einstellungen.this);
                        dialogbuilder4.setView(dialogview4);
                        dialogbuilder4.create().show();
                        break;
                }
            }
        });
        ActivityRegistry.register(this);
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            // Respond to the action bar's Up/Home button
            case android.R.id.home:
                onBackPressed();
                return true;
        }
        return super.onOptionsItemSelected(item);
    }

}
[doublepost=1533406711,1533405887][/doublepost]Sorry hat nicht richtig hochgeladen.
 

Anhänge

  • Activity.png
    Activity.png
    9,8 KB · Aufrufe: 198
Hi schön das du den Code noch gepostet hast.
Mich würde aber interessieren ob das was ich dir gesagt habe geholfen hat.
Wie ich aus deinem Code sehe hast du die Änderungen noch nicht gemacht.
 
Ich dachte eigentlich ein Screenshot vom Problem, also da wo die Sachen doppelt zu sehen sind.

Beim nochmaligen drüber schauen könnte ich mir vorstellen wo dein Problem liegt:
Code:
@override
public View getView(final int i, View view, ViewGroup viewGroup) {
    View row = view;
    if(row == null) {
        LayoutInflater inflater = context.getLayoutInflater();
        row = inflater.inflate(R.layout.listview_item_settings, viewGroup, false);
        TextView tvSettingsOption = row.findViewById(R.id.tvSettingsOptionText);
        tvSettingsOption.setText(settingOptions.get(i));
        ImageView ibSettingsOptionIcon = row.findViewById(R.id.ibSettingsOptionIcon);
        if (images != null && i < iconArrayLength) {
            ibSettingsOptionIcon.setImageResource(images.getResourceId(i, -1));
        }
    }
    return row;
}
Hier änderst du den Inhalt deiner View nur, wenn du sie neu inflatest.
Das ist aber falsch, eine Listview recyclet die einzelnen Views. D.h. wenn sie aus dem Bild scrollen werden sie für ein neues Item wiederverwendet. Die alte View bekommst du hier dann als view rein. Setzt du hier jetzt keine neuen Werte, dann hat die View noch den alten Content und die Liste zeigt items doppelt an.
Du musst also entweder jedesmal eine neue View infalten (schlechte Performance) oder im Fall dass die view != null ist einfach den Inhalt korrekt setzen ohne vorher zu inflaten.

In der neuen RecyclerView (die man als Anfänger eigentlich vor ListView präferieren sollte) ist das etwas explizierter dargestellt durch zwei Schritte.
 
Ok ich hab jetzt mal das von deek gemacht. Also die View jedesmal neu erstellen lassen.
Also von der Performance merke ich da keine wirklichen Nachteile. Hab das an meinem 150€ Huawei getestet.
Alle ListView Items sind da wo sie sein sollen.

Also mein Problem wäre damit gelöst.
Klar ist das nicht die schönste Lösung, aber sie
 
I's a weird situation you know!
Make sure you have implemented your adapter properly, especially the getView() method if you are extending Base Adapter.
Follow this link to get more information on base adapter Adapter  |  Android Developers
 
Hello Ashely,

welcome in our community and thank you for your answer.
Pls note : We are a native speaken german community and pls write in german .

Thx a lot
 

Ähnliche Themen

A
Antworten
10
Aufrufe
1.021
swa00
swa00
FabianDev
Antworten
5
Aufrufe
560
swa00
swa00
R
  • RudolfHagen
Antworten
1
Aufrufe
652
koje71
koje71
Zurück
Oben Unten