【问题标题】:Updating specific firebase field using recyclerview button in android在android中使用recyclerview按钮更新特定的firebase字段
【发布时间】:2020-03-24 08:31:06
【问题描述】:

我正在使用 Java 中的 Android Studio 开发一个投票应用程序,该应用程序使用 RecyclerView 列出 Firebase 数据库中的所有候选人。我可以列出所有候选人,但无法实现投票按钮来仅更新特定候选人的总票数。

数据被选择并显示在RecyclerView 中,如下所示: 候选人信息RecyclerView

我需要每次用户点击投票按钮时,数据库totalVotes 字段更新为+1。

MyAdapter 代码:

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {

    Context context;
    ArrayList <Candidate> candidates;
    private DatabaseReference mDatabase;


    public MyAdapter (Context c, ArrayList<Candidate> p){
        context = c;
        candidates =p;
    }


    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        return new MyViewHolder(LayoutInflater.from(context).inflate(R.layout.cardview, parent, false));
    }
    @Override
    public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
        holder.name.setText(candidates.get(position).getFirstname());
        holder.party.setText(candidates.get(position).getParty());
        holder.category.setText(candidates.get(position).getCategory());
        Picasso.get().load(candidates.get(position).getImageurl()).into(holder.profilepic);

        holder.onClick(position);
    }

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

    class MyViewHolder extends RecyclerView.ViewHolder{

        TextView name, party, category;
        ImageView profilepic;
        Button vote;

        public MyViewHolder(View itemView) {
            super(itemView);
            name = (TextView) itemView.findViewById(R.id.name);
            party = (TextView) itemView.findViewById(R.id.party);
            profilepic = (ImageView) itemView.findViewById(R.id.profilepic);
            category = (TextView) itemView.findViewById(R.id.category);
            vote = (Button) itemView.findViewById(R.id.vote);
        }

        public void onClick(int position){
            vote.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {

                }
            });
        }
    }


}

处理适配器的AllCandidates 类:

private DatabaseReference reference;
    private RecyclerView recyclerView;
    private ArrayList<Candidate> list;
    private ArrayList<CandidateIMage> listimage;
    private MyAdapter adapter;
    private DatabaseReference imagereference;
    FirebaseStorage storage;
    StorageReference storageReference;

    private static final String TAG = "AllCandidates";


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.all_candidates);

        //reference= FirebaseDatabase.getInstance().getReference().child("candidates");
        recyclerView = (RecyclerView) findViewById(R.id.myRecycler);

        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        list = new ArrayList<Candidate>();
        listimage = new ArrayList<CandidateIMage>();

        reference = FirebaseDatabase.getInstance().getReference();

        Query presidentquery = reference.child("candidates").orderByChild("category").equalTo("President");
        presidentquery.addListenerForSingleValueEvent(new ValueEventListener() {
            @Override
            public void onDataChange(DataSnapshot dataSnapshot) {
                if (dataSnapshot.exists()) {
                    for (DataSnapshot dataSnapshot1 : dataSnapshot.getChildren()) {
                        Candidate p = dataSnapshot1.getValue(Candidate.class);
                        //String userId = dataSnapshot1.getKey();
                        //System.out.println("User id to be passed is: "+userId);
                        list.add(p);
                    }
                    adapter = new MyAdapter(AllCandidates.this, list);
                    recyclerView.setAdapter(adapter);
                }
            }
            @Override
            public void onCancelled(DatabaseError databaseError) {
            }
        });
        };
    }

我曾尝试将此代码添加到 vote.onclicklosener 但它不起作用:

public void onClick(final int position){
            postRef = FirebaseDatabase.getInstance().getReference("candidates");
            vote.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    postRef.runTransaction(new Transaction.Handler() {
                        @Override
                        public Transaction.Result doTransaction(MutableData mutableData) {
                            Candidate p = mutableData.getValue(Candidate.class);
                            if (p == null) {
                                return Transaction.success(mutableData);
                            } else {
                                int fetched = p.getTotalVotes();
                                fetched = fetched + 1;

                                String userId = postRef.push().getKey();
                                // Set value and report transaction success
                                postRef.child(userId).child("totalVotes").setValue(fetched);

                                //mutableData.setValue(p);
                                return Transaction.success(mutableData);
                            }
                        }
                        @Override
                        public void onComplete(DatabaseError databaseError, boolean b,
                                               DataSnapshot dataSnapshot) {
                            // Transaction completed
                            Log.d(TAG, "postTransaction:onComplete:" + databaseError);
                        }
                    });
                }


            });
        }

我的候选 m0del 如下所示:

@IgnoreExtraProperties
public class Candidate {
    private String firstname;
    private String lastname;
    private String party;
    private String category;
    private String candidateemail;
    private String imageurl;
    public Integer totalVotes;

    // Default constructor required for calls to
    // DataSnapshot.getValue(Candidate.class)
    public Candidate() {
    }

    public Candidate(String imageurl, String candidateemail, String firstname, String lastname, String party, String category, Integer totalVotes) {

        this.candidateemail = candidateemail;
        this.imageurl = imageurl;
        this.firstname = firstname;
        this.lastname = lastname;
        this.party = party;
        this.category = category;
        this.totalVotes = totalVotes;
    }

    public String getCandidateemail() {
        return candidateemail;
    }

    public void setCandidateemail(String candidateemail) {
        this.candidateemail = candidateemail;
    }

    public String getFirstname() {
        return firstname;
    }

    public void setFirstname(String firstname) {
        this.firstname = firstname;
    }

    public String getLastname() {
        return lastname;
    }

    public void setLastname(String lastname) {
        this.lastname = lastname;
    }

    public String getParty() {
        return party;
    }

    public void setParty(String party) {
        this.party = party;
    }

    public String getCategory() {
        return category;
    }

    public void setCategory(String category) {
        this.category = category;
    }

    public Integer getTotalVotes() {
        return totalVotes;
    }

    public void setTotalVotes(Integer totalVotes) {
        this.totalVotes = totalVotes;
    }

    public String getImageurl() {
        return imageurl;
    }

    public void setImageurl(String imageurl) {
        this.imageurl = imageurl;
    }

【问题讨论】:

  • 这段代码中到底有什么不符合您的预期?
  • 当我点击投票按钮时,它会在数据库中创建一条新记录,而不是更新特定投票给候选人的totaLVotes字段。

标签: java android firebase firebase-realtime-database transactions


【解决方案1】:

根据您的评论:

当我点击投票按钮时,它会在数据库中创建一条新记录,而不是更新特定投票给候选人的 totaLVotes 字段。

发生这种情况是因为您以错误的方式使用交易。当您使用以下代码行时:

String userId = postRef.push().getKey();
postRef.child(userId).child("totalVotes").setValue(fetched);

每次调用.push() 都会生成一个新的随机密钥,因此每次新的总数都会被推入数据库。要仅更新 totalVotes 属性,请使用以下方法:

public static void updateTotalVotes(String operation) {
    DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
    DatabaseReference totalVotesRef = rootRef.child("candidates").child("-M35sglMi8onCgvEDzbm").child("totalVotes");
    totalVotesRef.runTransaction(new Transaction.Handler() {
        @Override
        public Transaction.Result doTransaction(MutableData mutableData) {
            Integer votes = mutableData.getValue(Integer.class);
            if (votes == null) {
                return Transaction.success(mutableData);
            }

            if (operation.equals("increaseTotalVotes")) {
                mutableData.setValue(votes + 1);
            } else if (operation.equals("decreaseTotalVotes")){
                mutableData.setValue(votes - 1);
            }

            return Transaction.success(mutableData);
        }

        @Override
        public void onComplete(DatabaseError databaseError, boolean b, DataSnapshot dataSnapshot) {
            Log.d(TAG, databaseError.getMessage()); //Don't ignore errors!
        }
    });
}

看,您必须设置使用指向totalVotes 属性的引用。现在开始:

updateTotalVotes("increaseTotalVotes");

更多信息请查看saving data as transactions的官方文档。

【讨论】:

  • 感谢@Alex。让我试试这个。此外,在这一行中: DatabaseReference totalVotesRef = rootRef.child("candidates").child("-M35sglMi8onCgvEDzbm").child("totalVotes");如果我想从数据库中获取候选密钥而不是将其 (-M35sglMi8onCgvEDzbm) 硬编码到 rootRef 中,这可能吗?
  • 在这种情况下,您应该将该 id 保存到一个变量中,并将其用于将来的操作。通常,我们使用来自Firebase authentication process 的用户的uid 和推送id 的not 作为唯一标识符。试一试,告诉我它是否有效。
  • 非常感谢第一个答案,它起作用了,现在正在为特定的候选键更新totalVote。但是,我仍然无法从数据库中获取密钥并将其存储在变量中,正如您在第二条评论中所建议的那样。有什么帮助吗?
  • 很高兴听到它有效:) 关于第二个问题,没有看到您尝试过的内容,我帮不上什么忙。所以请使用自己的MCVE 发布另一个问题,以便我和其他 Firebase 开发人员可以帮助您。
  • 如果您可以查看 MyAdapter.java 活动,我有一个 onBindViewHolder 方法,它可以渲染从数据库中读取的每个人并将其放置在 recyclerview 中。我需要每次呈现候选信息时,它还应该获取候选键并将其存储在变量中
猜你喜欢
  • 2017-11-30
  • 1970-01-01
  • 2018-12-29
  • 1970-01-01
  • 2019-03-12
  • 1970-01-01
  • 2021-12-01
  • 2021-03-15
  • 1970-01-01
相关资源
最近更新 更多