অ্যান্ড্রয়েডে ডেটা পড়ুন এবং লিখুন

এই নথিতে ফায়ারবেস ডেটা পড়া এবং লেখার মূল বিষয়গুলি অন্তর্ভুক্ত রয়েছে।

Firebase তথ্য একটি লেখা হয় FirebaseDatabase রেফারেন্স এবং রেফারেন্স একটি অ্যাসিঙ্ক্রোনাস শ্রোতা যুক্ত করে উদ্ধার করা হয়। শ্রোতা ডেটার প্রাথমিক অবস্থার জন্য একবার ট্রিগার হয় এবং আবার যে কোনও সময় ডেটা পরিবর্তিত হয়।

(Alচ্ছিক) প্রোটোটাইপ এবং ফায়ারবেস লোকাল এমুলেটর স্যুট দিয়ে পরীক্ষা করুন

আপনার অ্যাপ কিভাবে রিয়েলটাইম ডাটাবেস থেকে পড়ে এবং লেখায় সে সম্পর্কে কথা বলার আগে, আসুন একটি টুল সেট করি যা আপনি প্রোটোটাইপ করতে এবং রিয়েলটাইম ডেটাবেস কার্যকারিতা পরীক্ষা করতে ব্যবহার করতে পারেন: ফায়ারবেস লোকাল এমুলেটর স্যুট। আপনি যদি বিভিন্ন ডেটা মডেল চেষ্টা করে থাকেন, আপনার নিরাপত্তা বিধিগুলি অপ্টিমাইজ করছেন, অথবা ব্যাক-এন্ডের সাথে ইন্টারঅ্যাক্ট করার সবচেয়ে সাশ্রয়ী উপায় খুঁজে বের করার জন্য কাজ করছেন, তাহলে লাইভ সার্ভিস স্থাপন না করে স্থানীয়ভাবে কাজ করতে পারা একটি চমৎকার ধারণা হতে পারে।

একটি রিয়েলটাইম ডাটাবেস এমুলেটর স্থানীয় এমুলেটর স্যুটের অংশ, যা আপনার অ্যাপকে আপনার ইমুলেটেড ডাটাবেস সামগ্রী এবং কনফিগারের সাথে সাথে optionচ্ছিকভাবে আপনার অনুকরণকৃত প্রকল্প সম্পদ (ফাংশন, অন্যান্য ডেটাবেস এবং সুরক্ষা নিয়ম) এর সাথে যোগাযোগ করতে সক্ষম করে।

রিয়েলটাইম ডাটাবেস এমুলেটর ব্যবহার করে মাত্র কয়েকটি ধাপ জড়িত:

  1. এমুলেটরের সাথে সংযোগ স্থাপনের জন্য আপনার অ্যাপের টেস্ট কনফিগারে কোডের একটি লাইন যোগ করা।
  2. আপনার স্থানীয় প্রকল্প ডিরেক্টরি রুট, দৌড়ানো থেকে firebase emulators:start
  3. রিয়েলটাইম ডাটাবেস প্ল্যাটফর্ম SDK ব্যবহার করে আপনার অ্যাপের প্রোটোটাইপ কোড থেকে কল করা, অথবা রিয়েলটাইম ডেটাবেস REST API ব্যবহার করে।

বিস্তারিত রিয়েলটাইম ডাটাবেস এবং ক্লাউড কার্যাবলী জড়িত, walkthrough পাওয়া যায়। এছাড়াও আপনি কটাক্ষপাত থাকা উচিত স্থানীয় এমুলেটর সুইট ভূমিকা

একটি ডাটাবেস রেফারেন্স পান

পড়তে বা লিখতে তথ্য ডাটাবেস থেকে, আপনি একটি দৃষ্টান্ত প্রয়োজন DatabaseReference :

জাভা

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

কোটলিন+কেটিএক্স

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

ডেটা লিখুন

মৌলিক লেখার ক্রিয়াকলাপ

মৌলিক লেখার অপারেশন জন্য, আপনি ব্যবহার করতে পারেন setValue() একটি নির্দিষ্ট রেফারেন্স এ ডেটা সংরক্ষণ, যে পথ যে কোনো বিদ্যমান তথ্য প্রতিস্থাপন। আপনি এই পদ্ধতিটি ব্যবহার করতে পারেন:

  • পাসের প্রকারগুলি যা উপলব্ধ JSON প্রকারের সাথে সামঞ্জস্যপূর্ণ:
    • String
    • Long
    • Double
    • Boolean
    • Map<String, Object>
    • List<Object>
  • একটি কাস্টম জাভা অবজেক্ট পাস করুন, যদি ক্লাসটি সংজ্ঞায়িত করে তবে এটি একটি ডিফল্ট কনস্ট্রাক্টর যা কোনও যুক্তি নেয় না এবং সম্পত্তিগুলি বরাদ্দ করার জন্য পাবলিক গেটার থাকে।

যদি আপনি একটি জাভা বস্তু ব্যবহার করেন, আপনার বস্তুর বিষয়বস্তু স্বয়ংক্রিয়ভাবে একটি নেস্টেড ফ্যাশনে শিশু অবস্থানে ম্যাপ করা হয়। একটি জাভা অবজেক্ট ব্যবহার করা সাধারণত আপনার কোডকে আরও পাঠযোগ্য এবং বজায় রাখা সহজ করে তোলে। উদাহরণস্বরূপ, যদি আপনি একটি প্রাথমিক ব্যবহারকারী প্রোফাইলের সাথে একটি অ্যাপ্লিকেশন, তাহলে আপনার User অবজেক্ট হিসেবে চেহারা হতে পারে নিম্নরূপ:

জাভা

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

}

কোটলিন+কেটিএক্স

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

আপনার সাথে একটি ব্যবহারকারী যোগ করতে পারেন setValue() নিম্নরূপ:

জাভা

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

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

কোটলিন+কেটিএক্স

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

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

ব্যবহার setValue() এই ভাবে কোন সন্তান নোড সহ নির্দিষ্ট অবস্থানে ডেটা, মুছে ফেলা হয়। যাইহোক, আপনি এখনও পুরো বস্তুর পুনর্লিখন ছাড়াই একটি শিশুকে আপডেট করতে পারেন। আপনি যদি ব্যবহারকারীদের তাদের প্রোফাইল আপডেট করার অনুমতি দিতে চান তবে আপনি নিম্নরূপ ব্যবহারকারীর নাম আপডেট করতে পারেন:

জাভা

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

কোটলিন+কেটিএক্স

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

ডেটা পড়ুন

ক্রমাগত শ্রোতাদের সাথে ডেটা পড়ুন

একটি পাথ এ ডেটা পড়তে এবং পরিবর্তন শোনার জন্য, ব্যবহার addValueEventListener() একটি যোগ করার জন্য পদ্ধতি ValueEventListener একটি থেকে DatabaseReference

শ্রোতা ইভেন্ট কলব্যাক সাধারণ ব্যবহার
ValueEventListener onDataChange() একটি পথের সম্পূর্ণ বিষয়বস্তুর পরিবর্তনের জন্য পড়ুন এবং শুনুন।

আপনি ব্যবহার করতে পারেন onDataChange() , একজন প্রদত্ত পথ এ বিষয়বস্তুর একটি স্ট্যাটিক স্ন্যাপশট পড়তে পদ্ধতি হিসাবে তারা ইভেন্টের জন্য নির্ধারিত সময়ে অস্তিত্ব। এই পদ্ধতিটি একবার ট্রিগার করা হয় যখন শ্রোতা সংযুক্ত থাকে এবং প্রতিবার শিশু সহ ডেটা পরিবর্তন হয়। ইভেন্ট কলব্যাক একটি স্ন্যাপশট পাস করা হয় যেখানে শিশু ডেটা সহ সেই স্থানে সমস্ত ডেটা থাকে। যদি কোন তথ্য নেই, স্ন্যাপশট ফিরে আসবে false আপনি কল যখন exists() এবং null আপনি কল যখন getValue() এটা।

নিম্নলিখিত উদাহরণটি একটি সামাজিক ব্লগিং অ্যাপ্লিকেশন প্রদর্শন করে যা ডাটাবেস থেকে একটি পোস্টের বিবরণ পুনরুদ্ধার করে:

জাভা

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

কোটলিন+কেটিএক্স

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)

শ্রোতা একটি পায় DataSnapshot যে ইভেন্টের জন্য নির্ধারিত সময়ে ডাটাবেসের মধ্যে নির্দিষ্ট অবস্থানে তথ্য রয়েছে। কলিং getValue() একটি স্ন্যাপশট আয় ডেটার জাভা বস্তুর উপস্থাপনা। কোন তথ্য অবস্থানে বিদ্যমান, কলিং তাহলে getValue() আয় null

এই উদাহরণে, ValueEventListener এছাড়াও সংজ্ঞায়িত onCancelled() পদ্ধতি যে যদি পঠিত বাতিল করা হয়েছে বলা হয়। উদাহরণস্বরূপ, যদি ক্লায়েন্টের ফায়ারবেস ডাটাবেস অবস্থান থেকে পড়ার অনুমতি না থাকে তবে একটি পাঠ বাতিল করা যেতে পারে। এই পদ্ধতি একটি পাস করা হয়েছে DatabaseError বস্তুর ইঙ্গিত কেন ব্যর্থতা ঘটেছে।

একবার ডেটা পড়ুন

Get () ব্যবহার করে একবার পড়ুন

SDK ডেটাবেস সার্ভারের সাথে ইন্টারঅ্যাকশন পরিচালনা করার জন্য ডিজাইন করা হয়েছে আপনার অ্যাপ অনলাইন বা অফলাইন।

সাধারণত, আপনি ব্যবহার করা উচিত ValueEventListener কৌশল উপরে বর্ণিত ব্যাকএন্ড থেকে তথ্য আপডেট এর বিজ্ঞপ্তি পেতে ডেটা পড়তে। শ্রোতার কৌশলগুলি আপনার ব্যবহার এবং বিলিং হ্রাস করে এবং আপনার ব্যবহারকারীদের অনলাইন এবং অফলাইনে যাওয়ার সময় সর্বোত্তম অভিজ্ঞতা দিতে অপ্টিমাইজ করা হয়।

আপনি শুধুমাত্র একবার ডাটা প্রয়োজন হয়, তাহলে আপনি ব্যবহার করতে পারেন get() ডাটাবেস থেকে তথ্য একটি স্ন্যাপশট জন্য। যদি কোন কারণে get() সার্ভার মান ফেরত পাঠাতে অক্ষম, ক্লায়েন্ট স্থানীয় সংগ্রহস্থল ক্যাশে অনুসন্ধানের এবং একটি ত্রুটি আসতে যদি মান এখনও পাওয়া যায় নি হবে।

অপ্রয়োজনীয় ব্যবহার get() কর্মক্ষমতা হ্রাস, যা উপরে দেখানো একটি রিয়েলটাইম শ্রোতা ব্যবহার করে প্রতিরোধ করা যায় জন্য ব্যান্ডউইথে ও নেতৃত্ব ব্যবহার বৃদ্ধি করতে পারেন।

জাভা

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

কোটলিন+কেটিএক্স

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

শ্রোতা ব্যবহার করে একবার পড়ুন

কিছু ক্ষেত্রে আপনি সার্ভারে আপডেট করা মান চেক করার পরিবর্তে স্থানীয় ক্যাশে থেকে মানটি অবিলম্বে ফেরত দিতে চান। সেসব ক্ষেত্রে আপনি ব্যবহার করতে পারেন addListenerForSingleValueEvent অবিলম্বে স্থানীয় ডিস্ক ক্যাশে থেকে ডেটা জন্য।

এটি এমন ডেটার জন্য উপযোগী যা শুধুমাত্র একবার লোড করা প্রয়োজন এবং ঘন ঘন পরিবর্তন হবে না বা সক্রিয় শোনার প্রয়োজন হবে না। উদাহরণস্বরূপ, আগের উদাহরণের ব্লগিং অ্যাপ ব্যবহারকারীর প্রোফাইল লোড করার জন্য এই পদ্ধতি ব্যবহার করে যখন তারা একটি নতুন পোস্ট লেখা শুরু করে।

ডেটা আপডেট করা বা মুছে ফেলা

নির্দিষ্ট ক্ষেত্র আপডেট করুন

একযোগে অন্যান্য শিশু নোড মুছে যাওয়ার ছাড়া একটি নোডের নির্দিষ্ট শিশুদের লিখতে, ব্যবহার updateChildren() পদ্ধতি।

যখন কলিং updateChildren() , আপনি কী-এর জন্য একটি পাথ নির্দিষ্ট করে নিম্ন পর্যায়ের শিশু মান আপডেট করতে পারেন। তথ্য একাধিক অবস্থান মধ্যে সংরক্ষিত হয় তাহলে ভাল আকার পরিবর্তন করতে, আপনি ব্যবহার যে ডেটা সমস্ত উদাহরণ আপডেট করতে পারেন তথ্য পাখা-আউট । উদাহরণস্বরূপ, একটি সামাজিক ব্লগিং অ্যাপ্লিকেশন একটি থাকতে পারে Post ভালো শ্রেণী:

জাভা

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

কোটলিন+কেটিএক্স

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

একটি পোস্ট তৈরি করতে এবং একই সাথে সাম্প্রতিক ক্রিয়াকলাপ ফিড এবং পোস্ট করা ব্যবহারকারীর কার্যকলাপ ফিডে আপডেট করার জন্য, ব্লগিং অ্যাপ্লিকেশনটি এইরকম কোড ব্যবহার করে:

জাভা

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

কোটলিন+কেটিএক্স

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

এই উদাহরণটিতে ব্যবহারসমূহ push() এ সকল ব্যবহারকারীর জন্য পোস্টগুলি থাকা নোড একটি পোস্ট তৈরি করতে /posts/$postid এবং একই সঙ্গে কী পুনরুদ্ধার getKey() । কী তারপর ব্যবহারকারীর পোস্টে একটি দ্বিতীয় এন্ট্রি তৈরি করতে ব্যবহার করা যেতে পারে /user-posts/$userid/$postid

এই পাথ ব্যবহার করে, আপনি একটি একক কলের সাথে তাদেরকে JSON গাছ একাধিক অবস্থানে যুগপত আপডেট সম্পাদন করতে পারবেন updateChildren() যেমন কিভাবে এই উদাহরণে উভয় স্থানে নতুন পোস্ট তৈরি করে যেমন। এইভাবে করা যুগপত আপডেটগুলি পারমাণবিক: হয় সব আপডেট সফল হয় অথবা সব আপডেট ব্যর্থ হয়।

একটি সমাপ্তি কলব্যাক যোগ করুন

আপনি কখন আপনার ডেটা প্রতিশ্রুতিবদ্ধ হয়েছে তা জানতে চাইলে, আপনি একটি সম্পূর্ণ শ্রোতা যোগ করতে পারেন। উভয় setValue() এবং updateChildren() একটি ঐচ্ছিক সমাপ্তির শ্রোতা যখন লেখার সফলভাবে ডাটাবেসের সংঘটিত হয়েছে বলা হয় যে নিতে। যদি কলটি অসফল হয়, তাহলে শ্রোতা একটি ত্রুটি বস্তু প্রেরণ করে যা নির্দেশ করে কেন ব্যর্থতা ঘটেছে।

জাভা

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

কোটলিন+কেটিএক্স

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

ডেটা মুছুন

ডিলিট ডেটাতে সহজ উপায় কল হয় removeValue() যে তথ্য অবস্থানে একটি রেফারেন্সে।

এছাড়াও আপনি নির্দিষ্ট করে মুছে দিতে পারেন null যেমন অন্য লেখ অপারেশন জন্য মান হিসাবে setValue() বা updateChildren() । আপনার সাথে এই কৌশল ব্যবহার করতে পারেন updateChildren() একটি একক API কল একাধিক শিশু মুছে দিন।

শ্রোতাদের বিচ্ছিন্ন করুন

Callbacks কল করে সরিয়ে ফেলা হয় removeEventListener() আপনার Firebase ডাটাবেসের রেফারেন্সে পদ্ধতি।

যদি কোনো শ্রোতা কোনো ডেটা লোকেশনে একাধিকবার যোগ করা হয়, তাহলে একে একে প্রতিটি ইভেন্টের জন্য একাধিকবার বলা হয়, এবং এটি সম্পূর্ণরূপে মুছে ফেলার জন্য আপনাকে একই সংখ্যক বার আলাদা করতে হবে।

কলিং removeEventListener() একটি পিতা বা মাতা শ্রোতা স্বয়ংক্রিয়ভাবে তার সন্তানের নোড নিবন্ধিত শ্রোতাকে মুছে যায় না করুন; removeEventListener() যে কোনো শিশু শ্রোতাকে আহ্বান করা আবশ্যক কলব্যাক মুছে ফেলার জন্য।

লেনদেন হিসাবে ডেটা সংরক্ষণ করুন

যখন ডেটা আছে যা বৃদ্ধিজনিত কাউন্টারে যেমন সমবর্তী পরিবর্তন, দ্বারা ক্ষতিগ্রস্ত হতে পারে সঙ্গে কাজ, আপনি একটি ব্যবহার করতে পারেন লেনদেন অপারেশন । আপনি এই ক্রিয়াকলাপটিকে দুটি যুক্তি দেন: একটি আপডেট ফাংশন এবং একটি alচ্ছিক সমাপ্তি কলব্যাক। আপডেট ফাংশন একটি যুক্তি হিসাবে ডেটার বর্তমান অবস্থা নেয় এবং আপনি যে নতুন কাঙ্ক্ষিত অবস্থা লিখতে চান তা ফেরত দেয়। যদি আপনার নতুন মান সফলভাবে লেখার আগে অন্য ক্লায়েন্ট লোকেশনে লেখেন, তাহলে আপনার আপডেট ফাংশনটিকে নতুন বর্তমান মান দিয়ে আবার বলা হয় এবং লেখাটি আবার চেষ্টা করা হয়।

উদাহরণস্বরূপ, উদাহরণস্বরূপ সামাজিক ব্লগিং অ্যাপে, আপনি ব্যবহারকারীদের পোস্টগুলিকে তারকা এবং তারকাচিহ্নিত করার অনুমতি দিতে পারেন এবং একটি পোস্ট কতগুলি তারকা পেয়েছে তার হিসাব রাখতে পারেন:

জাভা

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

কোটলিন+কেটিএক্স

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

লেনদেন ব্যবহার করা তারকা গণনাকে ভুল হতে বাধা দেয় যদি একাধিক ব্যবহারকারী একই পোস্টে একই সময়ে স্টার করে অথবা ক্লায়েন্টের কাছে বাসি ডেটা থাকে। যদি লেনদেন প্রত্যাখ্যান করা হয়, সার্ভার ক্লায়েন্টকে বর্তমান মান ফেরত দেয়, যা আপডেট করা মান দিয়ে আবার লেনদেন চালায়। লেনদেন গ্রহণ না করা পর্যন্ত বা পুনরাবৃত্তি না হওয়া পর্যন্ত অনেক চেষ্টা করা হয়েছে।

পারমাণবিক সার্ভার-পার্শ্ব বৃদ্ধি

উপরের ব্যবহারের ক্ষেত্রে আমরা ডাটাবেসে দুটি মান লিখছি: যে ব্যবহারকারীর পোস্টটি স্টার/আনস্টার করে তার আইডি এবং বর্ধিত স্টার কাউন্ট। যদি আমরা ইতিমধ্যেই জানি যে ব্যবহারকারী পোস্টে অভিনয় করছেন, আমরা একটি লেনদেনের পরিবর্তে একটি পারমাণবিক বৃদ্ধি প্রক্রিয়া ব্যবহার করতে পারি।

জাভা

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

কোটলিন+কেটিএক্স

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

এই কোডটি একটি লেনদেন অপারেশন ব্যবহার করে না, তাই যদি কোনও বিরোধপূর্ণ আপডেট থাকে তবে এটি স্বয়ংক্রিয়ভাবে পুনরায় চালিত হবে না। যাইহোক, যেহেতু ইনক্রিমেন্ট অপারেশন সরাসরি ডাটাবেস সার্ভারে ঘটে, তাই দ্বন্দ্বের কোন সুযোগ নেই।

আপনি যদি অ্যাপ্লিকেশন-নির্দিষ্ট দ্বন্দ্বগুলি সনাক্ত করতে এবং প্রত্যাখ্যান করতে চান, যেমন একটি ব্যবহারকারী একটি পোস্ট যা তারা ইতিমধ্যেই অভিনয় করেছে তার আগে, আপনি সেই ব্যবহারের ক্ষেত্রে কাস্টম নিরাপত্তা নিয়ম লিখুন।

অফলাইনে ডেটা নিয়ে কাজ করুন

যদি কোন ক্লায়েন্ট তার নেটওয়ার্ক সংযোগ হারিয়ে ফেলে, আপনার অ্যাপ সঠিকভাবে কাজ চালিয়ে যাবে।

ফায়ারবেস ডাটাবেসের সাথে সংযুক্ত প্রতিটি ক্লায়েন্ট যে কোন ডেটার নিজস্ব অভ্যন্তরীণ সংস্করণ বজায় রাখে যার উপর শ্রোতারা ব্যবহার করা হচ্ছে বা যাকে সার্ভারের সাথে সিঙ্ক করার জন্য ফ্ল্যাগ করা হয়েছে। যখন ডেটা পড়া বা লেখা হয়, ডেটার এই স্থানীয় সংস্করণটি প্রথমে ব্যবহার করা হয়। ফায়ারবেস ক্লায়েন্ট তখন রিমোট ডাটাবেস সার্ভার এবং অন্যান্য ক্লায়েন্টদের সাথে "সেরা-প্রচেষ্টা" ভিত্তিতে সেই ডেটা সিঙ্ক্রোনাইজ করে।

ফলস্বরূপ, সার্ভারের সাথে যেকোনো মিথস্ক্রিয়ার আগে, সমস্ত ডাটাবেসে স্থানীয় ইভেন্টগুলিকে অবিলম্বে ট্রিগার করে। এর মানে হল যে আপনার অ্যাপটি নেটওয়ার্ক লেটেন্সি বা কানেক্টিভিটি নির্বিশেষে প্রতিক্রিয়াশীল থাকে।

একবার কানেক্টিভিটি পুনরায় প্রতিষ্ঠিত হয়ে গেলে, আপনার অ্যাপটি ইভেন্টের উপযুক্ত সেট গ্রহণ করে যাতে ক্লায়েন্ট কোন সার্ভার স্টেট এর সাথে সিঙ্ক করে, কোন কাস্টম কোড না লিখে।

আমরা অফলাইনে আচরণ সম্পর্কে আরো আলোচনা করব আরও জানুন সম্পর্কে অনলাইন ও অফলাইন ক্ষমতা

পরবর্তী পদক্ষেপ