Android'de Veri Listeleri ile Çalışma

Bu belgede, Firebase'deki veri listeleriyle çalışma konusu ele alınmaktadır. Firebase verilerini okuma ve yazmanın temellerini öğ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 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 bu otomatik olarak oluşturulan anahtarları kullanarak birden fazla istemci, yazma çakışmaları olmadan aynı anda aynı konuma alt öğeler ekleyebilir. push() tarafından oluşturulan benzersiz anahtar, zaman damgasına dayalıdır. Bu nedenle, liste öğeleri kronolojik olarak otomatik olarak sıralanır.

push() yöntemi tarafından döndürülen yeni verilere yapılan referansı kullanarak çocuğun otomatik olarak oluşturulan anahtarının değerini alabilir veya çocuk için veri ayarlayabilirsiniz. push() referansında getKey() çağrısı yapıldığında otomatik olarak oluşturulan anahtarın değeri döndürülür.

Veri yapınızı düzleştirme işlemini basitleştirmek için bu otomatik olarak oluşturulan anahtarları kullanabilirsiniz. Daha fazla bilgi için veri dağıtımı örneğini inceleyin.

Alt etkinliklerini dinleme

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

Çocuk etkinlikleri, bir düğümün çocuklarında meydana gelen belirli işlemlere yanıt olarak tetiklenir. Örneğin, push() yöntemiyle yeni bir çocuk eklenmesi veya updateChildren() yöntemiyle bir çocuğun güncellenmesi gibi işlemler. 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 ChildEventListener ekleyin:

Dinleyici Etkinlik geri araması 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, ardından belirtilen yola yeni bir 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 alt düğüm her değiştirildiğinde tetiklenir. Etkinlik işleyiciye iletilen DataSnapshot, çocuğa ait güncellenmiş verileri içerir.
onChildRemoved() Bir listeden kaldırılan öğeleri dinleyin. Etkinlik geri çağırmasına iletilen DataSnapshot, kaldırılan alt öğenin verilerini içerir.
onChildMoved() Sıralı listedeki öğelerin sırasıyla ilgili değişiklikleri dinleyin. Bu etkinlik, alt öğenin yeniden sıralanmasına neden olan bir güncelleme tarafından onChildChanged() geri çağırma işlemi her tetiklendiğinde tetiklenir. orderByChild veya orderByValue ile sıralanmış verilerle kullanılır.

Örneğin, bir sosyal blog uygulaması, bir gönderinin 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

ChildEventListener kullanmak, veri listelerini okumanın önerilen yoludur ancak bir liste referansına ValueEventListener eklemenin faydalı olduğu durumlar da vardır.

Bir veri listesine ValueEventListener eklemek, veri listesinin tamamını tek bir DataSnapshot olarak döndürür. Daha sonra tek tek alt öğelere erişmek için bu DataSnapshot üzerinde döngü oluşturabilirsiniz.

Sorgu için yalnızca tek bir eşleşme olsa bile anlık görüntü yine bir listedir. Yalnızca tek bir öğe içerir. Öğeye erişmek için sonucu döngüye almanı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 listedeki tüm alt öğeleri tek bir işlemde getirmek istediğinizde faydalı olabilir.

Dinleyicileri ayırma

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

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

Bir ebeveyn dinleyicide removeEventListener() çağrısı yapılması, alt düğümlerinde kayıtlı dinleyicileri otomatik olarak kaldırmaz. Geri çağırmayı kaldırmak için tüm alt dinleyicilerde de removeEventListener() çağrısı yapılmalıdır.

Verileri sıralama ve filtreleme

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

Verileri sıralama

Sıralanmış verileri almak için sonuçların nasıl sıralanacağını belirlemek üzere order-by yöntemlerinden birini belirterek başlayın:

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 öğe değerlerine göre sıralayın.

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

Aşağıdaki örnekte, bir kullanıcının yıldız sayısına göre sıralanmış en iyi gönderilerinin listesini 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, bir alt dinleyiciyle birleştirildiğinde istemciyi, veritabanındaki yoldan kullanıcının gönderileriyle senkronize eden bir sorguyu tanımlar. Bu işlem, kullanıcının gönderilerini kullanıcı kimliğine göre ve her gönderinin aldığı yıldız sayısına göre sıralayarak gerçekleştirilir. Kimlikleri dizin anahtarı olarak kullanma tekniğine veri dağıtımı 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ı sıralamak için kullanılacak alt anahtarı belirtir. Bu durumda, yayınlar ilgili "starCount" alt öğesinin değerine göre sıralanır. Aşağıdaki gibi verileriniz varsa sorgular 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, metrics anahtarı altında iç içe yerleştirilmiş değerlere göre liste öğelerimizi sıralayabiliriz. Bunun için orderByChild() çağrımızda iç içe yerleştirilmiş alt öğenin göreli yolunu belirtmemiz gerekir.

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 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() Sıralama yöntemine bağlı olarak, belirtilen anahtardan veya değerden büyük ya da bu anahtara veya değere eşit öğeleri döndürür.
startAfter() Sıralama yöntemine bağlı olarak, belirtilen anahtardan veya değerden büyük öğeleri döndürür.
endAt() Sıralama yöntemine bağlı olarak, belirtilen anahtardan veya değerden küçük ya da ona eşit öğeleri döndürür.
endBefore() Sıralama yöntemine bağlı olarak, belirtilen anahtardan veya değerden küçük öğeleri döndürür.
equalTo() Sıralama yöntemine bağlı olarak belirtilen anahtara veya değere eşit öğeleri döndürür.

Sıralama yöntemlerinden farklı olarak, 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ü bir liste olmaya devam eder. Yalnızca tek bir öğe içerir. Öğeye erişmek için sonucu döngüye almanı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, 100 sınırı belirlemek için limitToFirst() kullanırsanız başlangıçta yalnızca 100 onChildAdded() geri araması alırsınız. Firebase veritabanınızda 100'den az öğe depolanıyorsa her öğe için bir onChildAdded() geri çağırma işlemi tetiklenir.

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

Aşağıdaki örnekte, örnek blog uygulaması tarafından tüm kullanıcıların en son 100 gönderisinin listesini almak için nasıl bir sorgu tanımlandığı 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 örnek yalnızca bir sorguyu tanımlar. Verilerin gerçekten senkronize edilmesi için eklenmiş bir dinleyiciye sahip olması gerekir.

Anahtara veya değere göre filtreleme

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

Sorgu verilerinin sıralanma şekli

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

orderByChild

orderByChild() kullanılırken belirtilen alt anahtarı içeren veriler şu şekilde sıralanır:

  1. Belirtilen çocuk anahtarı için null değeri olan çocuklar önce gelir.
  2. Belirtilen alt anahtar için false değerine sahip alt öğeler bir sonraki sırada yer alır. Birden fazla alt öğe false değerine sahipse anahtara göre sözlük sırasına göre sıralanır.
  3. Belirtilen alt anahtar için true değerine sahip alt öğeler bir sonraki sırada yer alır. Birden fazla alt öğenin değeri true ise bunlar anahtara göre sözlük sırasına göre sıralanır.
  4. Sayısal değere sahip çocuklar, artan düzende sıralanarak gösterilir. 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 sırasına göre 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 sırasına göre sıralanır.
  6. Nesneler en sona gelir ve anahtara göre artan sözlük sıralamasıyla sıralanır.

orderByKey

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

  1. 32 bitlik bir tam sayı olarak ayrıştırılabilen anahtara sahip çocuklar, artan düzende sıralanarak ilk sırada yer alır.
  2. Anahtarı dize değeri olan çocuklar, sözlük sıralamasına göre artan düzende sıralanır.

orderByValue

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

Sonraki adımlar