Fehler beim Erweitern eines zweidimensionalen Arrays

  • Antworten:28
Frank Rudolf
  • Forum-Beiträge: 215

27.01.2016, 17:05:44 via Website

Ich möchte ein zweidimensionales Array um einen "Datensatz" erweitern. Dem Array soll also eine neue, weitere Zeile hinzugefügt werden. Jede Zeile besteht aus drei Spalten.

Beim Hinzufügen greife ich von einem DialogFragment aus auf das Array zu, das sich in der ActivityMain befindet. Hier die UpdateProzedur, die das Array aktualisieren möchte:

public void UpdateArray2DInfosGesamt(String iD, String info,String father){
        //das 2dimensionale Array arr2DInfosGesamt wird mit dem neuen Datensatz aktualisiert
        int arraySize;
        String teil;

        MainActivity mainActivity = new MainActivity();
        arraySize = mainActivity.arr2DInfosGesamt.length;

        mainActivity.arr2DInfosGesamt[arraySize][0] = iD;
        mainActivity.arr2DInfosGesamt[arraySize][1] = info;
        mainActivity.arr2DInfosGesamt[arraySize][2] = father;



    }

Folgende Fehlermeldung erscheint:
image

Hängt der Fehler vielleicht mit der folgenden Deklaration in der MainActivity zusammen?:

static String [][] arr2DInfosGesamt;

Antworten
Gelöschter Account
  • Forum-Beiträge: 2.492

27.01.2016, 18:41:53 via App

Mit .length erhälst du die Länge. Ein Array zählt aber von 0 bis Länge-1. Also hast du ein Array mit 5 Elementen ergibt .length = 5. Das letzte Element ist aber an Position 4. (das erste an 0).
Deshalb die indexoutofbounds.

Falls du dein Array wirklich erweitern willst. Also von Länge 5 auf 6 zum Beispiel müsstest du es neu initialisieren und alles rüber kopieren. Dafür wäre dann eine ArrayList besser gedacht. Die kann während der Laufzeit dynamisch erweitert werden.

— geändert am 27.01.2016, 18:44:51

Frank Rudolf

Antworten
Frank Rudolf
  • Forum-Beiträge: 215

27.01.2016, 19:08:07 via Website

Das nullbasierte Array habe ich schon berücksichtigt.

Wenn length zB 32 liefert, sind das die Einträge von 0 bis 31. Folglich haut es hin, wenn das nächste freie Element mit length (also 32) angesprochen wird.

Es wird - wie Du wohl schon richtig andeutest - damit zu tun haben, dass man das Array nicht erweitern kann, sondern neu initialisieren muss. Programmtechnisch würde das einen Zeitverlust bedeuten (bei zB 1500 Datensätzen).

Vielleicht kann ich ja doch noch auf eine Arraylist zugreifen. Ich glaube, dass ich diesmal keine Arraylist verwendet habe, weil ich nicht heraus bekam, wie man eine zweidimensionale Arraylist erstellen kann. Weißt Du, ob das geht?

Dir jedenfalls Danke!

— geändert am 27.01.2016, 19:24:23

Antworten
Frank Rudolf
  • Forum-Beiträge: 215

27.01.2016, 19:16:29 via Website

Mir ist doch noch eine Idee gekommen.

Was wäre denn, wenn ich das Array von vornherein so groß erstelle, dass ich noch Platz zum Einfügen hätte?

Im Augenblick wird es ja so deklariert:

static String [][] arr2DInfosGesamt;

Ich könnte ja hingehen, und stattdessen folgendes schreiben:

static String [3000][3] arr2DInfosGesamt;

Kann ich ja mal ausprobieren. Sieht aber irgendwie nach einer Notlösung aus :-).

Antworten
Klaus T.
  • Forum-Beiträge: 8.183

27.01.2016, 20:14:18 via Website

Mach dir statt des "Satz" für das mehrdimensionale Array eine kleine (interne) Klasse und nimm dann die ArrayList oder was anderes passendes.
Das ist flexibler....und mehr objectorientiert.

if all else fails, read the instructions.

Frank Rudolf

Antworten
Fabian Simon
  • Forum-Beiträge: 359

28.01.2016, 09:39:02 via Website

Und hier noch ein Besiel...

public class Info{
        private int id ;
        private String info;
        private Info father;

    public Info(){
        super();
    }

    public Info(int id, String info, Info father) {
        this();
        setFather(father);
        setId(id);
        setInfo(info);
    }
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getInfo() {
        return info;
    }
    public void setInfo(String info) {
        this.info = info;
    }
    public Info getFather() {
        return father;
    }
    public void setFather(Info father) {
        this.father = father;
    }


}

Und nutzt es dann mit:

ArrayList<Info> infolist = new ArrayList<Info>();
infolist.add(new Info(123,"",null));

Frank Rudolf

Antworten
Henrik Martens
  • Forum-Beiträge: 607

28.01.2016, 09:48:48 via Website

Genau so wie Fabian würde ich es auch machen. So bist du sowohl beim hinzufügen neuer "Datensätze" in die ArrayList, als auch beim ändern von bestehenden Daten sehr flexibel.

Frank Rudolf

Antworten
Frank Rudolf
  • Forum-Beiträge: 215

28.01.2016, 09:57:14 via Website

Mach dir statt des "Satz" für das mehrdimensionale Array eine kleine
(interne) Klasse und nimm dann die ArrayList oder was anderes
passendes. Das ist flexibler....und mehr objectorientiert.

Das klingt gut. Für mich bleibt aber noch immer - aufgrund meines Anfängerstatus in Android(?) - das Problem, mit einer zweidimensionalen Arraylist zu arbeiten.

Kannst Du mich vielleicht auf ein Beispiel verweisen?

Antworten
Henrik Martens
  • Forum-Beiträge: 607

28.01.2016, 10:00:49 via Website

Hallo Frank,

die ArrayList an sich ist weist nur eine Dimension auf, und zwar dein selbst erstelltes Objekt.
Dieses Objekt wiederum verfügt über die drei Variablen ID, info und father.

Das Beispiel oben von Fabian ist schon sehr gut.

Henrik

— geändert am 28.01.2016, 10:00:58

Frank Rudolf

Antworten
Frank Rudolf
  • Forum-Beiträge: 215

28.01.2016, 10:08:14 via Website

Danke Fabian für das ausgeführte Beispiel. Du greifst scheinbar die Idee von Klaus auf. Gefällt mir gut.

Ich hoffe nur, dass ich dann nicht dieselben Aktualisierungsprobleme beim Hinzufügen neuer Elemente habe wie bei einem "normalen" 2D-Array. Aber ich vermute, dass es so gehen dürfte.

Hintergrund:
ich möchte ja gelegentlich eine Datenmenge aus mehreren Tausend Elementen durch das Hinzufügen neuer Datensätze aktualiseren. Und dies soll zudem von einem Fragment aus geschehen (falls notwendig).

Seit gestern beschäftige ich mich mit der Datenübergabe zwischen Fragments und Activities (Callbacks etc.) als Alternativlösung. Vielleicht kann ich darauf sogar verzichten mit so einer eigenen ArrayListKlasse.

Eine Detailfrage noch an Dich. Wofür brauche ich das this im folgenden Code?

public Info(int id, String info, Info father) {
        this();
        setFather(father);
        setId(id);
        setInfo(info);
    }

— geändert am 28.01.2016, 10:09:04

Antworten
Frank Rudolf
  • Forum-Beiträge: 215

28.01.2016, 10:12:05 via Website

Danke auch Dir, Henrik!

Ich habe den Verdacht, dass ich den Weg der eigenen ArraylistKlasse gehen werde.

Mal sehen, welche Probleme dann auftauchen :). Aber lehrreich ist das wohl schon :).

Antworten
Henrik Martens
  • Forum-Beiträge: 607

28.01.2016, 10:19:15 via Website

Gerne, solltest du noch Fragen haben, dann immer her damit. Wir versuchen zu helfen.

Frank Rudolf

Antworten
Gelöschter Account
  • Forum-Beiträge: 2.492

28.01.2016, 10:22:36 via Website

Das this() ruft den Konstruktor

public Info(){
    super();
}

auf. Dieser ruft mit super() den Konstruktor der Superklasse auf. Falls du deine Info-Klasse also von nichts anderem ableitest ist das this nicht notwendig.

— geändert am 28.01.2016, 10:24:37

Frank Rudolf

Antworten
Frank Rudolf
  • Forum-Beiträge: 215

28.01.2016, 10:35:48 via Website

Mir fehlt im Augenblick noch meine Vorstellungskraft :).

Nehmen wir mal an, dass ich die ArrayList bereits mit vielen Elementen gefüllt habe.
ZB könnte das Hinzufügen des 1000. Elements so aussehen:

infolist.add(new Info("999","Hier steht die eigentliche Info", "4");

Wie greife ich dann bei Bedarf auf den Inhalt dieses 1000. InfoElements zu?

Übrigens:
nicht wundern, dass ich (in Abwandlung des FabianCodes) für das erste und dritte Element Strings nehme! Das ist in der Tat ungewöhnlich. Es liegt daran, dass die Daten aus einer Textdatei kommen. Natürlich könnte ich die noch umwandeln. Aber wer weiß, was für Probleme sich noch daraus entwickeln? Letztendlich muss ich nämlich auch noch eine Art Synchronisierung schaffen (ca. zwei Versionen dieser "Datenbank"; eine läuft derzeit unter Access, die andere soll auf Android laufen).

Nochwas:
Den FabianCode würde ich so modifizieren:

private String id ;
private String info;
private String father;

Das sind also die MemberVariablen der Info-Klasse.
Father ist nur die ID des übergeordneten Info-Elements. Hier herrscht das Prinzip der verketteten Liste.

Beispiel:
3; Europa;0
4;Italien;3
5;Irland;3
7;Dublin;5
23;Rom;4

— geändert am 28.01.2016, 10:47:52

Antworten
Gelöschter Account
  • Forum-Beiträge: 2.492

28.01.2016, 10:40:13 via Website

Info info = infolist.get(999);
String element1 = info.getId();
String element2 = info.getInfo();
String element3 = info.getFather();

Du holst dir also das Element aus der ArrayList und kannst dann die getter-Methoden des Objektes nutzen um die Daten auszulesen.
Falls du nur eins benötigst (das könntest du auch bei allen Elementen so machen, finde ich aber persönlich unschöner) könntest du auch kurz so machen:

String element1 = infolist.get(999).getInfo();

— geändert am 28.01.2016, 10:41:09

Frank Rudolf

Antworten
Henrik Martens
  • Forum-Beiträge: 607

28.01.2016, 10:41:33 via Website

Entweder du entnimmst der Arraylist das Objekt an entsprechender Stelle oder du durchsuchst es mit einer Schleife nach einem Objekt, was eine bestimmte Eigenschaft (ID, Info oder father) aufweist.

Die einzelnen Variablen aus den Objekt entnimmst du dann mit dem ".getID()" oder ".getInfo()" oder ".getFather()".

Frank Rudolf

Antworten
Frank Rudolf
  • Forum-Beiträge: 215

28.01.2016, 10:53:40 via Website

Danke für Eure super Hilfe!

Werde also mit Umbaumaßnahmen beschäftigt sein. Von Ergebnissen oder Problemen dabei werdet ihr schon hören :)

Antworten
Frank Rudolf
  • Forum-Beiträge: 215

28.01.2016, 12:38:05 via Website

Zwischenbericht:

Das Adden mit der ListArrayKlasse funktioniert :).

Als nächstes muss ich mich mit der Aktualisierung des ListViews befassen.

Antworten
Henrik Martens
  • Forum-Beiträge: 607

28.01.2016, 12:40:46 via Website

Das sollte über ein ArrayAdabter wunderbar klappen, musst du mal googlen.

Frank Rudolf

Antworten
Frank Rudolf
  • Forum-Beiträge: 215

28.01.2016, 13:07:55 via Website

Hier ein Beispiel für eine notwendige Anpassung des Codes. Die ArrayList-Klasse heißt nun textFile.

 for(int i=0; i< textFile.size(); i++) {
        if(textFile.get(i).getId().equals(father))
            {
                TextView textView = (TextView) findViewById(R.id.textViewKopf);
                textView.setText(textFile.get(i).getInfo());
            }
        }

@Lars:
Es ging nur die "unschöne" Langversion.

textFile.getInfo();

geht zB nicht. Beim Setzen des Punktes hinter textFile und Aufklappen der IntelliSense-Möglichkeiten erscheinen in dieser Kurzfassung auch gar nicht die Methoden der Klasse. Seltsam!

— geändert am 28.01.2016, 13:10:35

Antworten
Frank Rudolf
  • Forum-Beiträge: 215

28.01.2016, 13:13:16 via Website

Das sollte über ein ArrayAdabter wunderbar klappen, musst du mal
googlen.

Ja, sowas habe ich schon. Sieht bei mir bisher so aus:

final SimpleAdapter simpleAdapter = new SimpleAdapter(this, arraylistHashmapForDisplay, R.layout.view_item, new String[]{"id", "info", "father"}, new int[]{R.id.textViewId, R.id.textViewInfo, R.id.textViewFather});

Antworten
Gelöschter Account
  • Forum-Beiträge: 2.492

28.01.2016, 14:14:56 via Website

Frank Rudolf

 for(int i=0; i< textFile.size(); i++) {
        if(textFile.get(i).getId().equals(father))
            {
                TextView textView = (TextView) findViewById(R.id.textViewKopf);
                textView.setText(textFile.get(i).getInfo());
            }
        }

Du solltest dein textView nicht jedes mal neu initialisieren. Mach das am Besten über der Schleife.

@Lars:
Es ging nur die "unschöne" Langversion.

Du verwendest in deinem Beispiel doch schon die kurze Version :P
textFile.getInfo()
geht auch nicht, da weiß er ja nicht welches Element gemeint ist.

Frank Rudolf

Antworten
Frank Rudolf
  • Forum-Beiträge: 215

28.01.2016, 15:56:08 via Website

Hallo Lars!

Die Schleife oben ermittelt nur einen einzigen Wert. Daher kann ich das vertreten.

geht auch nicht, da weiß er ja nicht welches Element gemeint ist.

textFile.get(i).getInfo

Über das i in der Schleife bekommt er zB. das 44. Info-Objekt. Über getInfo geift er auf genau einen bestimmten Teil innerhalb des 44. Elements zu, nämlich auf den Member info (und nicht auf die Member id oder father. Oder wir haben uns missverstanden.

— geändert am 28.01.2016, 15:57:56

Antworten
Gelöschter Account
  • Forum-Beiträge: 2.492

28.01.2016, 15:59:38 via Website

Okay dann ist okay. Ich habe mir aber angewöhnt lokale Variablen zu Beginn eines Codeblocks zu deklarieren/initialisieren.

Genau so hatte ich es gemeint :P

Frank Rudolf

Antworten
Henrik Martens
  • Forum-Beiträge: 607

28.01.2016, 16:00:10 via Website

Ja Frank, so sehe ich das auch.

Ich glaub Lars ist etwas verwirrt, weil die Funktion "getInfo()" heißt. Müsste so aber funktionieren.

Deine Variable info wird mit der Funktion getInfo() übergeben.

EDIT: Lars war schneller mit seiner Antwort :D

— geändert am 28.01.2016, 16:00:42

Frank Rudolf

Antworten
Gelöschter Account
  • Forum-Beiträge: 2.492

28.01.2016, 16:02:05 via Website

Ich war zu keinem Augenblick verwirrt, haben wohl nur aneinander vorbei geredet :D

— geändert am 28.01.2016, 16:02:25

Frank Rudolf

Antworten
Frank Rudolf
  • Forum-Beiträge: 215

28.01.2016, 16:08:01 via Website

Ich habe mir aber angewöhnt lokale Variablen zu Beginn eines
Codeblocks zu deklarieren/initialisieren.

Hier schwanke ich noch. Das kann vielleicht der Übersichtlichkeit dienen. Aber ist es auch schneller?

Einen Sonderfall stellt es noch dar, wenn ich eine Variable gleich zu Beginn mit einem Wert besetze und sei es auch nur null.

Mit der Klein- und Großschreibung bin ich auch noch nicht am Ende meiner Überlegungen. Im Zweifel hält man sich vielleicht am besten an die Konventionen, die allerdings auch in Sonderfällen etwas schwanken.

— geändert am 28.01.2016, 16:10:17

Antworten
Henrik Martens
  • Forum-Beiträge: 607

28.01.2016, 16:11:40 via Website

Bei der Formatierung des Codes und auch bei der Namensgebung von den Funktionen etc. versuche ich mich immer an die allgemeingültigen "Standarts" zu halten.

Einfach auch den Grund, dass ja auch mal andere den Code lesen müssen eventuell.

Wenn man das strikt durchzieht, gewöhnt man sich da auch ganz schnell dran.

Frank Rudolf

Antworten
Gelöschter Account
  • Forum-Beiträge: 2.492

28.01.2016, 16:12:33 via Website

Schneller ist es denke ich nicht, außer der Codeblock (z.B. die Schleife) wird doch mehrmals durchlaufen.

Falls du alleine programmierst kann man es ja machen wie es einem am besten gefällt. So Standard-Konventionen, wie Methoden/Variablen: klein, Klassen: erster Buchstabe groß, Klassenvariablen: komplett groß,... sollte man sich aber meiner Meinung nach schon dran halten.

— geändert am 28.01.2016, 16:13:32

Frank Rudolf

Antworten