TheStudent123 TheStudent123 - 24 days ago 7
Android Question

Android - Firebase - Retrieving Data from Node X and Sending it to Node Y

Aim

Allow Users to send reports to the authorities. Reports will be stored and will not be overwritten when new Reports are entered by the same user

Picture of Current Database

enter image description here

The current user signed in is able to store "Incident Report" into the Database but apparently when the user submits another "Incident Report", the newly submitted "Incident Report" will overwrite the data of the previous "Incident Report"

Picture of Desired Database

enter image description here

The Yellow Highlighted data is supposed to be data retrieved from the "Users" child "name" which is the Red Circled data

For example, if the data within the Red Circled data is "Abe Long", the data of the Yellow Highlighted will be "Abe Long" as well.

In addition to that, when the current signed in User submits an "Incident Report", each new one created will create a new Unique Key. This means it will not overwrite the previously submitted data.

Fragment Report.xml

<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.task.app.ReportFragment">

<!-- TODO: Update blank fragment layout -->

<TextView
android:id="@+id/reportFormIntroTxt"
android:layout_width="240dp"
android:layout_height="30dp"
android:layout_marginBottom="0dp"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_marginTop="0dp"
android:gravity="center"
android:text="@string/report_form"
android:textColor="@color/common_google_signin_btn_text_dark_focused"
android:textSize="25sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.029" />

<TextView
android:id="@+id/dateReportTxt"
android:layout_width="100dp"
android:layout_height="40dp"
android:layout_marginBottom="0dp"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_marginTop="0dp"
android:text="@string/report_date"
android:textColor="@color/common_google_signin_btn_text_dark_focused"
android:textSize="18sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_bias="0.032"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.147" />

<EditText
android:id="@+id/reportDatePick"
android:layout_width="214dp"
android:layout_height="40dp"
android:layout_marginBottom="8dp"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_marginTop="8dp"
android:ems="10"
android:inputType="date"
android:textSize="18sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_bias="0.83"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.135" />

<TextView
android:id="@+id/timeReportTxt"
android:layout_width="100dp"
android:layout_height="40dp"
android:layout_marginBottom="0dp"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_marginTop="0dp"
android:text="@string/report_time"
android:textColor="@color/common_google_signin_btn_text_dark_focused"
android:textSize="18sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_bias="0.032"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.245" />

<EditText
android:id="@+id/reportTimeEnt"
android:layout_width="214dp"
android:layout_height="40dp"
android:layout_marginBottom="8dp"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_marginTop="8dp"
android:ems="10"
android:inputType="time"
android:textSize="18sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_bias="0.83"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.236" />

<TextView
android:id="@+id/locationReportTxt"
android:layout_width="100dp"
android:layout_height="40dp"
android:layout_marginBottom="0dp"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_marginTop="0dp"
android:text="@string/report_location"
android:textColor="@color/common_google_signin_btn_text_dark_focused"
android:textSize="18sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_bias="0.032"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.346" />

<EditText
android:id="@+id/reportLocationEnt"
android:layout_width="214dp"
android:layout_height="40dp"
android:layout_marginBottom="8dp"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_marginTop="8dp"
android:ems="10"
android:inputType="textPersonName"
android:textSize="18sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_bias="0.83"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.34" />

<TextView
android:id="@+id/descriptionReportTxt"
android:layout_width="100dp"
android:layout_height="40dp"
android:layout_marginBottom="0dp"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_marginTop="0dp"
android:gravity="center"
android:text="@string/report_description"
android:textColor="@color/common_google_signin_btn_text_dark_focused"
android:textSize="18sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_bias="0.032"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.439" />

<EditText
android:id="@+id/reportDescriptionEnt"
android:layout_width="322dp"
android:layout_height="149dp"
android:ems="10"
android:inputType="textMultiLine"
android:layout_marginLeft="8dp"
app:layout_constraintLeft_toLeftOf="parent"
android:layout_marginRight="8dp"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginBottom="8dp"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="8dp"
app:layout_constraintVertical_bias="0.679"
app:layout_constraintHorizontal_bias="0.363" />

<Button
android:id="@+id/reportSendBtn"
android:layout_width="153dp"
android:layout_height="44dp"
android:layout_marginBottom="0dp"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_marginTop="0dp"
android:background="@color/colorPrimary"
android:text="@string/send_report"
android:textColor="@color/common_google_signin_btn_text_dark_pressed"
android:textColorLink="@color/colorAccent"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_bias="0.502"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.917" />

</android.support.constraint.ConstraintLayout>


Report Fragment Class

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


Additional Comments


  • How the Report Fragment works



I do not intend for the currently signed in User to be able to submit their name, that will create a possibility of the User entering someone else's name into the "Incident Report". I intend for the "CurrentUser signed in" name to be retrieved and entered into the "Incident Report" automatically.


  • How the Report Fragment is coded



Instead of putting
jReportByUserDatabase.setValue(incidentReportUser)
I have tried putting
.updateChildren
while using
Map<String, Object>
. The problem was that each data was not entered under a "Unique ID" which will be stored under "Incident Report" within the Data Tree

Solution to the Problem


Helped by both Cadet and JavaBanana


Implementing a "For Loop DataSnapshot" to loop through the data and retrieving the desired one by also using the "Users class" which contains the name, address, status, etc.

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

Answer Source

Okay so the main problem with your designs that you are storing the reports under the user's Id which firebase will overwrite obviously.

You can generate a random key for storing your reports and set your report at the generated key in the database.

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

To Retrieve the names of the Users

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