Android'de Veri Okuma ve Yazma

Bu belgede Firebase verilerini okuma ve yazmayla ilgili temel bilgiler verilmektedir.

Firebase verileri bir FirebaseDatabase referansına yazılır ve bu referans tarafından alınır. referansa eşzamansız işleyici eklemektir. Dinleyici tetiklenir. bir kez, verilerin ilk durumu için bir kez ve veriler her değiştiğinde bir kez daha düzenleyin.

(İsteğe bağlı) Firebase Local Emulator Suite ile prototip oluşturun ve test edin

Uygulamanızın Realtime Database'den nasıl okuduğu ve yazdığından bahsetmeden önce Gerçek Zamanlı Veritabanı'nın prototipini oluşturmak ve test etmek için kullanabileceğiniz bir araç setinden bahsedelim. şu işleve sahip: Firebase Local Emulator Suite. Farklı verileri deniyorsanız güvenlik kurallarınızı optimize ederek veya makine öğreniminden en iyi şekilde arka uçla etkileşim kurmanın ve yerel olarak çalışabilmenin uygun maliyetli bir yoludur. çok iyi bir fikir olabilir.

Realtime Database emülatörü, Local Emulator Suite'in bir parçasıdır. uygulamanızın emüle edilmiş veritabanı içeriğinizle ve yapılandırmanızla etkileşim kurmasına olanak tanır. ve isteğe bağlı olarak emüle edilen proje kaynaklarınızın (işlevler, diğer veritabanları ve güvenlik kuralları) ekleyin.

Realtime Database emülatörünün kullanımı yalnızca birkaç adımdan oluşur:

  1. Emülatöre bağlanmak için uygulamanızın test yapılandırmasına bir kod satırı ekleme.
  2. Yerel proje dizininizin kök dizininden firebase emulators:start komutunu çalıştırın.
  3. Realtime Database platformu kullanarak uygulamanızın prototip kodundan çağrı yapma SDK'yı her zamanki gibi kullanın veya Realtime Database REST API'yi kullanın.

Realtime Database ve Cloud Functions'ı içeren adım adım açıklamalı ayrıntılı bir kılavuz mevcuttur. Ayrıca Local Emulator Suite tanıtımı'na da göz atmalısınız.

Veritabanı Referansı Alma

Veritabanından veri okumak veya yazmak için DatabaseReference:

Kotlin+KTX

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

Java

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

Verileri yazma

Temel yazma işlemleri

Temel yazma işlemleri için verileri belirli bir yere kaydetmek üzere setValue() kullanabilirsiniz yeni bir referans noktası yaparak bu yoldaki mevcut verilerin yerini alır. Bu yöntemi şu amaçlarla kullanabilirsiniz:

  • Kullanılabilir JSON türlerine karşılık gelen aşağıdaki gibi geçiş türleri:
    • String
    • Long
    • Double
    • Boolean
    • Map<String, Object>
    • List<Object>
  • Tanımlayan sınıfın bir varsayılanı varsa özel Java nesnesi iletin hiçbir argüman almayan ve mülkler için kamu alıcıları olan kurucu atanacak.

Java nesnesi kullanıyorsanız nesnenizin içeriği otomatik olarak eşlenir şekilde alt konumlara yerleştiriliyor. Bir Java nesnesi kullanmak genellikle daha kolay okunmasını ve bakımını yapmanızı sağlar. Örneğin, uygulamasındaysa User nesneniz aşağıdaki gibi görünebilir:

Kotlin+KTX

@IgnoreExtraProperties
data class User(val username: String? = null, val email: String? = null) {
    // Null default values create a no-argument default constructor, which is needed
    // for deserialization from a DataSnapshot.
}

Java

@IgnoreExtraProperties
public class User {

    public String username;
    public String email;

    public User() {
        // Default constructor required for calls to DataSnapshot.getValue(User.class)
    }

    public User(String username, String email) {
        this.username = username;
        this.email = email;
    }

}

setValue() uygulamasına sahip bir kullanıcıyı aşağıdaki şekilde ekleyebilirsiniz:

Kotlin+KTX

fun writeNewUser(userId: String, name: String, email: String) {
    val user = User(name, email)

    database.child("users").child(userId).setValue(user)
}

Java

public void writeNewUser(String userId, String name, String email) {
    User user = new User(name, email);

    mDatabase.child("users").child(userId).setValue(user);
}

setValue() bu şekilde kullanılırsa belirtilen konumdaki verilerin üzerine yazılır. dahildir. Ancak, eğer yoksa çocuklarınız için yeniden yazmanız gerekir. Kullanıcıların profillerini güncellemelerine izin vermek istiyorsanız kullanıcı adını şu şekilde güncelleyebilirsiniz:

Kotlin+KTX

database.child("users").child(userId).child("username").setValue(name)

Java

mDatabase.child("users").child(userId).child("username").setValue(name);

Verileri okuma

Verileri kalıcı işleyicilerle okuma

Bir yoldaki verileri okumak ve değişiklikleri dinlemek için addValueEventListener() aracını kullanın yöntemini kullanarak DatabaseReference öğesine ValueEventListener ekleyin.

Dinleyici Etkinlik geri çağırması Tipik kullanım
ValueEventListener onDataChange() Bir yolun tüm içeriğindeki değişiklikleri okuma ve dinleme.

Şu öğenin statik anlık görüntüsünü okumak için onDataChange() yöntemini kullanabilirsiniz: etkinlik sırasında mevcut oldukları halde, belirli bir yoldaki içerikler. Bu yöntem dinleyici eklendiğinde bir kez tetiklenir ve veriler her eklendiğinde bazı değişiklikler var. Etkinlik geri çağırması, çocuk verileri de dahil olmak üzere söz konusu konumdaki tüm veriler. Hiç veri yoksa anlık görüntü, exists() ve null çağrısı yaptığınızda false değerini döndürür. üzerinde getValue().

Aşağıdaki örnekte, ayrıntıları:

Kotlin+KTX

val postListener = object : ValueEventListener {
    override fun onDataChange(dataSnapshot: DataSnapshot) {
        // Get Post object and use the values to update the UI
        val post = dataSnapshot.getValue<Post>()
        // ...
    }

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

Java

ValueEventListener postListener = new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
        // Get Post object and use the values to update the UI
        Post post = dataSnapshot.getValue(Post.class);
        // ..
    }

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

İşleyici, belirtilenDataSnapshot etkinlik sırasında veritabanında bulunan konumu. Şu cihazda getValue() aranıyor: anlık görüntü, verilerin Java nesne gösterimini döndürür. Hiç veri yoksa konumda gerçekleştirildiğinde getValue() çağrısı yapıldığında null döndürülür.

Bu örnekte, ValueEventListener aynı zamandaonCancelled() değeri çağrılır. Örneğin, istemcinin Firebase veritabanı konumundan okuma izni yok. Bu yöntemine, hatanın neden oluştuğunu belirten bir DatabaseError nesnesi iletilir.

Verileri bir kez oku

get() kullanarak bir kez okuma

SDK, veritabanı sunucularıyla etkileşimleri yönetecek şekilde tasarlanmıştır. Uygulama çevrimiçi veya çevrimdışı.

Genellikle yukarıda açıklanan ValueEventListener tekniklerini kullanmalısınız. kullanarak arka uçtan veri güncelleme bildirimi alabilirsiniz. İlgili içeriği oluşturmak için kullanılan dinleyici teknikleri, kullanımınızı ve faturalandırmanızı azaltır ve kullanıcılarınıza çevrimiçi ve çevrimdışı ortamda en iyi deneyimi sunmanızı sağlar.

Verilere yalnızca bir kez ihtiyaç duyarsanız, raporun anlık görüntüsünü almak için get() kullanabilirsiniz bu verileri kaldırmanızı sağlar. get() herhangi bir nedenle sunucuyu döndüremezse değerine ayarlanırsa istemci, yerel depolama önbelleğini inceler ve değeri bulunamadı.

Gereksiz get() kullanımı, bant genişliği kullanımını artırabilir ve performansı gösterir. Bu performans, yukarıda gösterildiği gibi gerçek zamanlı işleyici kullanılarak engellenebilir.

Kotlin+KTX

mDatabase.child("users").child(userId).get().addOnSuccessListener {
    Log.i("firebase", "Got value ${it.value}")
}.addOnFailureListener{
    Log.e("firebase", "Error getting data", it)
}

Java

mDatabase.child("users").child(userId).get().addOnCompleteListener(new OnCompleteListener<DataSnapshot>() {
    @Override
    public void onComplete(@NonNull Task<DataSnapshot> task) {
        if (!task.isSuccessful()) {
            Log.e("firebase", "Error getting data", task.getException());
        }
        else {
            Log.d("firebase", String.valueOf(task.getResult().getValue()));
        }
    }
});

Dinleyici kullanarak bir kez okuma

Bazı durumlarda, yerel önbellek değerinin döndürülmesini isteyebilirsiniz güncel bir değer olup olmadığını kontrol etmek yerine anında rapor oluşturur. O addListenerForSingleValueEvent kullanabilir, bu durumlarda yerel disk önbelleğinizi hemen kontrol edin.

Bu, yalnızca bir kez yüklenmesi gereken ve yüklenmesi beklenmeyen veriler için yararlıdır. veya aktif dinlemeyi gerektirir. Örneğin blog uygulaması Yukarıdaki örneklerde, kullanıcı bir web sitesine girdiğinde kullanıcının profilini yüklemek için yeni bir yayın yazmaya başlayın.

Verileri güncelleme veya silme

Belirli alanları güncelle

Diğer düğümlerin üzerine yazmadan bir düğümün belirli alt öğelerine aynı anda yazmak için alt düğümler için updateChildren() yöntemini kullanın.

updateChildren() çağrısı yapılırken alt düzey alt değerleri şu şekilde güncelleyebilirsiniz: anahtar için bir yol belirterek. Veriler ölçeklendirilmek üzere birden fazla konumda depolanıyorsa isterseniz, bu verilerin tüm örneklerini verilerin yayılması. Örneğin, sosyal blog uygulaması şuna benzer bir Post sınıfına sahip olabilir:

Kotlin+KTX

@IgnoreExtraProperties
data class Post(
    var uid: String? = "",
    var author: String? = "",
    var title: String? = "",
    var body: String? = "",
    var starCount: Int = 0,
    var stars: MutableMap<String, Boolean> = HashMap(),
) {

    @Exclude
    fun toMap(): Map<String, Any?> {
        return mapOf(
            "uid" to uid,
            "author" to author,
            "title" to title,
            "body" to body,
            "starCount" to starCount,
            "stars" to stars,
        )
    }
}

Java

@IgnoreExtraProperties
public class Post {

    public String uid;
    public String author;
    public String title;
    public String body;
    public int starCount = 0;
    public Map<String, Boolean> stars = new HashMap<>();

    public Post() {
        // Default constructor required for calls to DataSnapshot.getValue(Post.class)
    }

    public Post(String uid, String author, String title, String body) {
        this.uid = uid;
        this.author = author;
        this.title = title;
        this.body = body;
    }

    @Exclude
    public Map<String, Object> toMap() {
        HashMap<String, Object> result = new HashMap<>();
        result.put("uid", uid);
        result.put("author", author);
        result.put("title", title);
        result.put("body", body);
        result.put("starCount", starCount);
        result.put("stars", stars);

        return result;
    }
}

Bir yayın oluşturmak ve aynı anda bunu son etkinlikle güncellemek için etkinlik feed'ini paylaşmak isterseniz blog uygulaması kod şöyle olur:

Kotlin+KTX

private fun writeNewPost(userId: String, username: String, title: String, body: String) {
    // Create new post at /user-posts/$userid/$postid and at
    // /posts/$postid simultaneously
    val key = database.child("posts").push().key
    if (key == null) {
        Log.w(TAG, "Couldn't get push key for posts")
        return
    }

    val post = Post(userId, username, title, body)
    val postValues = post.toMap()

    val childUpdates = hashMapOf<String, Any>(
        "/posts/$key" to postValues,
        "/user-posts/$userId/$key" to postValues,
    )

    database.updateChildren(childUpdates)
}

Java

private void writeNewPost(String userId, String username, String title, String body) {
    // Create new post at /user-posts/$userid/$postid and at
    // /posts/$postid simultaneously
    String key = mDatabase.child("posts").push().getKey();
    Post post = new Post(userId, username, title, body);
    Map<String, Object> postValues = post.toMap();

    Map<String, Object> childUpdates = new HashMap<>();
    childUpdates.put("/posts/" + key, postValues);
    childUpdates.put("/user-posts/" + userId + "/" + key, postValues);

    mDatabase.updateChildren(childUpdates);
}

Bu örnekte, push() ile ilgili yayınları içeren düğümde bir yayın oluşturmak için /posts/$postid alanındaki tüm kullanıcıları ve anahtarı getKey(). Bu anahtar, kullanıcının iş sayfasında ikinci bir giriş oluşturmak için kullanılabilir. /user-posts/$userid/$postid itibarıyla yayınları var.

Bu yolları kullanarak, bir bölgedeki birden fazla konumda aynı anda güncelleme yapabilirsiniz. tek bir çağrıyla JSON ağacını (ör. bu örnekte olduğu gibi)updateChildren() yeni yayını her iki konumda da oluşturur. Bu şekilde yapılan eş zamanlı güncellemeler çok önemli: ya tüm güncellemeler başarılı olur ya da tüm güncellemeler başarısız olur.

Tamamlama Geri Çağırması Ekle

Verilerinizin ne zaman kaydedildiğini öğrenmek istiyorsanız en iyi tamamlama dinleyicisidir. Hem setValue() hem de updateChildren() isteğe bağlı yazma işlemi başarıyla gerçekleştirildiğinde çağrılan tamamlama işleyicisi taahhüdümüz var. Arama başarısız olduysa dinleyici hatanın neden oluştuğunu belirten bir hata nesnesi iletti.

Kotlin+KTX

database.child("users").child(userId).setValue(user)
    .addOnSuccessListener {
        // Write was successful!
        // ...
    }
    .addOnFailureListener {
        // Write failed
        // ...
    }

Java

mDatabase.child("users").child(userId).setValue(user)
        .addOnSuccessListener(new OnSuccessListener<Void>() {
            @Override
            public void onSuccess(Void aVoid) {
                // Write was successful!
                // ...
            }
        })
        .addOnFailureListener(new OnFailureListener() {
            @Override
            public void onFailure(@NonNull Exception e) {
                // Write failed
                // ...
            }
        });

Verileri silin

Verileri silmenin en basit yolu,removeValue() söz konusu verilerin konumu.

Başka bir yazma işleminin değeri olarak null değerini belirterek de silebilirsiniz setValue() veya updateChildren() gibi bir işlem. Bu tekniği kullanarak tek bir API çağrısındaki birden çok alt öğeyi silmek için updateChildren() ile birlikte kullanın.

Dinleyicileri ayır

Geri çağırma işlevleri,removeEventListener() Firebase veritabanı referansı.

Bir dinleyici bir veri konumuna birden çok kez eklenmişse her etkinlik için bir kereden fazla çağrılır ve etkinliği, o etkinlik için gereken sayıda kaldırmanız gerekir.

Ebeveyn dinleyicide removeEventListener() adlı kullanıcıya yapılan arama şunu yapmaz: alt düğümlerine kayıtlı işleyicileri otomatik olarak kaldırmalıdır; removeEventListener(), tüm çocuk dinleyicilerde de çağrılmalıdır tuşuna basarak geri çağırmayı kaldırın.

Verileri işlem olarak kaydet

Eşzamanlı etkenlere göre bozulabilecek verilerle çalışırken artımlı sayaçlar gibi değişiklikleri yapmak için işlemin işleyiş şekli. Bu işleme bir güncelleme işlevi ve bir isteğe bağlı bağımsız değişken olmak üzere geri arama tamamlanmasını sağlar. Güncelleme işlevi, verilerin mevcut durumunu bağımsız değişken ve yazmak istediğiniz yeni, istenen durumu döndürür. Eğer Yeni değeriniz başarıyla onaylanmadan önce başka bir istemci konuma yazar yazıldığında, güncelleme fonksiyonunuz yeni geçerli değerle tekrar çağrılır ve yazma yeniden denendi.

Örneğin sosyal blog uygulaması örneğimizde, kullanıcıların yayınlara yıldız ekleyebilir, yayınların yıldızlarını kaldırabilir ve ilgili yayının kaç yıldız aldığını takip edebilirsiniz şu şekildedir:

Kotlin+KTX

private fun onStarClicked(postRef: DatabaseReference) {
    // ...
    postRef.runTransaction(object : Transaction.Handler {
        override fun doTransaction(mutableData: MutableData): Transaction.Result {
            val p = mutableData.getValue(Post::class.java)
                ?: return Transaction.success(mutableData)

            if (p.stars.containsKey(uid)) {
                // Unstar the post and remove self from stars
                p.starCount = p.starCount - 1
                p.stars.remove(uid)
            } else {
                // Star the post and add self to stars
                p.starCount = p.starCount + 1
                p.stars[uid] = true
            }

            // Set value and report transaction success
            mutableData.value = p
            return Transaction.success(mutableData)
        }

        override fun onComplete(
            databaseError: DatabaseError?,
            committed: Boolean,
            currentData: DataSnapshot?,
        ) {
            // Transaction completed
            Log.d(TAG, "postTransaction:onComplete:" + databaseError!!)
        }
    })
}

Java

private void onStarClicked(DatabaseReference postRef) {
    postRef.runTransaction(new Transaction.Handler() {
        @NonNull
        @Override
        public Transaction.Result doTransaction(@NonNull MutableData mutableData) {
            Post p = mutableData.getValue(Post.class);
            if (p == null) {
                return Transaction.success(mutableData);
            }

            if (p.stars.containsKey(getUid())) {
                // Unstar the post and remove self from stars
                p.starCount = p.starCount - 1;
                p.stars.remove(getUid());
            } else {
                // Star the post and add self to stars
                p.starCount = p.starCount + 1;
                p.stars.put(getUid(), true);
            }

            // Set value and report transaction success
            mutableData.setValue(p);
            return Transaction.success(mutableData);
        }

        @Override
        public void onComplete(DatabaseError databaseError, boolean committed,
                               DataSnapshot currentData) {
            // Transaction completed
            Log.d(TAG, "postTransaction:onComplete:" + databaseError);
        }
    });
}

Bir işlem kullanmak, birden fazla olduğunda yıldız sayısının yanlış olmasını önler kullanıcılar aynı yayına yıldız ekleyebilir veya müşterinin verileri eski olabilir. Öğe işlem reddedilirse sunucu geçerli değeri istemciye döndürür. güncel değerle işlemi yeniden çalıştırır. Bu işlem, İşlem kabul edildi veya çok fazla deneme yapıldı.

Atomik sunucu tarafı artışları

Yukarıdaki kullanım örneğinde veritabanına iki değer yazıyoruz: Yayına yıldız veren/yıldızı kaldıran kullanıcı ve artan yıldız sayısı. Bir kullanıcının yayına yıldız eklediğini bilirsek atomik bir artış kullanabiliriz işlemidir.

Kotlin+KTX

private fun onStarClicked(uid: String, key: String) {
    val updates: MutableMap<String, Any> = hashMapOf(
        "posts/$key/stars/$uid" to true,
        "posts/$key/starCount" to ServerValue.increment(1),
        "user-posts/$uid/$key/stars/$uid" to true,
        "user-posts/$uid/$key/starCount" to ServerValue.increment(1),
    )
    database.updateChildren(updates)
}

Java

private void onStarClicked(String uid, String key) {
    Map<String, Object> updates = new HashMap<>();
    updates.put("posts/"+key+"/stars/"+uid, true);
    updates.put("posts/"+key+"/starCount", ServerValue.increment(1));
    updates.put("user-posts/"+uid+"/"+key+"/stars/"+uid, true);
    updates.put("user-posts/"+uid+"/"+key+"/starCount", ServerValue.increment(1));
    mDatabase.updateChildren(updates);
}

Bu kod bir işlem işlemi kullanmadığından otomatik olarak çakışan bir güncelleme varsa yeniden çalıştırın. Ancak, artış işlemi veritabanı sunucusunda gerçekleştiğinden çakışma olasılığı yoktur.

Uygulamaya özel çakışmaları (ör. kullanıcı adı) tespit edip reddetmek istiyorsanız daha önce yıldız eklediğiniz bir yayına yıldız ekleyerek kurallarından bahsedeceğiz.

Verilerle çevrimdışı çalışma

İstemcinin ağ bağlantısı kesilirse uygulamanız çalışmaya devam eder sağlayabilir.

Firebase veritabanına bağlı her istemcinin kendi dahili sürümü bulunur dinleyicilerin kullanılmakta olduğu veya saklanmak üzere işaretlendiği tüm verilerin sunucuyla senkronize edilir. Veriler okunurken veya yazılırken, aracın kullanılan verilerdir. Daha sonra Firebase istemcisi bu verileri uzaktan veritabanı sunucuları ve diğer müşterilerle .

Sonuç olarak, veritabanına yapılan tüm yazmalar yerel etkinlikleri hemen, tüm etkileşimlerde kullanılabilir. Yani uygulamanız yanıt vermeye devam ediyor ağ gecikmesinden veya bağlantıdan bağımsız şekilde değişiklik gösterir.

Bağlantı yeniden kurulduğunda uygulamanız uygun veri kümesini alır Böylece istemcinin, istemcinin bunu gerçekleştirmesine gerek kalmadan mevcut sunucu durumuyla herhangi bir özel kod yazabilirsiniz.

Çevrimdışı davranışlara biraz daha değineceğiz. Online ve çevrimdışı özellikler hakkında daha fazla bilgi edinin.

Sonraki adımlar