【问题标题】:Android - Firebase - Retrieving Data from Node X and Sending it to Node YAndroid - Firebase - 从节点 X 检索数据并将其发送到节点 Y
【发布时间】:2017-09-25 12:14:45
【问题描述】:

瞄准

允许用户向当局发送报告。当同一用户输入新报告时,报告将被存储并且不会被覆盖

当前数据库的图片

当前登录的用户可以将“事件报告”存储到数据库中,但显然当用户提交另一个“事件报告”时,新提交的“事件报告”将覆盖之前的“事件报告”的数据

所需数据库的图片

黄色突出显示数据应该是从“用户”子“名称”检索到的数据,即红色圆圈数据

例如,如果红圈数据中的数据是“Abe Long”,那么Yellow Highlighted的数据也会是“Abe Long”。

除此之外,当当前登录用户提交“事件报告”时,每个新创建的用户都会创建一个新的唯一密钥。这意味着它不会覆盖之前提交的数据。

报表片段类

import android.app.ProgressDialog;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.Fragment;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;

import java.util.Date;
import java.util.HashMap;


public class ReportFragment extends Fragment {

    private EditText jReportDatePick;
    private EditText jReportTimeEnt;
    private EditText jReportLocationEnt;
    private EditText jReportDescriptionEnt;

    private Button jReportSendBtn;

    private FirebaseUser jReportCurrentUserID;

    private DatabaseReference jReportByUserDatabase;

    private ProgressDialog jReportLoad;

    public ReportFragment() {
        // Required empty public constructor
    }


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View viewRoot = inflater.inflate(R.layout.fragment_report, container, false);

        jReportDatePick = viewRoot.findViewById(R.id.reportDatePick);
        jReportTimeEnt = viewRoot.findViewById(R.id.reportTimeEnt);
        jReportLocationEnt = viewRoot.findViewById(R.id.reportLocationEnt);
        jReportDescriptionEnt = viewRoot.findViewById(R.id.reportDescriptionEnt);

        jReportSendBtn = viewRoot.findViewById(R.id.reportSendBtn);

        jReportLoad = new ProgressDialog(getActivity());

        jReportSendBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                String userReportDate = jReportDatePick.getText().toString();
                String userReportTime = jReportTimeEnt.getText().toString();
                String userReportLocation = jReportLocationEnt.getText().toString();
                String userReportDescription = jReportDescriptionEnt.getText().toString();

                if(!TextUtils.isEmpty(userReportDate)&&
                        !TextUtils.isEmpty(userReportTime)&&
                        !TextUtils.isEmpty(userReportLocation)&&
                        !TextUtils.isEmpty(userReportDescription)){
                    submitReport(userReportDate, userReportTime, userReportLocation, userReportDescription);
                    jReportLoad.setTitle("Sending Report");
                    jReportLoad.setMessage("Please wait while the report is being sent");
                    jReportLoad.setCanceledOnTouchOutside(false);
                    jReportLoad.show();
                }else{
                    jReportLoad.dismiss();
                    Toast.makeText(getActivity(), "Report failed to be sent due to empty inputs", Toast.LENGTH_SHORT).show();
                }

            }
        });

        return  viewRoot;
    }

    private void submitReport(final String userReportDate,final String userReportTime,
                              final String userReportLocation,final String userReportDescription) {

        jReportCurrentUserID = FirebaseAuth.getInstance().getCurrentUser();
        final String reportUserID = jReportCurrentUserID.getUid();
        jReportByUserDatabase = FirebaseDatabase.getInstance().getReference().child("Incident Reports").child(reportUserID);

        HashMap<String, String> incidentReportUser = new HashMap<>();
        incidentReportUser.put("date", userReportDate);
        incidentReportUser.put("time", userReportTime);
        incidentReportUser.put("location", userReportLocation);
        incidentReportUser.put("description", userReportDescription);

        jReportByUserDatabase.setValue(incidentReportUser).addOnCompleteListener(new OnCompleteListener<Void>() {
            @Override
            public void onComplete(@NonNull Task<Void> task) {
                if(task.isSuccessful()){
                    jReportLoad.dismiss();
                    Toast.makeText(getActivity(), "Report was Sent", Toast.LENGTH_SHORT).show();
                    jReportDatePick.setText("");
                    jReportTimeEnt.setText("");
                    jReportLocationEnt.setText("");
                    jReportDescriptionEnt.setText("");
                }else{
                    jReportLoad.dismiss();
                    Toast.makeText(getActivity(), "Report failed to be sent", Toast.LENGTH_SHORT).show();
                }
            }
        });
    }
}

附加评论

  • 报告片段的工作原理

我不打算让当前登录的用户能够提交他们的姓名,这将导致用户在“事件报告”中输入其他人的姓名的可能性。我打算自动检索“当前用户登录”名称并将其输入到“事件报告”中。

  • 报告片段的编码方式

我尝试在使用Map&lt;String, Object&gt; 时放置.updateChildren,而不是放置jReportByUserDatabase.setValue(incidentReportUser)。问题是每个数据没有在“唯一 ID”下输入,该 ID 将存储在数据树中的“事件报告”下


问题的解决方案

在 Cadet 和 JavaBanana 的帮助下

实现一个“For Loop DataSnapshot”循环遍历数据并使用包含名称、地址、状态等的“Users 类”检索所需的数据。

private void submitReport(final String userReportDate,final String userReportTime,
                          final String userReportLocation,final String userReportDescription) {

DatabaseReference dbRef = FirebaseDatabase.getInstance().getReference();
dbRef.child("Users").addListenerForSingleValueEvent(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
        for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
            Users user = snapshot.getValue(Users.class);
            HashMap<String, String> incidentReportUser = new HashMap<>();
            incidentReportUser.put("name", user.name);
            incidentReportUser.put("date", userReportDate);
            incidentReportUser.put("time", userReportTime);
            incidentReportUser.put("location", userReportLocation);
            incidentReportUser.put("description", userReportDescription);

            jReportCurrentUserID = FirebaseAuth.getInstance().getCurrentUser();
            final String reportUserID = jReportCurrentUserID.getUid();
            jReportByUserDatabase = FirebaseDatabase.getInstance().getReference().child("Incident Reports").child(reportUserID);
            jReportByUserDatabase.push().setValue(incidentReportUser).addOnCompleteListener(new OnCompleteListener<Void>() {
                @Override
                public void onComplete(@NonNull Task<Void> task) {
                    if(task.isSuccessful()){
                        jReportLoad.dismiss();
                        Toast.makeText(getActivity(), "Report was Sent", Toast.LENGTH_SHORT).show();
                        jReportDatePick.setText("");
                        jReportTimeEnt.setText("");
                        jReportLocationEnt.setText("");
                        jReportDescriptionEnt.setText("");
                    }else{
                        jReportLoad.dismiss();
                        Toast.makeText(getActivity(), "Report failed to be sent", Toast.LENGTH_SHORT).show();
                    }
                }
            });
        }
    }
    @Override
    public void onCancelled(DatabaseError databaseError) {
    }
});
}

【问题讨论】:

    标签: java android firebase firebase-realtime-database


    【解决方案1】:

    这样写 (推送添加值,而不是覆盖)。

    jReportByUserDatabase.push()setValue(incidentReportUser)

    另外,我建议让报告节点也包含用户字段。就像将它们组合成平面节点一样。

    【讨论】:

    • 天啊,非常感谢!!! .push() 帮助解决了 90% 的问题!!我从来没想过!!但是有没有办法让我得到当前用户的“名字”?请帮我解决这个问题 =D
    • “当前”用户的定义是什么?有人做了最新报告?
    • 是的!!!例如,“John Smith”是登录到应用程序的 currentUser。 “约翰史密斯”将能够发送任意数量的报告。但我只想从 Red Circled 数据中检索他的“姓名”,如 所需数据库的图片所示
    • 嗯...我明白了。这个问题还涉及逻辑变化,不仅仅是 Firebase 的使用。我可以推荐的是让 Report 节点也包含用户字段。就像将它们组合到平面节点(我会尝试将快照添加到我之前的答案中 - 我不能在 cmets 中做到这一点)。可能您的代码中有 2 个独立的类(用户和报表),因此将参数“用户”添加到报表的构造函数中,读取字段并在报表中生成平面(将它们称为 userAddess、userName 等)它将为您节省未来的许多问题,并降低使用 Firebase 的复杂性。
    • 感谢您的建议 Cadet,但如果我要将它们作为一个数据库添加到数据库中,如屏幕截图所示,这意味着一旦用户注册到应用程序,他们已经在发送事件报告。如果用户因为他们所在区域的一切都很好而决定不发送报告怎么办?我尝试从单个节点获取选定的数据并且它可以工作。但我不希望用户一注册就发送报告。
    【解决方案2】:

    好的,您的设计的主要问题是您将报告存储在用户 ID 下,而 Firebase 显然会覆盖该 ID。

    您可以生成一个随机密钥来存储您的报告,并将您的报告设置为数据库中生成的密钥。

    public class Report {
      String reportId; // This is important
      String reporterId;  //This is important
      String reporterName;
      String userType;
      String status;
      String address;
      String neibourhood;
      String image;
    }
    
    DatabaseReference dbRef = FirebaseDatabase.getInstance().getReference("Incident Reports");
    String reportId = dbRef.push().getKey(); //This generates a new key and returns it
    Report report = new Report("report id", "reporter id", "other stuff"... "etc");
    dbRef.child(reportId).setValue(report);
    

    检索用户姓名

    DatabaseReference dbRef = FirebaseDatabase.getInstance().getReference();
    dbRef.child("Users").addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            //Loop through the retrieved user data
            for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
                User user = snapshot.getValue(User.class);
                System.out.println(user.name);
            }
        }
        @Override
        public void onCancelled(DatabaseError databaseError) {}
    });
    

    【讨论】:

    • 感谢您的回答!!感谢您向我展示了生成新密钥 String reportId = dbRef.push().getKey(); 的方法,但是如果我想从 **Red Circled ** 数据中检索“名称”怎么办?
    • 来自“用户”节点或“事件报告”节点的用户名?
    • “用户”节点中的用户名。 当前数据库的图片是我目前拥有的,所需数据库的图片是我想要生成的。用户的“姓名”不是当前用户输入的,而是在当前用户提交“事件报告”时从他/她那里检索到的
    • JavaBanana!!!谢谢您的回答。我已将 HashMap 放入 DataSnapshot 以保存数据和检索到的数据。祝你有美好的一天。
    • 你好JavaBanana,你能帮我回答这个问题吗stackoverflow.com/questions/46471541/… =D
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多