Android'de Veri Listeleri ile Çalışma

Bu belgede, Firebase'deki veri listeleriyle çalışma açıklanmaktadır. Firebase verilerini okuma ve yazmayla ilgili temel bilgileri öğrenmek için Android'de Veri Okuma ve Yazma başlıklı makaleyi inceleyin.

Veritabanı Referansı Alma

Veritabanından veri okumak ve yazmak için bir DatabaseReference örneğine ihtiyacınız vardır:

Kotlin+KTX

private lateinit var database: DatabaseReference
// ...
database = Firebase.database.reference

Java

private DatabaseReference mDatabase;
// ...
mDatabase = FirebaseDatabase.getInstance().getReference();

Liste okuma ve yazma

Veri listesine ekle

Çok kullanıcılı uygulamalarda bir listeye veri eklemek için push() yöntemini kullanın. push() yöntemi, belirtilen Firebase referansına her yeni alt öğe eklendiğinde benzersiz bir anahtar oluşturur. Listedeki her yeni öğe için otomatik olarak oluşturulan bu anahtarları kullanarak bazı istemciler, yazma çakışmaları olmadan aynı anda aynı konuma alt öğeler ekleyebilir. push() tarafından oluşturulan benzersiz anahtar bir zaman damgasına dayanır. Bu nedenle liste öğeleri otomatik olarak kronolojik olarak sıralanır.

Alt yayıncının otomatik olarak oluşturulan anahtarın değerini öğrenmek veya alt öğe için verileri ayarlamak üzere push() yöntemi tarafından döndürülen yeni verilere referansı kullanabilirsiniz. push() referansında getKey() çağrısı yapıldığında otomatik oluşturulan anahtarın değeri döndürülür.

Veri yapınızı düzeltmeyi basitleştirmek için otomatik olarak oluşturulan bu anahtarları kullanabilirsiniz. Daha fazla bilgi için veri yayma örneğine bakın.

Çocuk etkinliklerini dinle

Listelerle çalışırken uygulamanız, tek nesneler için kullanılan değer etkinlikleri yerine alt etkinlikleri dinlemelidir.

Alt etkinlikler, push() yöntemiyle eklenen yeni bir alt öğe veya updateChildren() yöntemiyle güncellenen bir alt öğe gibi bir işlemdeki düğümün alt öğelerine yapılan belirli işlemlere yanıt olarak tetiklenir. Bunların her biri, veritabanındaki belirli bir düğümde yapılan değişiklikleri dinlemek için faydalı olabilir.

DatabaseReference uygulamasında alt etkinlikleri dinlemek için bir ChildEventListener ekleyin:

Dinleyici Etkinlik geri çağırması Tipik kullanım
ChildEventListener onChildAdded() Öğe listelerini alın veya öğe listesine yapılan eklemeleri dinleyin. Bu geri çağırma, mevcut her alt öğe için bir kez ve belirtilen yola her yeni alt öğe eklendiğinde tekrar tetiklenir. İşleyiciye iletilen DataSnapshot, yeni alt öğenin verilerini içerir.
onChildChanged() Listedeki öğelerde yapılan değişiklikleri bekleyin. Bu etkinlik, alt düğümün alt öğelerinde yapılan tüm değişiklikler dahil olmak üzere bir alt düğümde her değişiklik yapıldığında tetiklenir. Etkinlik işleyiciye iletilen DataSnapshot, alt öğeye ait güncellenmiş verileri içerir.
onChildRemoved() Bir listeden kaldırılan öğeleri bekleyin. Etkinlik geri çağırmasına iletilen DataSnapshot, kaldırılan alt öğenin verilerini içerir.
onChildMoved() Sıralı listedeki öğelerin sırasındaki değişiklikleri bekleyin. Bu etkinlik, onChildChanged() geri çağırması, alt öğenin yeniden sıralanmasına neden olan bir güncelleme tarafından tetiklendiğinde tetiklenir. orderByChild veya orderByValue ile sıralanmış verilerle kullanılır.

Örneğin, bir sosyal blog uygulaması bir yayının yorumlarındaki etkinliği izlemek için aşağıda gösterildiği gibi bu yöntemleri birlikte kullanabilir:

Kotlin+KTX

val childEventListener = object : ChildEventListener {
    override fun onChildAdded(dataSnapshot: DataSnapshot, previousChildName: String?) {
        Log.d(TAG, "onChildAdded:" + dataSnapshot.key!!)

        // A new comment has been added, add it to the displayed list
        val comment = dataSnapshot.getValue<Comment>()

        // ...
    }

    override fun onChildChanged(dataSnapshot: DataSnapshot, previousChildName: String?) {
        Log.d(TAG, "onChildChanged: ${dataSnapshot.key}")

        // A comment has changed, use the key to determine if we are displaying this
        // comment and if so displayed the changed comment.
        val newComment = dataSnapshot.getValue<Comment>()
        val commentKey = dataSnapshot.key

        // ...
    }

    override fun onChildRemoved(dataSnapshot: DataSnapshot) {
        Log.d(TAG, "onChildRemoved:" + dataSnapshot.key!!)

        // A comment has changed, use the key to determine if we are displaying this
        // comment and if so remove it.
        val commentKey = dataSnapshot.key

        // ...
    }

    override fun onChildMoved(dataSnapshot: DataSnapshot, previousChildName: String?) {
        Log.d(TAG, "onChildMoved:" + dataSnapshot.key!!)

        // A comment has changed position, use the key to determine if we are
        // displaying this comment and if so move it.
        val movedComment = dataSnapshot.getValue<Comment>()
        val commentKey = dataSnapshot.key

        // ...
    }

    override fun onCancelled(databaseError: DatabaseError) {
        Log.w(TAG, "postComments:onCancelled", databaseError.toException())
        Toast.makeText(
            context,
            "Failed to load comments.",
            Toast.LENGTH_SHORT,
        ).show()
    }
}
databaseReference.addChildEventListener(childEventListener)

Java

ChildEventListener childEventListener = new ChildEventListener() {
    @Override
    public void onChildAdded(DataSnapshot dataSnapshot, String previousChildName) {
        Log.d(TAG, "onChildAdded:" + dataSnapshot.getKey());

        // A new comment has been added, add it to the displayed list
        Comment comment = dataSnapshot.getValue(Comment.class);

        // ...
    }

    @Override
    public void onChildChanged(DataSnapshot dataSnapshot, String previousChildName) {
        Log.d(TAG, "onChildChanged:" + dataSnapshot.getKey());

        // A comment has changed, use the key to determine if we are displaying this
        // comment and if so displayed the changed comment.
        Comment newComment = dataSnapshot.getValue(Comment.class);
        String commentKey = dataSnapshot.getKey();

        // ...
    }

    @Override
    public void onChildRemoved(DataSnapshot dataSnapshot) {
        Log.d(TAG, "onChildRemoved:" + dataSnapshot.getKey());

        // A comment has changed, use the key to determine if we are displaying this
        // comment and if so remove it.
        String commentKey = dataSnapshot.getKey();

        // ...
    }

    @Override
    public void onChildMoved(DataSnapshot dataSnapshot, String previousChildName) {
        Log.d(TAG, "onChildMoved:" + dataSnapshot.getKey());

        // A comment has changed position, use the key to determine if we are
        // displaying this comment and if so move it.
        Comment movedComment = dataSnapshot.getValue(Comment.class);
        String commentKey = dataSnapshot.getKey();

        // ...
    }

    @Override
    public void onCancelled(DatabaseError databaseError) {
        Log.w(TAG, "postComments:onCancelled", databaseError.toException());
        Toast.makeText(mContext, "Failed to load comments.",
                Toast.LENGTH_SHORT).show();
    }
};
databaseReference.addChildEventListener(childEventListener);

Değer etkinliklerine göz atın

Veri listelerini okumak için önerilen yöntem ChildEventListener kullanmak olsa da liste referansına ValueEventListener eklemenin faydalı olduğu durumlar vardır.

Bir veri listesine ValueEventListener eklendiğinde tüm veri listesi, tek bir DataSnapshot olarak döndürülür. Daha sonra, bunları tek tek alt öğelere erişmek için devre dışı bırakabilirsiniz.

Sorgu için tek bir eşleşme olsa bile anlık görüntü yine de bir liste olarak kalır ve yalnızca tek bir öğe içerir. Öğeye erişmek için sonucun üstünden geçmeniz gerekir.

Kotlin+KTX

// My top posts by number of stars
myTopPostsQuery.addValueEventListener(object : ValueEventListener {
    override fun onDataChange(dataSnapshot: DataSnapshot) {
        for (postSnapshot in dataSnapshot.children) {
            // TODO: handle the post
        }
    }

    override fun onCancelled(databaseError: DatabaseError) {
        // Getting Post failed, log a message
        Log.w(TAG, "loadPost:onCancelled", databaseError.toException())
        // ...
    }
})

Java

// My top posts by number of stars
myTopPostsQuery.addValueEventListener(new ValueEventListener() {
    @Override
    public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
        for (DataSnapshot postSnapshot: dataSnapshot.getChildren()) {
            // TODO: handle the post
        }
    }

    @Override
    public void onCancelled(@NonNull DatabaseError databaseError) {
        // Getting Post failed, log a message
        Log.w(TAG, "loadPost:onCancelled", databaseError.toException());
        // ...
    }
});

Bu kalıp, ek onChildAdded etkinliklerini dinlemek yerine bir listenin tüm alt öğelerini tek bir işlemde getirmek istediğinizde kullanışlı olabilir.

Dinleyicileri ayır

Geri çağırma işlevleri, Firebase veritabanı referansınızda removeEventListener() yöntemi çağrılarak kaldırılır.

İşleyici bir veri konumuna birden çok kez eklenmişse her etkinlik için birden çok kez çağrılır ve tamamen kaldırmak için aynı sayıda çıkarmanız gerekir.

Bir üst işleyicide removeEventListener() çağrısı yapıldığında, alt düğümlerde kayıtlı işleyiciler otomatik olarak kaldırılmaz. Geri çağırmanın kaldırılması için tüm alt işleyicilerde de removeEventListener() çağrılmalıdır.

Verileri sıralama ve filtreleme

Verileri anahtara, değere veya bir alt öğenin değerine göre sıralanmış şekilde almak için Realtime Database Query sınıfını kullanabilirsiniz. Sıralanan sonucu belirli sayıda sonuç veya anahtar ya da değer aralığına göre de filtreleyebilirsiniz.

Verileri sırala

Sıralanmış verileri almak için öncelikle sonuçların nasıl sıralandığını belirlemek üzere sıralama yöntemlerinden birini belirtin:

Yöntem Kullanım
orderByChild() Sonuçları, belirtilen bir alt anahtarın veya iç içe yerleştirilmiş alt yolun değerine göre sıralayın.
orderByKey() Sonuçları alt anahtarlara göre sıralayın.
orderByValue() Sonuçları alt değerlere göre sıralayın.

Aynı anda yalnızca bir sıralama yöntemi kullanabilirsiniz. Bir sıralama yönteminin aynı sorguda birden çok kez çağrılması hataya neden olur.

Aşağıdaki örnek, bir kullanıcının yıldız sayısına göre sıralanmış en popüler yayınlarının listesini nasıl alabileceğinizi gösterir:

Kotlin+KTX

// My top posts by number of stars
val myUserId = uid
val myTopPostsQuery = databaseReference.child("user-posts").child(myUserId)
    .orderByChild("starCount")

myTopPostsQuery.addChildEventListener(object : ChildEventListener {
    // TODO: implement the ChildEventListener methods as documented above
    // ...
})

Java

// My top posts by number of stars
String myUserId = getUid();
Query myTopPostsQuery = databaseReference.child("user-posts").child(myUserId)
        .orderByChild("starCount");
myTopPostsQuery.addChildEventListener(new ChildEventListener() {
    // TODO: implement the ChildEventListener methods as documented above
    // ...
});

Bu, bir alt işleyici ile birleştirildiğinde, istemcinin kullanıcı kimliğine göre veritabanındaki yoldan kullanıcının yayınları ile senkronize edilmesini sağlayan bir sorgu tanımlar. Kullanıcı kimlikleri, her bir yayının aldığı yıldız sayısına göre sıralanır. Kimlikleri dizin anahtarı olarak kullanma tekniği "veri yayma" olarak adlandırılır. Bu teknik hakkında daha fazla bilgiyi Veritabanınızı Yapılandırma bölümünde bulabilirsiniz.

orderByChild() yöntemine yapılan çağrı, sonuçların sıralanacağı alt anahtarı belirtir. Bu durumda yayınlar ilgili "starCount" alt öğesinin değerine göre sıralanır. Sorgular, aşağıdaki gibi görünen verileriniz olması durumunda iç içe yerleştirilmiş alt öğelere göre de sıralanabilir:

"posts": {
  "ts-functions": {
    "metrics": {
      "views" : 1200000,
      "likes" : 251000,
      "shares": 1200,
    },
    "title" : "Why you should use TypeScript for writing Cloud Functions",
    "author": "Doug",
  },
  "android-arch-3": {
    "metrics": {
      "views" : 900000,
      "likes" : 117000,
      "shares": 144,
    },
    "title" : "Using Android Architecture Components with Firebase Realtime Database (Part 3)",
    "author": "Doug",
  }
},

Bu örnekte, orderByChild() çağrımızda iç içe yerleştirilmiş alt öğenin göreli yolunu belirterek liste öğelerimizi metrics anahtarı altında iç içe yerleştirilmiş değerlere göre sıralayabiliriz.

Kotlin+KTX

// Most viewed posts
val myMostViewedPostsQuery = databaseReference.child("posts")
    .orderByChild("metrics/views")
myMostViewedPostsQuery.addChildEventListener(object : ChildEventListener {
    // TODO: implement the ChildEventListener methods as documented above
    // ...
})

Java

// Most viewed posts
Query myMostViewedPostsQuery = databaseReference.child("posts")
        .orderByChild("metrics/views");
myMostViewedPostsQuery.addChildEventListener(new ChildEventListener() {
    // TODO: implement the ChildEventListener methods as documented above
    // ...
});

Diğer veri türlerinin nasıl sıralandığı hakkında daha fazla bilgi için Sorgu verileri nasıl sıralanır? bölümüne bakın.

Veri filtreleme

Verileri filtrelemek için bir sorgu oluştururken sınır veya aralık yöntemlerinden herhangi birini tek bir sıralama yöntemiyle birleştirebilirsiniz.

Yöntem Kullanım
limitToFirst() Sıralı sonuç listesinin başlangıcından itibaren döndürülecek maksimum öğe sayısını ayarlar.
limitToLast() Sıralı sonuç listesinin sonundan döndürülecek maksimum öğe sayısını ayarlar.
startAt() Seçilen sıralama yöntemine bağlı olarak, belirtilen anahtar veya değerden büyük veya ona eşit olan öğeleri döndürün.
startAfter() Seçilen yönteme göre belirlenen anahtar veya değerden daha yüksek olan öğeleri döndürür.
endAt() Seçilen sıralama yöntemine bağlı olarak, belirtilen anahtar veya değerden düşük veya ona eşit olan öğeleri döndürün.
endBefore() Seçilen yönteme göre belirlenen anahtar veya değerden daha düşük olan öğeleri döndürür.
equalTo() Seçilen sıralama yöntemine bağlı olarak, belirtilen anahtar veya değere eşit olan öğeleri döndürün.

Sıralama ölçütü yöntemlerinden farklı olarak birden çok sınırlama veya aralık işlevini birleştirebilirsiniz. Örneğin, sonuçları belirli bir değer aralığıyla sınırlamak için startAt() ve endAt() yöntemlerini birleştirebilirsiniz.

Sorgu için tek bir eşleşme olsa bile anlık görüntü yine de bir listedir ve yalnızca tek bir öğe içerir. Öğeye erişmek için sonucu döngüye geçirmeniz gerekir.

Kotlin+KTX

// My top posts by number of stars
myTopPostsQuery.addValueEventListener(object : ValueEventListener {
    override fun onDataChange(dataSnapshot: DataSnapshot) {
        for (postSnapshot in dataSnapshot.children) {
            // TODO: handle the post
        }
    }

    override fun onCancelled(databaseError: DatabaseError) {
        // Getting Post failed, log a message
        Log.w(TAG, "loadPost:onCancelled", databaseError.toException())
        // ...
    }
})

Java

// My top posts by number of stars
myTopPostsQuery.addValueEventListener(new ValueEventListener() {
    @Override
    public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
        for (DataSnapshot postSnapshot: dataSnapshot.getChildren()) {
            // TODO: handle the post
        }
    }

    @Override
    public void onCancelled(@NonNull DatabaseError databaseError) {
        // Getting Post failed, log a message
        Log.w(TAG, "loadPost:onCancelled", databaseError.toException());
        // ...
    }
});

Sonuç sayısını sınırlandırın

Belirli bir geri çağırma işlemi için senkronize edilecek maksimum alt öğe sayısını ayarlamak için limitToFirst() ve limitToLast() yöntemlerini kullanabilirsiniz. Örneğin, 100 sınır belirlemek için limitToFirst() kullanırsanız başlangıçta en fazla 100 onChildAdded() geri çağırması alırsınız. Firebase veritabanınızda depolanan öğe sayısı 100'den azsa her öğe için onChildAdded() geri çağırması etkinleşir.

Öğeler değiştikçe sorguya giren öğeler için onChildAdded() geri çağırma, sorgudan çıkan öğeler için ise onChildRemoved() geri çağırma alırsınız. Böylece toplam sayı 100'de kalır.

Aşağıdaki örnekte, örnek blogging uygulamasının tüm kullanıcılar tarafından yapılan en son 100 yayının listesini almak için bir sorguyu nasıl tanımladığı gösterilmektedir:

Kotlin+KTX

// Last 100 posts, these are automatically the 100 most recent
// due to sorting by push() keys.
databaseReference.child("posts").limitToFirst(100)

Java

// Last 100 posts, these are automatically the 100 most recent
// due to sorting by push() keys
Query recentPostsQuery = databaseReference.child("posts")
        .limitToFirst(100);

Bu örnek yalnızca bir sorguyu tanımlar; verilerin senkronize edilebilmesi için ekli bir işleyici içermesi gerekir.

Anahtar veya değere göre filtreleyin

Sorgular için rastgele başlangıç, bitiş ve denklik noktalarını seçmek amacıyla startAt(), startAfter(), endAt(), endBefore() ve equalTo() kullanabilirsiniz. Bu, verileri sayfalara ayırmak veya belirli bir değere sahip alt öğeleri olan öğeleri bulmak için yararlı olabilir.

Sorgu verileri nasıl sıralanır?

Bu bölümde, verilerin Query sınıfındaki her bir yönteme göre nasıl sıralandığı açıklanmaktadır.

orderByChild

orderByChild() kullanılırken belirtilen alt anahtarı içeren veriler aşağıdaki gibi sıralanır:

  1. Belirtilen alt anahtarda null değerine sahip olan alt öğeler önce gelir.
  2. Belirtilen alt anahtar için false değerine sahip olan alt öğeler ardından gelir. Birden fazla alt öğe false değerine sahipse bunlar anahtara göre sözlüksel olarak sıralanır.
  3. Belirtilen alt anahtar için true değerine sahip olan alt öğeler ardından gelir. Birden fazla alt öğe true değerine sahipse bunlar sözlüksel olarak anahtara göre sıralanır.
  4. Sayısal değere sahip olan alt öğeler artan düzende sıralanır. Belirtilen alt düğüm için aynı sayısal değere sahip birden fazla alt öğe varsa bunlar anahtara göre sıralanır.
  5. Dizeler sayılardan sonra gelir ve sözlüksel olarak artan düzende sıralanır. Birden fazla alt düğüm, belirtilen alt düğüm için aynı değere sahipse bunlar sözlüksel olarak anahtara göre sıralanır.
  6. Nesneler son sırada gelir ve anahtara göre sözlüksel olarak artan düzende sıralanır.

orderByKey

Verilerinizi sıralamak için orderByKey() kullandığınızda veriler, anahtara göre artan düzende döndürülür.

  1. 32 bit tam sayı olarak ayrıştırılabilen bir anahtarı olan alt öğeler önce gelir ve artan düzende sıralanır.
  2. Anahtarlarında dize değeri olan alt öğeler sıradaki sırayla, sözlüksel olarak artan düzende sıralanır.

orderByValue

orderByValue() kullanılırken alt öğeler değerlerine göre sıralanır. Sıralama ölçütleri orderByChild() ile aynıdır. Tek fark, belirtilen alt anahtarın değeri yerine düğümün değerinin kullanılmasıdır.

Sonraki adımlar