Catch up on everthing we announced at this year's Firebase Summit. Learn more

Android'de Veri Okuma ve Yazma

Bu belge, Firebase verilerini okuma ve yazmayla ilgili temel bilgileri kapsar.

Firebase veriler yazılır FirebaseDatabase referans ve referans için bir zaman uyumsuz dinleyici takılarak alınan. Dinleyici, verilerin ilk durumu için bir kez ve veriler değiştiğinde yeniden tetiklenir.

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

Uygulamanızın Realtime Database'den nasıl okuduğundan ve ona yazdığından bahsetmeden önce, Realtime Database işlevselliğini prototiplemek ve test etmek için kullanabileceğiniz bir dizi araç tanıtalım: Firebase Local Emulator Suite. Farklı veri modelleri deniyor, güvenlik kurallarınızı optimize ediyor veya arka uçla etkileşim kurmanın en uygun maliyetli yolunu bulmaya çalışıyorsanız, canlı hizmetleri dağıtmadan yerel olarak çalışabilmek harika bir fikir olabilir.

Gerçek Zamanlı Veritabanı öykünücüsü, uygulamanızın öykünülmüş veritabanı içeriğiniz ve yapılandırmanızın yanı sıra isteğe bağlı olarak öykünülmüş proje kaynaklarınızla (işlevler, diğer veritabanları ve güvenlik kuralları) etkileşim kurmasını sağlayan Yerel Öykünücü Paketi'nin bir parçasıdır.

Gerçek Zamanlı Veritabanı öykünücüsünü kullanmak yalnızca birkaç adımı içerir:

  1. Öykünücüye bağlanmak için uygulamanızın test yapılandırmasına bir kod satırı ekleme.
  2. Çalışan yerel proje dizininin kökü itibaren firebase emulators:start .
  3. Her zamanki gibi bir Realtime Database platformu SDK'sını veya Realtime Database REST API'sini kullanarak uygulamanızın prototip kodundan çağrı yapma.

Detaylı bir Gerçek Zamanlı Veritabanı ve Bulut İşlevleri içeren örneklerde mevcuttur. Ayrıca bir göz sahip olmalıdır Yerel Emülatörü Suite giriş .

Bir Veritabanı Referansı Alın

Okuma veya yazma verileri veritabanından, sen bir örneğini ihtiyaç için DatabaseReference :

Java

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

Kotlin+KTX

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

Veri yaz

Temel yazma işlemleri

Temel yazma işlemleri için kullanabileceğiniz setValue() o yolda herhangi mevcut verileri değiştirerek, belirli bir referansa verileri kaydetmek. Bu yöntemi aşağıdakiler için kullanabilirsiniz:

  • Kullanılabilir JSON türlerine karşılık gelen türleri aşağıdaki gibi geçirin:
    • String
    • Long
    • Double
    • Boolean
    • Map<String, Object>
    • List<Object>
  • Özel bir Java nesnesini iletin, onu tanımlayan sınıf, hiçbir argüman almayan ve atanacak özellikler için genel alıcılara sahip varsayılan bir kurucuya sahipse.

Bir Java nesnesi kullanırsanız, nesnenizin içeriği otomatik olarak alt konumlara iç içe geçmiş bir şekilde eşlenir. Bir Java nesnesi kullanmak da genellikle kodunuzu daha okunabilir ve bakımı daha kolay hale getirir. Bir temel kullanıcı profiline sahip bir uygulama varsa Örneğin, sizin User olarak görünebilir nesne aşağıdaki gibidir:

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;
    }

}

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.
}

Sen sahip bir kullanıcı ekleyebilir setValue() aşağıdaki gibi:

Java

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

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

Kotlin+KTX

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

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

Kullanılması setValue() bu şekilde tüm alt düğümler dahil belirtilen yerde verileri yazar. Ancak, tüm nesneyi yeniden yazmadan bir alt öğeyi güncelleyebilirsiniz. Kullanıcıların profillerini güncellemelerine izin vermek istiyorsanız, kullanıcı adını aşağıdaki gibi güncelleyebilirsiniz:

Java

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

Kotlin+KTX

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

Verileri oku

Kalıcı dinleyicilerle verileri okuyun

Kullanmak, bir yolda verileri okumak ve değişiklikleri işler için addValueEventListener() bir ekleme yöntemi ValueEventListener bir etmek DatabaseReference .

dinleyici Olay geri arama Tipik kullanım
ValueEventListener onDataChange() Bir yolun tüm içeriğindeki değişiklikleri okuyun ve dinleyin.

Sen kullanabilirsiniz onDataChange() onlar olayın anda varolan gibi, belirli bir yol üstündeki içindekiler statik anlık okunması yöntemi. Bu yöntem, dinleyici eklendiğinde bir kez ve çocuklar dahil veriler her değiştiğinde tekrar tetiklenir. Olay geri çağrısı, alt veriler de dahil olmak üzere o konumdaki tüm verileri içeren bir anlık görüntüden geçirilir. Hiçbir veri yoksa, anlık dönecektir false Aradığınızda exists() ve null Aradığınızda getValue() Üzerinde.

Aşağıdaki örnek, veri tabanından bir gönderinin ayrıntılarını alan bir sosyal blog uygulamasını göstermektedir:

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);

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)

Dinleyici aldığı DataSnapshot etkinliği sırasında veritabanında belirtilen yerde veri içerir. Arayan getValue() anlık getiri verilerin Java nesne temsilini. Hiçbir veri çağırarak, bir konumda bulunuyorsa getValue() döner null .

Bu örnekte, ValueEventListener de tanımlar onCancelled() okuma iptal edilirse adlandırılan yöntem. Örneğin, istemcinin bir Firebase veritabanı konumundan okuma izni yoksa bir okuma iptal edilebilir. Bu yöntem, bir geçirilir DatabaseError arızası meydana neden gösteren bir nesne.

Verileri bir kez oku

get() kullanarak bir kez okuyun

SDK, uygulamanız ister çevrimiçi ister çevrimdışı olsun, veritabanı sunucularıyla etkileşimleri yönetmek için tasarlanmıştır.

Genellikle, kullanması gereken ValueEventListener arka uç verilerine güncellemeleri bildirim almak için veri okumak için teknikler yukarıda açıklanan. Dinleyici teknikleri, kullanımınızı ve faturalandırmanızı azaltır ve kullanıcılarınıza çevrimiçi ve çevrimdışı olduklarında en iyi deneyimi sunmak için optimize edilmiştir.

Eğer sadece bir kez veri gerekiyorsa, kullanabilirsiniz get() veritabanından verilerin anlık görüntüsünü alır. Herhangi bir nedenle için ise get() sunucu değeri döndürmek edemez, istemci yerel depolama önbelleği soruşturma ve değeri hala bulunmazsa bir hata döndürür.

Gereksiz yere kullanılması get() yukarıda gösterildiği gibi gerçek zamanlı bir dinleyici kullanılarak önlenebilir performans kaybı, bant genişliği ve kurşun kullanımı artırabilir.

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()));
        }
    }
});

Kotlin+KTX

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

Dinleyici kullanarak bir kez okuyun

Bazı durumlarda, sunucuda güncellenmiş bir değer olup olmadığını kontrol etmek yerine yerel önbellekteki değerin hemen döndürülmesini isteyebilirsiniz. Bu gibi durumlarda kullanabileceğiniz addListenerForSingleValueEvent hemen yerel disk önbellekten veri almak için.

Bu, yalnızca bir kez yüklenmesi gereken ve sık sık değişmesi beklenmeyen veya etkin dinleme gerektirmeyen veriler için kullanışlıdır. Örneğin, önceki örneklerdeki blog uygulaması, bir kullanıcı yeni bir gönderi yazmaya başladığında profilini yüklemek için bu yöntemi kullanır.

Verileri güncelleme veya silme

Belirli alanları güncelle

Aynı anda kullanmak, diğer alt düğümlerin üzerine yazmadan bir düğümün belirli çocuklarına yazmak için updateChildren() yöntemini.

Çağrılırken updateChildren() , sen anahtarı için bir yolu belirterek düşük seviyede bir alt değerleri güncelleyebilirsiniz. Veri daha iyi ölçekli birden çok yerde saklanıyorsa, kullandığınız verilerin tüm örneklerini güncelleyebilirsiniz veri fan-out . Örneğin, bir sosyal blogging uygulaması bir olabilir Post böyle sınıfını:

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;
    }
}

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
        )
    }
}

Bir gönderi oluşturmak ve onu aynı anda en son etkinlik akışına ve gönderiyi gönderen kullanıcının etkinlik akışına güncellemek için blog uygulaması şuna benzer bir kod kullanır:

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);
}

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)
}

Bu örnek kullanır push() tüm kullanıcılar için mesajları içeren düğümünde bir yayın oluşturma /posts/$postid ve eşzamanlı ile anahtarı almak getKey() . Anahtar o zaman en Kullanıcı mesajlarının ikinci giriş oluşturmak için kullanılabilir /user-posts/$userid/$postid .

Bu yolları kullanarak, tek bir çağrıyla JSON ağacında birden fazla konuma eşzamanlı güncelleştirmeler gerçekleştirebilen updateChildren() böyle bu örnek her iki konumda da yeni yayın oluşturulur nasıl gibi. Bu şekilde yapılan eşzamanlı güncellemeler atomiktir: ya tüm güncellemeler başarılı olur ya da tüm güncellemeler başarısız olur.

Tamamlama Geri Araması Ekle

Verilerinizin ne zaman kaydedildiğini bilmek istiyorsanız, bir tamamlama dinleyicisi ekleyebilirsiniz. Hem setValue() ve updateChildren() yazma başarıyla veritabanına taahhüt edilmiştir çağrılan isteğe bağlı tamamlama dinleyicisi alır. Çağrı başarısız olursa, dinleyiciye hatanın neden oluştuğunu belirten bir hata nesnesi iletilir.

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
                // ...
            }
        });

Kotlin+KTX

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

Verileri sil

Silme verilere en basit yolu aramaktır removeValue() bu verilerin konumun referansı üzerine.

Ayrıca belirterek silebilirsiniz null gibi başka yazma işlemi için değer olarak setValue() veya updateChildren() . Sen ile bu tekniği kullanabilirsiniz updateChildren() tek bir API çağrısında birden fazla çocuk silmek için.

Dinleyicileri ayırın

Callbacks arayarak kaldırılır removeEventListener() sizin Firebase veritabanı Referanstaki yöntemi.

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

Arayan removeEventListener() otomatik olarak alt düğümler üzerinde kayıtlı dinleyicileri kaldırmaz bir ebeveyn dinleyici üzerinde; removeEventListener() ayrıca geri arama kaldırmak için herhangi bir çocuk işleyicilerinizde çağrılmalıdır.

Verileri işlem olarak kaydedin

Böyle sayıcı olarak eşzamanlı değişiklikler, tarafından bozulmuş olabilir verilerle çalışırken, bir kullanabilir işlem operasyonu . Bu işleme iki argüman verirsiniz: bir güncelleme işlevi ve isteğe bağlı bir tamamlama geri çağrısı. güncelleme işlevi, verilerin mevcut durumunu bir argüman olarak alır ve yazmak istediğiniz yeni istenen durumu döndürür. Yeni değeriniz başarıyla yazılmadan önce başka bir istemci konuma yazarsa, güncelleme işleviniz yeni geçerli değerle tekrar çağrılır ve yazma işlemi yeniden denenir.

Örneğin, örnek sosyal blog uygulamasında, kullanıcıların gönderilere yıldız eklemesine ve yıldızları kaldırmasına ve bir gönderinin kaç yıldız aldığını aşağıdaki gibi takip etmesine izin verebilirsiniz:

Java

private void onStarClicked(DatabaseReference postRef) {
    postRef.runTransaction(new Transaction.Handler() {
        @Override
        public Transaction.Result doTransaction(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);
        }
    });
}

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!!)
        }
    })
}

Bir işlemin kullanılması, birden fazla kullanıcının aynı gönderiye aynı anda yıldız vermesi veya istemcinin eski verileri olması durumunda yıldız sayılarının yanlış olmasını önler. İşlem reddedilirse, sunucu, işlemi güncellenen değerle yeniden çalıştıran istemciye mevcut değeri döndürür. Bu, işlem kabul edilene veya çok fazla deneme yapılana kadar tekrarlanır.

Atomik sunucu tarafı artışları

Yukarıdaki kullanım durumunda, veritabanına iki değer yazıyoruz: gönderiye yıldız atan/yıldızı kaldıran kullanıcının kimliği ve artan yıldız sayısı. Kullanıcının gönderiye yıldız eklediğini zaten biliyorsak, işlem yerine atomik bir artış işlemi kullanabiliriz.

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);
}

Kotlin+KTX

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

Bu kod bir işlem işlemi kullanmaz, bu nedenle çakışan bir güncelleme varsa otomatik olarak yeniden çalıştırılmaz. Ancak artırma işlemi doğrudan veritabanı sunucusunda gerçekleştiği için çakışma olasılığı yoktur.

Bir kullanıcının daha önce yıldız verdiği bir gönderiye yıldız eklemesi gibi uygulamaya özel çakışmaları algılamak ve reddetmek istiyorsanız, bu kullanım durumu için özel güvenlik kuralları yazmalısınız.

Verilerle çevrimdışı çalışın

Bir istemci ağ bağlantısını kaybederse uygulamanız düzgün şekilde çalışmaya devam eder.

Bir Firebase veritabanına bağlı her istemci, üzerinde dinleyicilerin kullanıldığı veya sunucuyla senkronize tutulmak üzere işaretlenen herhangi bir verinin kendi dahili sürümünü tutar. Veri okunurken veya yazılırken, önce verinin bu yerel versiyonu kullanılır. Firebase istemcisi daha sonra bu verileri uzak veritabanı sunucuları ve diğer istemcilerle "en iyi çaba" temelinde senkronize eder.

Sonuç olarak, veritabanına yapılan tüm yazma işlemleri, sunucuyla herhangi bir etkileşimden hemen önce yerel olayları tetikler. Bu, uygulamanızın ağ gecikmesinden veya bağlantıdan bağımsız olarak yanıt vermeye devam edeceği anlamına gelir.

Bağlantı yeniden kurulduğunda, uygulamanız uygun olay kümesini alır, böylece istemci herhangi bir özel kod yazmak zorunda kalmadan mevcut sunucu durumuyla eşitlenir.

Biz de çevrimdışı davranış hakkında daha fazla konuşacağız daha yaklaşık çevrimiçi ve çevrimdışı yetenekleri öğrenin .

Sonraki adımlar