עבוד עם רשימות נתונים באנדרואיד

מסמך זה מכסה עבודה עם רשימות נתונים ב- Firebase. כדי ללמוד את יסודות הקריאה והכתיבה נתונים Firebase לראות נתונים לקרוא ולכתוב על אנדרואיד .

קבל מסד נתונים

כדי לקרוא נתונים כתיבה ממסד הנתונים, אתה צריך מופע של DatabaseReference :

ג'אווה

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

Kotlin + KTX

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

קרא וכתוב רשימות

הוסף לרשימת הנתונים

השתמש push() השיטה לצרף נתונים לרשימה ביישומים מרובים משתמשים. push() שיטה מייצר מפתח ייחודי בכל פעם ילד חדש מתווסף התייחסות Firebase שצוין. על ידי שימוש במקשים שנוצרו אוטומטית עבור כל אלמנט חדש ברשימה, מספר לקוחות יכולים להוסיף ילדים לאותו מיקום בו זמנית ללא התנגשויות כתיבה. המפתח הייחודי שנוצר על ידי push() מבוסס על חותמת, כך פריטי רשימה מסודרים באופן אוטומטי לפי סדר כרונולוגי.

אתה יכול להשתמש התייחסות לנתונים החדשים שהוחזרו על ידי push() השיטה כדי לקבל את הערך של נתון מפתח או סט שנוצר באופן האוטומטי של הילדים לילד. שיחות getKey() על push() הפניה מחזירה את הערך של המפתח שנוצר באופן אוטומטי.

אתה יכול להשתמש במפתחות שנוצרו אוטומטית כדי לפשט את רידוד מבנה הנתונים שלך. לקבלת מידע נוסף, ראה אוהד-אאוט נתונים לדוגמה .

האזינו לאירועים של ילדים

כשאתה עובד עם רשימות, היישום שלך צריך להקשיב לאירועי ילדים ולא לאירועי הערך המשמשים לאובייקטים בודדים.

אירועי ילד מופעלים בתגובה לפעולות ספציפיות שקורות לילדים של צומת מניתוח כגון ילד חדש שנוסף בעקבות push() שיטה או ילד מתעדכן דרך updateChildren() השיטה. כל אחד מאלה יחד יכול להיות שימושי להאזנה לשינויים בצומת ספציפי במסד נתונים.

כדי להאזין לאירועי הילד על DatabaseReference , לצרף ChildEventListener :

מַאֲזִין התקשרות חוזרת לאירוע שימוש אופייני
ChildEventListener onChildAdded() אחזר רשימות פריטים או האזן לתוספות לרשימת פריטים. החזרה זו מופעלת פעם אחת עבור כל ילד קיים ואז שוב בכל פעם שמתווסף ילד חדש לנתיב שצוין. DataSnapshot עבר המאזין מכיל את הנתונים של הילד החדש.
onChildChanged() האזן לשינויים בפריטים ברשימה. אירוע זה הופעל בכל פעם שצומת ילד שונה, כולל שינויים בצאצאי צומת הילד. DataSnapshot עבר המאזין אירוע המכיל את הנתונים המעודכנים עבור הילד.
onChildRemoved() האזן לפריטים שהוסרו מרשימה. DataSnapshot עבר התקשרות אירוע המכיל את הנתונים עבור הילד שהוסרו.
onChildMoved() האזן לשינויים בסדר הפריטים ברשימה שהוזמנה. אירוע זה מופעל בכל פעם onChildChanged() התקשרות מופעלת על ידי עדכון הגורמת סידור מחדש של הילד. הוא משמש עם נתונים מסודרים כך orderByChild או orderByValue .

לדוגמה, אפליקציה לבלוגים חברתיים עשויה להשתמש בשיטות אלה יחד כדי לפקח על הפעילות בתגובות הפוסט, כמוצג להלן:

ג'אווה

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

Kotlin + KTX

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)

הקשב לאירועים ערכיים

בזמן שאנו משתמשים ChildEventListener היא הדרך המומלצת לקרוא רשימות של נתונים, יש מצבים שבהם מצרף ValueEventListener להפניה רשימה שימושית.

צירוף ValueEventListener לרשימת הנתונים יחזיר את הרשימה המלאה של נתונים כסינגל DataSnapshot , אשר תוכל לולאה מעל ל ילדים בודדים גישה.

גם כשיש התאמה אחת לשאילתה, תמונת המצב היא עדיין רשימה; הוא פשוט מכיל פריט יחיד. כדי לגשת לפריט, עליך לעבור על התוצאה:

ג'אווה

// My top posts by number of stars
myTopPostsQuery.addValueEventListener(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
        for (DataSnapshot postSnapshot: dataSnapshot.getChildren()) {
            // TODO: handle the post
        }
    }

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

Kotlin + KTX

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

דפוס זה יכול להיות שימושי כאשר אתה רוצה להביא את כל הילדים של רשימת בפעולה אחת, ולא מקשיב נוספים onChildAdded אירועים.

נתק את המאזינים

התקשרויות חוזרות יוסרו על ידי קריאה removeEventListener() שיטה על הפנייה למאגר הנתונים Firebase שלך.

אם מאזין נוסף מספר פעמים למיקום נתונים, הוא נקרא מספר פעמים לכל אירוע, ועליך לנתק אותו באותו מספר פעמים כדי להסיר אותו לחלוטין.

שיחות removeEventListener() על מאזין ההורה אינו מסיר אוטומטית המאזינים רשום על בלוטות הילד שלה; removeEventListener() חייב גם להיקרא על כול מאזיני ילד להסיר את ההתקשרות.

מיון וסינון נתונים

אתה יכול להשתמש מסד זמן אמת Query בכיתה כדי לאחזר נתונים מסודרים על ידי מפתח, לפי ערך, או לפי ערך של ילד. ניתן גם לסנן את התוצאה הממוינת למספר מסוים של תוצאות או לטווח של מקשים או ערכים.

מיון נתונים

כדי לאחזר נתונים ממוינים, התחל על ידי ציון אחת משיטות ההזמנה לפי קביעת אופן ההזמנה של התוצאות:

שיטה נוֹהָג
orderByChild() סדר סדר לפי הערך של מפתח צאצא שצוין או נתיב ילד מקונן.
orderByKey() הזמינו תוצאות לפי מפתחות ילדים.
orderByValue() סדר תוצאות לפי ערכי ילדים.

אתה יכול להשתמש רק כדי-ידי אחד שיטה בכל פעם. קריאה לשיטת סדר לפי מספר פעמים באותה שאילתה מביאה לשגיאה.

הדוגמה הבאה מדגימה כיצד תוכל לאחזר רשימה של הפוסטים המובילים של המשתמש ממוינים לפי ספירת הכוכבים שלהם:

ג'אווה

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

Kotlin + KTX

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

זה מגדיר שאילתה בשילוב עם המאזין ילד מסנכרן את הלקוח עם של הודעות המשתמשים מנתיב במסד הנתונים מבוססים על זיהוי המשתמש שלהם, מסודרים לפי מספר הכוכבים בכל פוסט קיבלה. טכניקה זו של שימוש מזהי כמפתחות מדד נקרא החוצה אוהד נתונים, אתה יכול לקרוא עוד על אותו מבנה בסיס הנתונים שלך .

הקריאה אל orderByChild() השיטה מייצגת את המפתח לילד להזמין את התוצאות על ידי. במקרה זה, הודעות מסודרות על ידי הערך של כול אחד מהם "starCount" ילד. ניתן להזמין שאילתות גם על ידי ילדים מקוננים, אם יש לך נתונים שנראים כך:

"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",
  }
},

בדוגמה זו, אנו יכולים להזמין אלמנטי הרשימה שלנו על ידי ערכים המקוננים תחת metrics המרכזיים ידי ציון הנתיב ביחס לילד המקוננים שלנו orderByChild() השיחה.

ג'אווה

// Most viewed posts
Query myMostViewedPostsQuery = databaseReference.child("posts")
        .orderByChild("metrics/views");
myMostViewedPostsQuery.addChildEventListener(new ChildEventListener() {
    // TODO: implement the ChildEventListener methods as documented above
    // ...
});

Kotlin + KTX

// Most viewed posts
val myMostViewedPostsQuery = databaseReference.child("posts")
        .orderByChild("metrics/views")
myMostViewedPostsQuery.addChildEventListener(object : ChildEventListener {
    // TODO: implement the ChildEventListener methods as documented above
    // ...
})

לקבלת מידע נוסף על אופן סוגי נתונים אחרים מסודרים, לראות איך נתוני שאילתא הורה .

סינון נתונים

כדי לסנן נתונים, באפשרותך לשלב כל אחת משיטות המגבלה או הטווח עם שיטת סדר לפי בנייה של שאילתה.

שיטה נוֹהָג
limitToFirst() מגדיר את המספר המרבי של פריטים שיחזירו מתחילת רשימת התוצאות שהוזמנה.
limitToLast() מגדיר את המספר המרבי של פריטים להחזיר מסוף רשימת התוצאות שהוזמנה.
startAt() החזר פריטים הגדולים או שווים למפתח או לערך שצוינו, בהתאם לשיטת ההזמנה לפי בחירה.
startAfter() החזר פריטים הגדולים מהמפתח או הערך שצוינו, בהתאם לשיטת ההזמנה לפי בחירה.
endAt() החזר פריטים שקולים או שווים למפתח או לערך שצוינו, בהתאם לשיטת ההזמנה לפי בחירה.
endBefore() החזר פריטים פחות מהמפתח או הערך שצוינו, בהתאם לשיטת ההזמנה לפי בחירה.
equalTo() החזר פריטים שווים למפתח או לערך שצוין, בהתאם לשיטת ההזמנה לפי בחירה.

בניגוד לשיטות סדר לפי סדר, ניתן לשלב מספר פונקציות מגבלה או טווח. לדוגמה, אתה יכול לשלב את startAt() ו endAt() שיטות להגביל את התוצאות טווח ערכים שצוינו.

גם כשיש התאמה אחת לשאילתה, תמונת המצב היא עדיין רשימה; הוא פשוט מכיל פריט יחיד. כדי לגשת לפריט, עליך לעבור על התוצאה:

ג'אווה

// My top posts by number of stars
myTopPostsQuery.addValueEventListener(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
        for (DataSnapshot postSnapshot: dataSnapshot.getChildren()) {
            // TODO: handle the post
        }
    }

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

Kotlin + KTX

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

הגבל את מספר התוצאות

אתה יכול להשתמש limitToFirst() ו limitToLast() שיטות לקביעה מספר מרבי של ילדים להיות מסונכרנים של התקשרות נתון. לדוגמה, אם אתה משתמש limitToFirst() לקבוע תקרה של 100, אתה בתחילה רק לקבל עד 100 onChildAdded() הגיעו ליעדן. אם יש לך פחות מ 100 פריטים מאוחסנים במסד הנתונים Firebase שלך, onChildAdded() שריפות התקשרות עבור כל פריט.

כפריטים לשנות, שתקבל onChildAdded() הגיעו ליעדן עבור הפריטים הקלידו את השאילתא ואת onChildRemoved() הגיעו ליעדן עבור הפריטים להיפלט כך שהיות המספר הכולל ב 100.

הדוגמה הבאה מדגימה כיצד אפליקציית בלוגים לדוגמא מגדירה שאילתה כדי לאחזר רשימה של 100 ההודעות האחרונות של כל המשתמשים:

ג'אווה

// Last 100 posts, these are automatically the 100 most recent
// due to sorting by push() keys
Query recentPostsQuery = databaseReference.child("posts")
        .limitToFirst(100);

Kotlin + KTX

// Last 100 posts, these are automatically the 100 most recent
// due to sorting by push() keys.
databaseReference.child("posts").limitToFirst(100)

דוגמא זו רק מגדירה את שאילתא, כדי בעצם לסנכרן נתונים זה צריך להיות מחובר מאזין .

סנן לפי מפתח או ערך

אתה יכול להשתמש startAt() , startAfter() , endAt() , endBefore() , ולאחר equalTo() כדי לבחור נקודה שרירותית, שהסתיים, ונקודות שקילות לשאילתא. זה יכול להיות שימושי לצורך העמדת נתונים או למציאת פריטים עם ילדים בעלי ערך ספציפי.

כיצד מזמינים נתוני שאילתה

סעיף זה מסביר כיצד הנתונים ממוינים לפי כל סדר-ידי שיטות של Query בכיתה.

orderByChild

בעת שימוש orderByChild() , נתונים המכילים את מפתח הילד שצוין הורה כדלקמן:

  1. ילדים עם null ערך עבור מפתח הבן שצוין לבוא ראשון.
  2. ילדים עם ערך של false עבור מפתח הבן שצוין לבוא הבאים. אם ילדים מרובים יש ערך של false , הם מסודרים lexicographically ידי מפתח.
  3. ילדים עם ערך של true עבור מפתח הבן שצוין לבוא הבאים. אם ילדים מרובים יש ערך של true , הם מסודרים lexicographically ידי מפתח.
  4. ילדים עם ערך מספרי מגיעים אחר כך, ממוינים בסדר עולה. אם למספר ילדים יש את אותו ערך מספרי עבור צומת הילד שצוין, הם ממוינים לפי מפתח.
  5. מיתרים באים אחרי מספרים וממוינים בצורה לקסיקוגרפית בסדר עולה. אם למספר ילדים יש ערך זהה לצומת הילדים שצוין, הם מסודרים באופן לקסיקוגרפי לפי מפתח.
  6. אובייקטים מגיעים אחרונים וממוינים באופן לקסיקוגרפי לפי מקשים בסדר עולה.

orderByKey

בעת שימוש orderByKey() כדי למיין את נתון, נתונים מוחזרים בסדר עולה לפי מפתח.

  1. ילדים עם מפתח שניתן לנתח כמספר שלם של 32 סיביות במקום הראשון, ממוינים בסדר עולה.
  2. ילדים עם ערך מחרוזת כמפתח הם הבאים, ממוינים באופן לקסיקוגרפי בסדר עולה.

orderByValue

בעת שימוש orderByValue() , הילדים מסודרים לפי ערכם. הקריטריונים ההזמנה זהים ב orderByChild() , למעט הערך של הצומת משמש במקום הערך של מפתח הבן שצוין.

הצעדים הבאים