如何在Firebase数据库中创建和访问根节点的多个子级?

时间:2018-11-21 12:21:43

标签: android firebase firebase-realtime-database

我需要访问数据库中的books字段。我创建了一个带有recyclerview的片段,用于显示书籍。我在应用程序中需要的是每个用户只能请求一本书。因此,我在根节点下直接创建了另一个节点作为“用户”,但是在添加“用户”节点后,recyclerview无法正常工作。这是添加“用户”后数据库的外观。 Database Snapshot

这是“回收之前”视图: Before Adding users field

这是After RecyclerView: After Adding users field

这是从Firebase数据库导出的json代码。

{
  "books" : {
    "BOOK 1 BY AUTHOR 1": {
      "author" : "Author 1",
      "category" : "CLASSICAL",
      "description" : "",
      "image" : "NO_IMAGE",
      "requested" : "NO",
      "requester" : "NO_ONE",
      "title" : "Book 1"
    },
    "BOOK 2 BY AUTHOR 2" : {
      "author" : "Author 2",
      "category" : "SPIRITUALITY",
      "description" : "",
      "image" : "NO_IMAGE",
      "requested" : "NO",
      "requester" : "NO_ONE",
      "title" : "Book 2"
    },
    "BOOK 3  BY AUTHOR 3" : {
      "author" : "author 3",
      "category" : "ADVENTURE",
      "description" : "",
      "image" : "NO_IMAGE",
      "requested" : "NO",
      "requester" : "NO_ONE",
      "title" : "book 3 "
    }
  },
  "user" : {
    "User1" : {
      "requestedBook" : "no"
    },
    "User2" : {
      "requestedBook" : "yes"
    }
  }
}

`这是片段代码。

    package club.bms.keshav.readersreserve.fragments;

import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.app.Fragment;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ProgressBar;

import com.google.firebase.database.ChildEventListener;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import java.util.ArrayList;
import java.util.List;

import club.bms.keshav.readersreserve.NewBookAttributes;
import club.bms.keshav.readersreserve.R;
import club.bms.keshav.readersreserve.dataHelper.Book;
import club.bms.keshav.readersreserve.dataHelper.BooksAdapter;

public class HomeFragment extends Fragment{
    private static final String TAG = "HomeFragment";
    RecyclerView.LayoutManager mLayoutManager;
    RecyclerView recyclerView;
    List<Book> bookList = new ArrayList<>();
    BooksAdapter adapter;
    private ChildEventListener childEventListener;
    private ProgressBar progressBar;
    private DatabaseReference databaseReference;
    public HomeFragment() {
    }


    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //setHasOptionsMenu(true);
        Log.d(TAG, "onCreate: ");
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable final ViewGroup container, @Nullable Bundle savedInstanceState) {

        View view = inflater.inflate(R.layout.activity_recyclerview_declaration, container, false);
        view.setBackgroundResource(R.color.white);
        Log.d(TAG, "onCreateView: background color set");
        recyclerView = view.findViewById(R.id.recycler_view);
        progressBar = view.findViewById(R.id.progress_bar_home_fragment);
        recyclerView.setVisibility(View.GONE);
        progressBar.setVisibility(View.VISIBLE);
        final Context context = view.getContext();
        FloatingActionButton fab = (FloatingActionButton) view.findViewById(R.id.add_book_fab);

        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startActivity(new Intent(context, NewBookAttributes.class));
            }
        });


        mLayoutManager = new GridLayoutManager(view.getContext(), 2, GridLayoutManager.VERTICAL, false);

        recyclerView.setLayoutManager(mLayoutManager);
        recyclerView.setItemAnimator(new DefaultItemAnimator());
        Log.d(TAG, "onCreateView: recyclerview set without adapter");
         databaseReference = FirebaseDatabase.getInstance().getReference();
         databaseReference.keepSynced(true);
        Log.d(TAG, "onCreateView: database ref created");
        childEventListener = new ChildEventListener() {
            @Override
            public void onChildAdded(@NonNull DataSnapshot dataSnapshot, @Nullable String s) {
                Log.d(TAG, "onChildAdded: ");
                getAllBooks(dataSnapshot, context);
            }

            @Override
            public void onChildChanged(@NonNull DataSnapshot dataSnapshot, @Nullable String s) {
                Log.d(TAG, "onChildChanged: ");
                getAllBooks(dataSnapshot, context);
            }

            @Override
            public void onChildRemoved(@NonNull DataSnapshot dataSnapshot) {
                taskDeletion(dataSnapshot, context);
            }

            @Override
            public void onChildMoved(@NonNull DataSnapshot dataSnapshot, @Nullable String s) {

            }

            @Override
            public void onCancelled(@NonNull DatabaseError databaseError) {

            }
        };
            databaseReference.addChildEventListener(childEventListener);
        Log.d(TAG, "onCreateView: added listener");
         return view;
    }


    private void taskDeletion(DataSnapshot dataSnapshot, Context context) {

        for(DataSnapshot snapshot: dataSnapshot.getChildren())
        {
            Book book = snapshot.getValue(Book.class);
            Book tempBook = new Book();
            tempBook.setAuthor(book.getAuthor());
            tempBook.setTitle(book.getTitle());
            tempBook.setDescription(book.getDescription());
            for(int i=0;i<bookList.size();i++)
            {
                Book b = bookList.get(i);
                if(b.getAuthor().equals(tempBook.getAuthor()) && b.getTitle().equals(tempBook.getTitle()))
                {
                    bookList.remove(i);
                }
            }
        }
        adapter = new BooksAdapter(context, bookList);
        adapter.notifyDataSetChanged();
        recyclerView.setAdapter(adapter);
        Log.d(TAG, "taskDeletion: adapter set");

    }

    private  void getAllBooks(DataSnapshot dataSnapshot, Context context) {

       bookList.clear();
        Book book;
        for(DataSnapshot dataSnapshot1: dataSnapshot.getChildren()) {
            book = dataSnapshot1.getValue(Book.class);
            bookList.add(book);
        }
        adapter = new BooksAdapter(context, bookList);
        recyclerView.setAdapter(adapter);
        progressBar.setVisibility(View.GONE);
        recyclerView.setVisibility(View.VISIBLE);
        Log.d(TAG, "getAllBooks: adapter set");
        }

    @Override
    public void onDetach() {
        super.onDetach();
        databaseReference.removeEventListener(childEventListener);
        Log.d(TAG, "onDetach: removed listener");
    }
}

当我以编程方式添加“用户”节点时,卡片视图变为空,并且在单击卡片视图时会显示NullPointerException。

这是RecyclerView适配器的代码

    package club.bms.keshav.readersreserve.dataHelper;

import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;
import com.google.firebase.storage.FirebaseStorage;
import com.google.firebase.storage.StorageReference;

import java.util.List;

import club.bms.keshav.readersreserve.ConstantFields;
import club.bms.keshav.readersreserve.GlideApp;
import club.bms.keshav.readersreserve.R;
import club.bms.keshav.readersreserve.Single_Book_Activity;

class   RecyclerViewHolder extends RecyclerView.ViewHolder implements View.OnLongClickListener, View.OnClickListener {
    public TextView mAuthor, mTitle, mCategory;
    public ImageView mBookImage;
    //public TextView btn, mauthor;

    private ItemClickListener itemClickListener;

    public RecyclerViewHolder(@NonNull View itemView) {
        super(itemView);
        mAuthor = itemView.findViewById(R.id.textV_book_author);
        mTitle = itemView.findViewById(R.id.textV_book_title);
        mBookImage = itemView.findViewById(R.id.image_for_book);
        mCategory = itemView.findViewById(R.id.textV_book_category);
        //        mStatus = itemView.findViewById(R.id.textV_book_status);
        itemView.setOnClickListener(this);
        itemView.setOnLongClickListener(this);

    }

    public void setmBookImage(String path, final Context context)
    {
        if(path == null || path.equals(ConstantFields.NO_IMAGE))
        {
            Glide.with(context)
                    .load(R.drawable.default_book_cover)
                    .into(mBookImage);
        }
        else{
            StorageReference storageReference = FirebaseStorage.getInstance().getReference().child("images/" + path + "/" + path + " cover");

            GlideApp.with(MyApp.getAppContext())
                    .load(storageReference)
                    .apply(new RequestOptions()
                            .placeholder(R.drawable.rolling_placeholder)
                            .error(R.drawable.default_book_cover)
                    )
                    .into(mBookImage);
        }

    }

    public void setItemClickListener(ItemClickListener itemClickListener) {
        this.itemClickListener = itemClickListener;
    }

    @Override
    public void onClick(View v) {
        itemClickListener.onClick(v, getAdapterPosition(), false);
    }

    @Override
    public boolean onLongClick(View v) {
        itemClickListener.onClick(v, getAdapterPosition(), true);
        return true;
    }
}


public class BooksAdapter extends RecyclerView.Adapter<RecyclerViewHolder> {
    private Context mContext;
    private List<Book> bookList;
    private Book book;
    private ItemClickListener itemClickListener = new ItemClickListener() {
        @Override
        public void onClick(View view, int position, boolean isLongClicked) {
            if (isLongClicked) {

//                AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
//                builder.setMessage("DELETE");
//                AlertDialog dialog = builder.create();
//                dialog.show();

                //DO SOMETHING
            } else {
                Intent intent = new Intent(mContext, Single_Book_Activity.class);
                Bundle args = new Bundle();
                book = bookList.get(position);
                args.putSerializable("bookObject", book);
                intent.putExtras(args);
                mContext.startActivity(intent);
            }
        }
    };

    public BooksAdapter(Context mContext, List<Book> bookList) {
        this.mContext = mContext;
        this.bookList = bookList;
    }

    @NonNull
    @Override
    public RecyclerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.book_list_row, parent, false);
        return new RecyclerViewHolder(itemView);
    }

    @Override
    public void onBindViewHolder(@NonNull RecyclerViewHolder holder, int i) {
        book = bookList.get(i);
        holder.mAuthor.setText(book.getAuthor());
        holder.mTitle.setText(book.getTitle());
        holder.mCategory.setText(book.getCategory());
        holder.setmBookImage(book.getImage(), mContext);
        holder.setItemClickListener(itemClickListener);
    }


    @Override
    public int getItemCount() {
        return bookList.size();
    }

}

还有其他方法可以应用一个用户,一本书规则吗?

将代码更改为

      databaseReference = FirebaseDatabase.getInstance().getReference().child(ConstantFields.CHILD_BOOK);
         bookRef = databaseReference.child(ConstantFields.CHILD_BOOK);
bookRef.addChildEventListener(...);

我可以成功地将书添加到数据库中的所需位置(我不知道如何),但是不会调用OnChildAdded()或onChildChanged()方法,因此进度条将继续无限显示,并且书不显示

2 个答案:

答案 0 :(得分:0)

检查您的数据库参考。

database = FirebaseDatabase.getInstance.getReference 

这将检查整个数据库。

您的子事件侦听器应检查database.child(“ books”)

DatabaseReference db = FirebaseDatabase.getInstance.getReference
dbBooks = db.child("books")
dbBooks.addChildEventListener(new ChildEventListener{
}

答案 1 :(得分:0)

我认为JJ Swart的答案是正确的,这里的问题是您对整个数据的BookReference引用,而不仅仅是对“书籍的数据”的引用。您可以向我们显示您的“例外”信息,以查看将“书”的引用更改为您的错误之后的情况。