FirebaseRecyclerAdapter的问题,删除数据时出现空对象引用

时间:2018-11-11 14:08:30

标签: android firebase firebase-realtime-database recycler-adapter firebaseui

Firebase数据库的显示工作正常,但是当我尝试从数据库中删除项目时,应用程序崩溃,尽管发生了删除。在字符串中的空对象引用上写:

String postDescription = dataSnapshot.child("desc").getValue().toString();

这是我的代码:

public class PostFragment extends Fragment {

private RecyclerView recyclerPost;

private DatabaseReference postReference;

private View view;
private LinearLayoutManager layoutManager;

public PostFragment() {
}

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

    view = inflater.inflate(R.layout.fragment_post, container, false);

    recyclerPost = view.findViewById(R.id.recycler_post);

    postReference = FirebaseDatabase.getInstance().getReference().child("Posts");
    postReference.keepSynced(true);

    layoutManager = new LinearLayoutManager(getContext());
    layoutManager.setReverseLayout(true);
    layoutManager.setStackFromEnd(true);
    recyclerPost.setHasFixedSize(true);
    recyclerPost.setLayoutManager(layoutManager);

    return view;
}

@Override
public void onStart() {
    super.onStart();
    Query query = postReference.orderByChild("timestamp");

    FirebaseRecyclerOptions<Posts> options =
            new FirebaseRecyclerOptions.Builder<Posts>()
                    .setQuery(query, Posts.class)
                    .build();

    FirebaseRecyclerAdapter adapter = new FirebaseRecyclerAdapter<Posts, PostViewHolder>(options) {

        @Override
        protected void onBindViewHolder(@NonNull final PostViewHolder holder, int position, @NonNull final Posts model) {

            final String postId = getRef(position).getKey();
            postReference.child(postId).addValueEventListener(new ValueEventListener() {
                @Override
                public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                    String postDescription = dataSnapshot.child("desc").getValue().toString();
                    holder.postDesc.setText(postDescription);                   
                }

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

                }
            });

            holder.delBtn.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    postReference.child(postId).removeValue();
                }
            });


        }

        @NonNull
        @Override
        public PostViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int position) {
            View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.blog_item, viewGroup, false);
            return new PostViewHolder(view);
        }

    };

    adapter.startListening();
    recyclerPost.setAdapter(adapter);
}

public class PostViewHolder extends RecyclerView.ViewHolder {

    private TextView postDesc;
    private Button delBtn;
    private View view;

    public PostViewHolder(@NonNull View itemView) {
        super(itemView);
        view = itemView;
        postDesc = (TextView) view.findViewById(R.id.post_description); 
        delBtn = (Button) view.findViewById(R.id.del_post_btn);

    }
}
}

请告诉我解决此问题的方法。

2 个答案:

答案 0 :(得分:0)

您可以尝试以下操作:

#include <linux/module.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/i2c.h>
#include <linux/i2c-id.h>
#include <linux/videodev2.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/log2.h>

#include <media/v4l2-ioctl.h>
#include <media/v4l2-device.h>
#include <media/v4l2-chip-ident.h>
#include <media/v4l2-subdev.h>
#include <media/soc_camera.h>

#include "adv7403_regs.h"

#define DRIVER_NAME "adv7403"

struct adv7403_state {
          struct v4l2_subdev subdev;
};

static __devinit int adv7403_probe(struct i2c_client *client,
                              const struct i2c_device_id *id)
{
          struct adv7403_state *state;
          int ret;

          /* Check if the adapter supports the needed features */
          if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
                    return -EIO;

          v4l_info(client, "chip found @ 0x%02x (%s)\n",
                              client->addr << 1, client->adapter->name);

          state = kzalloc(sizeof(struct adv7403_state), GFP_KERNEL);
          if (state == NULL) {
                    ret = -ENOMEM;
                    goto err;
          }
        else{
                    printk(KERN_ERR DRIVER_NAME ": Detected %d\n");
          }

err:
          printk(KERN_ERR DRIVER_NAME ": Failed to probe: %d\n", ret);
          return ret;
}


static __devexit int adv7403_remove(struct i2c_client *client)
{
          struct v4l2_subdev *sd = i2c_get_clientdata(client);

          v4l2_device_unregister_subdev(sd);
          return 0;
}

static const struct i2c_device_id adv7403_id[] = {
          {DRIVER_NAME, 0},
          {},
};

MODULE_DEVICE_TABLE(i2c, adv7403_id);

static struct i2c_driver adv7403_driver = {
          .driver = {
                    .owner          = THIS_MODULE,
                    .name          = DRIVER_NAME,
          },
        .probe                    = adv7403_probe,
        .remove                    = adv7403_remove,
          .id_table          = adv7403_id
};

static int __init adv7403_mod_init(void)
{
          printk(" ADV7403 Video Decoder Device Driver inserted to kernel \n");
          return i2c_add_driver(&adv7403_driver);
}

static void __exit adv7403_mod_exit(void)
{
        printk(" ADV7403 Video Decoder Device Driver removed from kernel \n");
          i2c_del_driver(&adv7403_driver);
}

module_init(adv7403_mod_init);
module_exit(adv7403_mod_exit);

您可以使用方法 postReference.child(postId).addValueEventListener(new ValueEventListener() { @Override public void onDataChange(@NonNull DataSnapshot dataSnapshot) { if(dataSnapshot.exists()){ String postDescription = dataSnapshot.child("desc").getValue().toString(); holder.postDesc.setText(postDescription); } } @Override public void onCancelled(@NonNull DatabaseError databaseError) { } });

  

exists()

     

如果快照包含非空值,则返回true。

它将检查数据快照是否在 数据库,如果它不在数据库中,那么您可以添加小吃店或烤面包。

更多信息在这里:

https://firebase.google.com/docs/reference/android/com/google/firebase/database/DataSnapshot#exists()

答案 1 :(得分:0)

每次将帖子添加到适配器/列表视图时,您现在都在addValueEventListener中使用onBindViewHolder创建了一个侦听器。该监听器从数据库获取值,然后继续监听更改,直到将其删除。由于您永远不会删除这些侦听器,因此随着时间的推移它们会加起来,事情可能会不同步。

最简单的解决方案是使用addListenerForSingleValueEvent

@Override
protected void onBindViewHolder(@NonNull final PostViewHolder holder, int position, @NonNull final Posts model) {

    final String postId = getRef(position).getKey();
    postReference.child(postId).addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
            String postDescription = dataSnapshot.child("desc").getValue().toString();
            holder.postDesc.setText(postDescription);                   
        }

        @Override
        public void onCancelled(@NonNull DatabaseError databaseError) {
            throw databaseError.toException(); // don't ignore errors
        }
    });

使用addListenerForSingleValueEvent时,onDataChange首次触发后,监听器即被删除。