Firebase lädt langsam

  • Antworten:36
  • OffenNicht stickyBentwortet
  • Forum-Beiträge: 169

12.05.2020, 21:33:48 via Website

Hallo zusammen

Hier bereits schon mein nächstes Problem mit FIrebase

Ich habe meine Datenbank so weit das ich sie jetzt sinnvoll auslesen kann, viele daten sind es noch nicht, und trotzdem ist da eine spührbare ladezeit von mindesten einer halben sekunde, bei drei einträgen.

Hier der Json der abgerufen wird:

"gruppe" : {
      "-M739MIOjwbiDqCD8L4R" : {
        "land" : "Angola",
        "mail" : "madad@gmx.ch",
        "name" : "madad",
        "passwort" : "c4ca4238a0b923820dcc509a6f75849b"
      },
      "-M73WWzMwSfT4JhpNkQq" : {
        "land" : "Pakistan",
        "mail" : "Noerio@Noerio.ch",
        "name" : "Noerio",
        "passwort" : "c4ca4238a0b923820dcc509a6f75849b"
      },
      "-M73Y-QC5idHA-X8ghYs" : {
        "land" : "Anguilla",
        "mail" : "wetlino@wetlino.ch",
        "name" : "wetlino",
        "passwort" : "c81e728d9d4c2f636f067f89cc14862c"
      }

Das sindja nur drei....

der AbrufCode sieht inetwa so aus

DatabaseReference dbf = fb.GET_mannschaften(id_user);
    dbf.addValueEventListener(new ValueEventListener() {
        @Override
        public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                if(dataSnapshot.exists()){
                    LinearLayout ll = v.findViewById(R.id.list);
                    ll.removeAllViews();
                    for(DataSnapshot ds:dataSnapshot.getChildren()) {
                        final String id_benutzer = ds.getKey();
                        final String team_name= ds.child(FirebaseTable.mannschaften.name).getValue(String.class);
                        TextView tv = (TextView) LayoutInflater.from(ctx).inflate(R.layout.standart_textview, null);
                        tv.setText(team_name);
                        ll.addView(tv);

///usw
                        }
                    }
            }

        @Override
        public void onCancelled(@NonNull DatabaseError databaseError) {

        }
    });

Ich habe bemerkt, wenn ich z.b. die eine person aufrufe, und die Layouts bereits gesetzt sind ( Bearbeitungsformular) , geht es sauschnell. Aber wenn ich eine Liste mit TextViews füllen will geht es viel länger, doch wie soll man das sonst machen? Oder bin ich wieder mal total daneben mit dem was ich will?

Vielen dank schonmal im vorraus!

— geändert am 12.05.2020, 21:34:15

Diskutiere mit!
Beste Antwort
  • Forum-Beiträge: 11.012

19.05.2020, 18:56:32 via Website

Wenn deine joins im Client zu langsam sind, könntest du die auch als Firebase WebFunktions nach Firebase auslagern. sowas wie "Views" in relationalen Datenbanken wird es da siche auch geben. Dann musst du nur die View abfragen und die behandelt deine joins serverseitig

LG Pascal //It's not a bug, it's a feature. :) ;)

Hilfreich?
Diskutiere mit!
  • Forum-Beiträge: 1.218

13.05.2020, 07:09:41 via Website

Hallo so wie du hier versuchst eine Liste zu machen ist auch nicht sinnvoll.
Immer wider eine view selber in ein layout einzufügen.

Dafür was du willst, gibt es eine Litstview oder neuer ein Recyclerview.
Benutze das mit einem Adapter der dir deine Liste aufbaut nachdem du alle Daten erhalten hast.

Schaue dir litstview an.

— geändert am 13.05.2020, 07:11:39

Hilfreich?
Diskutiere mit!
  • Forum-Beiträge: 169

13.05.2020, 15:31:02 via Website

So wie ich Firebase verstanden habe, löst dieser ValueEventListener doch bei jeder änderung den ganzen Inhalt nochmals neu aus, hängt es mir da nicht die ganze List unten nochmal an? egal ob TextVierw oder eben einnen Array.....

Sobald ich feierabend habe, schau ich mir das RecyclerView an, immer wieder gesehen, danke schonmal!

Hilfreich?
Diskutiere mit!
  • Forum-Beiträge: 1.218

13.05.2020, 17:14:11 via Website

Wenn es Änderungen gab also der listner ausgelöst wurde. Weiß ich jetzt nicht genau ob er dir nur die änderungen in dem datasnapshot gibt oder alles.

Für listen ist eigentlich ein ChildEventListener() besser geeignet. Denn da hast du alle Möglichkeiten. Ubdate, löschen, und neue Datensätze. Als callback Methode. Damit kannst du deine array Liste für den Adapter actualisiren.

https://firebase.google.com/docs/database/android/lists-of-data

Hilfreich?
Diskutiere mit!
  • Forum-Beiträge: 1.218

13.05.2020, 17:21:12 via Website

Wenn dir dein listner immer alle Datensätze schickt. Wiso löscht du da nicht deine Liste die du dem Adapter übergibt.
Du löscht doch auch deine views on dem listner als erstes. Ist doch eigentlich das gleiche Prinzip. Nur das das litstview performanter arbeitet als deine Variante. Denn das listView ist bestimmt eine c Bibliothek die im hinderund benutzt wird und kein Java Code.

Hilfreich?
Diskutiere mit!
  • Forum-Beiträge: 3.501

13.05.2020, 17:30:44 via Website

Ich würde eh mit einem dynamischen ArrayAdapter arbeiten und diesen dann komplett übergeben.

Liebe Grüße - Stefan
[ App - Entwicklung ]

Hilfreich?
Diskutiere mit!
  • Forum-Beiträge: 169

13.05.2020, 17:52:53 via Website

So... so schnell war ich nie zuhause :D....
Ich habe es gleich mit einem ArrayAdapter versucht inkl. chilckListener! macht mich schon zu 90% Glücklich.
Wenn ich etwas hinzufüge addet es schon brav in die liste, wollte gleich auch Change und delete machen, das funktioniert natürlich wieder mal wegen dem Arrayadapter nicht.
Noch nie was von Dynamischen Arrayadapter gehört, ich werde aber mich gleich mal daran machen ,und hoffen das die das peilen.

Aber etwas stört mich ja trotzdem noch. die ladezeiten sind immer noch misserabel, vorallem beim ersten laden, das muss doch zackzackgehen,beim zweiten mal laden ist es wunderbar.... ist es besser die gesamte Datenbank schon zu laden wenn die App gleich startet? einfach mal so im hintergrund?

— geändert am 13.05.2020, 17:53:07

Hilfreich?
Diskutiere mit!
  • Forum-Beiträge: 1.218

13.05.2020, 20:23:29 via Website

Mal eine Frage wo und wann setzt du denn deinen Eventlistner. Hoffe du machst das nicht erst im Button onClicklister.

Hilfreich?
Diskutiere mit!
  • Forum-Beiträge: 169

13.05.2020, 20:29:20 via Website

Also eigentlich gleich im OnCreate in einer neuen Activity.

Was ich bemerkt habe z.b.
wenn ich ein Formular lade und erst dan
mit dem addValueeventlistener nur die
et.setText(ds.child("irgendwo").getValue()String.class)); einfüge ist der Edittext immer gleich mit den Angaben gefüllt, und fühlt sich richtig an.
Wenn ich aber den EditText im Eventlistener erstelle und in die View einfüge, braucht es beim ersten Ladevorgang immer einen Moment, bis es mir anzeigt.
Wenn ich genau weiss was ich laden will geht das ja wunderbar mit dem oberen beispiel, wenn ich aber eine Liste laden will geht es immer einem moment bis die Liste (also auch jetzt mit dem ArrayaListener) geladen ist.....

Hilfreich?
Diskutiere mit!
  • Forum-Beiträge: 1.218

13.05.2020, 20:43:46 via Website

Deine erste Abfrage ist ja eine direkte Abfrage. Ohne listner das ist eigentlich keine Abfrage die eine Realtime ist.
Sondern direkt in dem Moment wo du es aufrufst.
Der listner wir aufgerufen.
Wenn sich Daten ändern.
Oder wenn die Daten das erste Mal benutzt werden sich noch nicht in einem Zeichen Puffer befinden.

Hilfreich?
Diskutiere mit!
  • Forum-Beiträge: 169

13.05.2020, 21:14:40 via Website

Ich glaube... ich verstehe.... :)

Ich habe den Pfad nun einfach mal aufgerugen in der MainActivity mit

FirebaseDatabase dbf = FirebaseDatabase.getInstance();
DatabaseReference get = dbf.getReference("test");

und wenn ich nun die zweite aktivity aufrufe, geht es doppelt so schnell, da ist aber immer noch eine verzögerung.....

wenn ich dann in der MainActivity aber ein einfach

get.addValueEventListener(new ValueEventListener() {
        @Override
        public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
        }
        @Override
        public void onCancelled(@NonNull DatabaseError databaseError) {
        }
    });

aufrufe, und in die zweite Aktivity gehe, ist das ganze bereits geladen.
Macht man das denn so?

Ich meine, bei der zweiten Aktivity lade ich es jetzt mit dem ChildEventListener()
und mit
@Override
public void onChildAdded(@NonNull DataSnapshot dataSnapshot, @Nullable String s) {
map.add(new List_simple_id_name( dataSnapshot.getKey(),dataSnapshot.child("name").getValue(String.class)));
listView.setAdapter(adapter);
}

wird meine Liste gleich geladen, und wenn ich über den Brwoser in der Console einen neuen wert hinzufüge, scheint das ding zu kapieren, das er nur diesen einen eintrag hinzufügt.

mit onChildChanged() und Delete() erkennt er auch welches Feld ich bearbeitet habe ABER, jetzt muss nur noch dieses Mistding den Adapter dazubringen die richtige Position zu finden, zu löschen oder zu editieren. Ich habe bestimmt schon 30 Tabs offen, und schwanke zwischen herusfiden wie dieses Dynamische Arrayadapter funktioniert..... :)

Hilfreich?
Diskutiere mit!
  • Forum-Beiträge: 1.218

13.05.2020, 21:49:37 via Website

Hallo was @swa00 mit dem dynamischen array Adapter genau meint kann ich dir leider auch nicht genau sagen. Für mich ist das auch nur eine array Liste. Ich würde aber beim Speichen in der Liste nicht nur den Wert Speichen sondern auch den key des Datensatzes.
Wenn etwas geupdatet gelöscht wurde bekommst du doch auch den key des Daten Satzes. Kannst den ja jetzt in der arrayliste suchen. Und ändern.

Das ist für mich das Prinzip key wert paar. Was du auch in einer collection Speichen könntest um leichter suchen zu können.

Das würde meiner Meinung einer dynamischen array Liste nahe kommen. Binn mir da arber nicht sicher. Swa00 wir das dir bestimmt noch erklären.

Wie gesagt ist das mein Gedanke mehr nicht.

— geändert am 13.05.2020, 21:54:42

Hilfreich?
Diskutiere mit!
  • Forum-Beiträge: 169

13.05.2020, 21:55:36 via Website

erstma, für heute bin ich durch! Ich mach morgen weiter :D, noch etwas zeit für meine Frau muss auch sein ;)

Genau das mit dem Key bin ich am versuchen irgendwie hinzukriegen, ich habe das richtige beispiel noch nicht gefunden.
Den wert gebe ich ja mit einer zweiten textview die ich aber View.GONE setzte mit. und beim OnItemklickListener auch aufrufen kann, ich will es aber wenn schon gleich richtig machen, das wenn jemand anderes was ändert, das dies auch mit Echtzeit passiert.... Das Kriege ich ( mit eurere Hilfe) bestimmt schon hin. Aufgeben gibts nicht ;)

schönen Aben noch, und vielen Dank für die Mühe!

Hilfreich?
Diskutiere mit!
  • Forum-Beiträge: 169

13.05.2020, 22:12:46 via Website

manchmal muss die Frau warten.... :) ich habs ;)

for(int i =0;i<listView.getCount();i++){
                log.i("go Position",i);
                Object o = listView.getItemAtPosition(i);
                List_simple_id_name item = (List_simple_id_name) o;
                String id_spieler = item.getId();
                log.i("search",id_spieler);
                if(dataSnapshot.getKey().equals(id_spieler)){
                    log.i("found",dataSnapshot.child("name").getValue(String.class));
                    map.remove(i);
                    map.add(i,new List_simple_id_name( dataSnapshot.getKey(),dataSnapshot.child("name").getValue(String.class)));
                    break;
                }
            }
Hilfreich?
Diskutiere mit!
  • Forum-Beiträge: 1.218

16.05.2020, 19:14:32 via Website

Hallo wenn du noch nicht weiter gekommen bist hier ein einfaches Beispiel für eine Liste.
Mit dem FirebaseListAdapter der alle Änderungen der DB sofort anzeigt. Neu, Update, Löschen wird sofort angezeigt.

Wichtig du musst die richtige Lib unter dependencies einfügen.
implementation 'com.firebaseui:firebase-ui:0.5.1'

import android.os.Bundle;
import android.view.View;
import android.widget.ListView;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import com.firebase.ui.database.FirebaseListAdapter;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;

public class FList extends AppCompatActivity {
    ListView mListView;
    DatabaseReference databaseReference;
    FirebaseListAdapter<Person1> firebaseListAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_app_start);
        //addDaten();
        setListView();
    }

    void addDaten() {
        FirebaseDatabase database = FirebaseDatabase.getInstance();
        databaseReference = database.getReference("Person");
        Person1 person = new Person1("hans", "xx");
        databaseReference.push().setValue(person);
        person = new Person1("max");
        databaseReference.push().setValue(person);
        person = new Person1("franz");
        databaseReference.push().setValue(person);
    }

    void setListView() {
        mListView = (ListView) findViewById(R.id.list_view);
        FirebaseDatabase database = FirebaseDatabase.getInstance();
        databaseReference = database.getReference("Person");
        firebaseListAdapter = new FirebaseListAdapter<Person1>(this, Person1.class,
                android.R.layout.simple_expandable_list_item_1, databaseReference) {
            @Override
            protected void populateView(View v, Person1 model, int position) {
                ((TextView) v.findViewById(android.R.id.text1)).setText(model.getName() + "  " + model.getName2());
            }
        };
        mListView.setAdapter(firebaseListAdapter);
    }

    public class Person1 {
        private String name;
        private String name2;

        public Person1() {
        }

        public Person1(String name) {
            this.name = name;
        }

        public Person1(String name, String name2) {
            this.name = name;
            this.name2 = name2;
        }

        public String getName() {
            return name;
        }

        public String getName2() {
            return name2;
        }
    }

}
Hilfreich?
Diskutiere mit!
  • Forum-Beiträge: 169

18.05.2020, 18:43:45 via Website

Also erstmal, Vielen Dank mochmal, Ich habe eine sehr ähnliche lösung , und das funktioniert mittlerweile,

Ich habe etwas gehadert, ich merke langsam , Firebase ist wahrscheinlich doch nicht die aller Weltslösung, das Denormalisieren ist doch sehr, sehr mühsam, so bin ich jetzt beim zusammenführen von Team und Spieler auf drei Datenstrukturen gekommen ( bei den Spieler füge ich die Teams an, bei den Team füge ich die Spieler an, und eine die Teams und Spieler direkt verbinden),
wenn ich da jetzt aber die Namen übertrage, muss ich ja die ganze zeit das "Updabel" oder deletable" halten. was nochmmal 2 Strukturen bedingen, das macht mir langsam doch schon mehr mühe.
Würdest du das auch so machen?

"spieler" : {
  "-M739MIOjwbiDqCD8L4R" : {
    "land" : "Angola",
    "mail" : "meuth@gmx.com",
    "name" : "Michu",
    "passwort" : "c4ca4238a0b923820dcc509a6f75849b",
    >>>>>"spieler_delete" : {
      "-M7Z-fWdZ4ZUTXWFJL8z" : {
        "link" : "TZBAxFGSgZPZBoYZz7F4MVm5MAP2/team_connect/-M7981xTLAi4FskoXkSi/spieler_team_connect/-M739MIOjwbiDqCD8L4R/"
      },
      "-M7Z-fWhebHwK6GTH5Fg" : {
        "link" : "TZBAxFGSgZPZBoYZz7F4MVm5MAP2/mannschaften/-M7981xTLAi4FskoXkSi/alleSpieler/-M739MIOjwbiDqCD8L4R/"
      },
    },
    >>>>>"spieler_update" : {
      "-M7Z-fWVz4U1vxYbvtlt" : {
        "name" : "TZBAxFGSgZPZBoYZz7F4MVm5MAP2/team_connect/-M7981xTLAi4FskoXkSi/spieler_team_connect/-M739MIOjwbiDqCD8L4R/name_spieler"
      },
    },
    >>>>>"teams" : {
      "-M7981xTLAi4FskoXkSi" : {
        "name" : "Tinto Blues"
      }
    }
  }

Also das ziel ist, wenn ich bei den Manschaften bin, dort einen spieler hinzufüge, kommt nicht nur seine ID in das ManschaftsDB, sondern ein eintrag beim user, damit ich bei einer änderung des Namens , oder löschen des Profils, alle einträge mit ge-Updated/ oder gelöscht werden ? Hab ich das so richtig verstanden?
Das ist ja zäh und so richtig mühsam!

— geändert am 18.05.2020, 18:48:11

Hilfreich?
Diskutiere mit!
  • Forum-Beiträge: 1.218

18.05.2020, 19:27:20 via Website

Wieso machst du das nicht so wie man es in einer SQL auch macht.
Du hast das Objekt Spieler (SQL Tabelle Spieler)
Dort hast du alle die es gibt jeder hat eine automatisch vergebe ID.

In der Tabelle Teams brauchst du doch nur die ID der Spieler speichern. Die Daten hast du doch in der anderen Tabelle. Wieso brauchst du im Team den Namen des Spielers?
über die ID bekommst du doch alles aus dem Objekt Spieler. Name Alter….

Setze dir doch eine Ref. auf Spieler und eine Team.
Ob ein Team aktiv ist oder nicht kannst du ja auch gleich mit im Team speichern.

Hilfreich?
Diskutiere mit!
  • Forum-Beiträge: 169

18.05.2020, 20:11:36 via Website

So wie ich es verstanden habe, ist das nicht optimal für die Ladezeit, und ein problem wegen den Rechten (read/write)
so sollen auch eben bestimmte begriffe zusammengelegt werden falls man diese wie in einer Datenbank suchen soll, zb, land und plz seperat nochmal zusätzlich zusammen als eigenes Feld gespeichert werden falls man diese dann mal sucht. ÄTZEND!!! :)

https://firebase.google.com/docs/database/video-series?authuser=0

wie gesagt, mein english ist grottig, ich habe das ganze nur hinausintepretiert ;)
vorallem die Video
- Denormalization is normal with the Realtime Database
- Data consistency with Multi-path updates

bin ich gerade am umsetzen. da bin ich aber wirklich fast am verzweifeln ;)

Hilfreich?
Diskutiere mit!
  • Forum-Beiträge: 11.012

18.05.2020, 22:08:54 via App

Normalerweise immer so wenig wie möglich redundant ablegen.
Schau dir dazu mal die Datenbank Normalenform an.
Das funktioniert i.d.r auch bei Objekt Basiererten DBs und hat nix mit dem Realtime zutun. Rechte müsste auch gehen, das kannst du ja im Worst Case auf Record Ebene runterbrechen

LG Pascal //It's not a bug, it's a feature. :) ;)

Hilfreich?
Diskutiere mit!
  • Forum-Beiträge: 169

19.05.2020, 18:19:32 via Website

hmmmm...... ich werde einige beispiele probieren müssen, da aber leftjoins in der Realtime db nicht funktionieren, bzw ständig neue Threads öffnen muss auf die ich ausserhalb keinen zugriff habe,
und ich bis zu 7 db gleichzeitg aufrufen muss ( ich habe die App ja eigentlich "fertig", aber nur eben mit SQL ) glaube ich, das dies doch nicht sehr ideal ist wenn ich alles normalisiert halte in der Firebase database, schlussendlich soll das ganze sowieso alles vollautomatisch ablaufen, Ich muss aber wirklich noch mehr ein gefühl dafür bekommen wie und was alles möglich ist. Den Childeventlistener habe ich zuerst vollkommen ignoriert.

Vielen Dank für die tollen tipps!!

Hilfreich?
Diskutiere mit!
Empfohlene Artikel bei NextPit