Android'de Veri Listeleri ile Çalışma

Bu belgede, Firebase'de veri listeleriyle çalışma konusu ele alınmaktadır. Firebase verilerini okuma ve yazmanın temel bilgilerini öğrenmek için Android'de Veri Okuma ve Yazma başlıklı makaleyi inceleyin.

DatabaseReference alma

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

Kotlin

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

Java

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

Listeleri okuma ve yazma

Veri listesine ekleme

Ç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 üretilmiş bu anahtarları kullanarak birden fazla istemci, yazma çakışması olmadan aynı konuma aynı anda alt öğe ekleyebilir. push() tarafından oluşturulan benzersiz anahtar, zaman damgasına dayalıdır. Bu nedenle, liste öğeleri otomatik olarak kronolojik sıraya göre sıralanır.

Alt öğenin otomatik olarak üretilmiş anahtarının değerini almak veya alt öğe için veri ayarlamak üzere push() yönteminin döndürdüğü yeni verilere yapılan referansı kullanabilirsiniz. Bir push() referansında getKey() çağrıldığında otomatik olarak üretilmiş anahtarın değeri döndürülür.

Veri yapınızı düzleştirmeyi kolaylaştırmak için otomatik olarak üretilmiş bu anahtarları kullanabilirsiniz. Daha fazla bilgi için veri yayma örneğini inceleyin.

Alt etkinlikleri dinleme

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

Alt etkinlikler, bir düğümün alt öğelerinde gerçekleşen belirli işlemlere yanıt olarak tetiklenir. Örneğin, push() yöntemiyle yeni bir alt öğe eklenmesi veya updateChildren() yöntemiyle bir alt öğenin güncellenmesi gibi. Bunların her biri, bir veritabanındaki belirli bir düğümde yapılan değişiklikleri dinlemek için yararlı olabilir.

DatabaseReference üzerinde alt etkinlikleri dinlemek için bir ChildEventListener ekleyin:

Dinleyici Etkinlik geri çağırma Tipik kullanım
ChildEventListener onChildAdded() Öğe listelerini alma veya öğe listesine eklenenleri dinleme Bu geri çağırma, mevcut her alt öğe için bir kez ve ardından belirtilen yola her yeni alt öğe eklendiğinde tekrar tetiklenir. Dinleyiciye iletilen DataSnapshot, yeni alt öğenin verilerini içerir.
onChildChanged() Bir listedeki öğelerde yapılan değişiklikleri dinleme. Bu etkinlik, alt düğümün alt öğelerinde yapılan değişiklikler de dahil olmak üzere bir alt düğüm her değiştirildiğinde tetiklenir. Etkinlik işleyiciye iletilen DataSnapshot, alt öğenin güncellenmiş verilerini içerir.
onChildRemoved() Listeden kaldırılan öğeleri dinleme 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 dinleme Bu etkinlik, onChildChanged() geri çağırma işlevi alt öğenin yeniden sıralanmasına neden olan bir güncellemeyle tetiklendiğinde tetiklenir. orderByChild veya orderByValue ile sıralanan verilerle kullanılır.

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

Kotlin

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 etkinliklerini dinleme

Veri listelerini okumak için ChildEventListener kullanılması önerilse de liste referansına ValueEventListener eklemenin faydalı olduğu durumlar da vardır.

Bir veri listesine ValueEventListener eklediğinizde tüm veri listesi tek bir DataSnapshot olarak döndürülür. Ardından, tek tek alt öğelere erişmek için bu liste üzerinde döngü oluşturabilirsiniz.

Sorgu için yalnızca tek bir eşleşme olsa bile anlık görüntü yine de bir listedir; yalnızca tek bir öğe içerir. Öğeye erişmek için sonuç üzerinde döngü oluşturmanız gerekir:

Kotlin

// 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 almak istediğinizde yararlı olabilir.

Dinleyicileri ayırma

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

Bir dinleyici bir veri konumuna birden fazla kez eklendiyse her etkinlik için birden fazla kez çağrılır ve tamamen kaldırmak için aynı sayıda ayırmanız gerekir.

Üst dinleyicide removeEventListener() yöntemini çağırmak, alt düğümlerinde kayıtlı dinleyicileri otomatik olarak kaldırmaz. Geri çağırmayı kaldırmak için alt dinleyicilerde de removeEventListener() yönteminin çağrılması gerekir.

Verileri sıralama ve filtreleme

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

Verileri sıralama

Sıralanmış verileri almak için öncelikle sonuçların nasıl sıralanacağı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ıralar.
orderByKey() Sonuçları alt anahtarlara göre sıralar.
orderByValue() Sonuçları alt değerlere göre sıralar.

Aynı anda yalnızca bir sıralama yöntemi kullanabilirsiniz. Aynı sorguda bir sıralama yöntemini birden çok kez çağırmak hataya neden olur.

Aşağıdaki örnekte, bir kullanıcının en çok beğenilen yayınlarının listesini yıldız sayısına göre sıralanmış olarak nasıl alabileceğiniz gösterilmektedir:

Kotlin

// 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, alt dinleyici ile birleştirildiğinde istemciyi, kullanıcı kimliğine göre veritabanındaki yoldan kullanıcının gönderileriyle senkronize eden ve her gönderinin aldığı yıldız sayısına göre sıralanan bir sorgu tanımlar. Dizin anahtarları olarak kimlikleri kullanma tekniğine veri yayma adı verilir. Bu konu hakkında daha fazla bilgiyi Veritabanınızı Yapılandırma başlıklı makalede bulabilirsiniz.

orderByChild() yöntemine yapılan çağrı, sonuçların sıralanacağı alt anahtarı belirtir. Bu durumda yayınlar, ilgili "starCount" alt öğelerinin değerine göre sıralanır. Sorgular, aşağıdaki gibi verileriniz varsa 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ının altında iç içe yerleştirilmiş değerlere göre sıralayabiliriz.

Kotlin

// 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? başlıklı makaleyi inceleyin.

Veri filtreleme

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

Yöntem Kullanım
limitToFirst() Sıralı sonuç listesinin başı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 anahtardan veya değerden büyük ya da ona eşit olan öğeleri döndürür.
startAfter() Seçilen sıralama yöntemine bağlı olarak, belirtilen anahtar veya değerden daha büyük öğeleri döndürür.
endAt() Seçilen sıralama yöntemine bağlı olarak, belirtilen anahtar veya değere eşit ya da ondan küçük öğeleri döndürür.
endBefore() Seçilen sıralama yöntemine bağlı olarak, belirtilen anahtar veya değerden daha küçük öğeleri döndürür.
equalTo() Seçilen sıralama yöntemine bağlı olarak, belirtilen anahtara veya değere eşit öğeleri döndürür.

Sıralama yöntemlerinin aksine, birden fazla sınır 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 yalnızca tek bir eşleşme olsa bile anlık görüntü yine de bir listedir; yalnızca tek bir öğe içerir. Öğeye erişmek için sonuç üzerinde döngü oluşturmanız gerekir:

Kotlin

// 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ırlama

Belirli bir geri çağırma için senkronize edilecek maksimum alt öğe sayısını ayarlamak üzere limitToFirst() ve limitToLast() yöntemlerini kullanabilirsiniz. Örneğin, limitToFirst() kullanarak 100 sınırı belirlerseniz başlangıçta yalnızca en fazla 100 onChildAdded() geri çağırma alırsınız. Firebase veritabanınızda 100'den az öğe varsa her öğe için bir onChildAdded() geri çağırma işlevi tetiklenir.

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

Aşağıdaki örnekte, örnek blog uygulamasının tüm kullanıcıların en son 100 yayınını içeren bir listeyi almak için nasıl sorgu tanımladığı gösterilmektedir:

Kotlin

// 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 örnekte yalnızca bir sorgu tanımlanmaktadır. Verilerin senkronize edilmesi için ekli bir dinleyici olması gerekir.

Anahtara veya değere göre filtrele

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

Sorgu verilerinin sıralanma şekli

Bu bölümde, verilerin Query sınıfındaki sıralama yöntemlerinin her biri tarafından nasıl sıralandığı açıklanmaktadır.

orderByChild

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

  1. Belirtilen alt anahtar için null değerine sahip alt öğeler önce gelir.
  2. Ardından, belirtilen alt anahtar için false değerine sahip alt öğeler gelir. Birden fazla alt öğenin değeri false ise anahtara göre sözlük düzeninde sıralanırlar.
  3. Ardından, belirtilen alt anahtar için true değerine sahip alt öğeler gelir. Birden fazla alt öğenin değeri true ise bunlar anahtara göre alfabetik olarak sıralanır.
  4. Ardından, sayısal değere sahip alt öğeler artan düzende sıralanır. Belirtilen alt düğüm için birden fazla alt öğe aynı sayısal değere sahipse bunlar anahtara göre sıralanır.
  5. Dizeler sayılardan sonra gelir ve sözlük düzeninde artan düzende sıralanır. Belirtilen alt düğüm için birden fazla alt öğe aynı değere sahipse bunlar anahtara göre sözlük düzeninde sıralanır.
  6. Nesneler en sonda yer alır ve anahtara göre alfabetik olarak artan düzende sıralanır.

orderByKey

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

  1. 32 bit tam sayı olarak ayrıştırılabilen bir anahtara sahip alt öğeler, artan düzende sıralanarak ilk sırada yer alır.
  2. Ardından, anahtarı dize değeri olan alt öğeler, alfabetik 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, belirtilen bir alt anahtarın değeri yerine düğümün değerinin kullanılması dışında orderByChild() ile aynıdır.

Sonraki adımlar