Android/FireStore QuerySnapshot convert to CustomObject - java

I am currently programin a test QuizApp. The gameplay is pretty easy I just want an online database of questions and a user can answer them.
This is what the database looks like:
That collection questions contains an unique ID and a custom Object (questionObject) named 'content'. The number is only something easy I can query/search for.
This is my questionAdder and query UI. It's only a small test App.
public class questionAdder extends AppCompatActivity {
EditText pQuestion, pAnwerA, pAnswerB, pAnswerC, pAnswerD, number;
Button pAdd, query;
private DatabaseReference databaseReference;
private FirebaseFirestore firebaseFirestore;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.addquestion);
firebaseFirestore = FirebaseFirestore.getInstance();
pQuestion = (EditText) findViewById(R.id.question);
pAnwerA = (EditText) findViewById(R.id.answerA);
pAnswerB = (EditText) findViewById(R.id.answerB);
pAnswerC = (EditText) findViewById(R.id.answerC);
pAnswerD = (EditText) findViewById(R.id.answerD);
number = (EditText) findViewById(R.id.number);
pAdd = (Button) findViewById(R.id.addQuestion);
pAdd.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
readQuestionStore();
}
});
query = (Button) findViewById(R.id.query);
query.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
CollectionReference questionRef = firebaseFirestore.collection("questions");
questionRef.whereEqualTo("content.number", "20").get().addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
#Override
public void onSuccess(QuerySnapshot queryDocumentSnapshots) {
questionObject pContent = queryDocumentSnapshots.toObjects(questionObject.class);
}
});
}
});
}
public void readQuestionStore(){
Map<String, Object> pContent = new HashMap<>();
pContent.put("question", pQuestion.getText().toString());
pContent.put("Corr Answer", pAnwerA.getText().toString());
pContent.put("AnswerB", pAnswerB.getText().toString());
pContent.put("AnswerC", pAnswerC.getText().toString());
pContent.put("AnswerD", pAnswerD.getText().toString());
questionObject content = new questionObject(pContent, number.getText().toString()); //document("Essen").collection("Katalog")
firebaseFirestore.collection("questions").add(content).addOnSuccessListener(new OnSuccessListener<DocumentReference>() {
#Override
public void onSuccess(DocumentReference documentReference) {
Toast.makeText(questionAdder.this, "Klappt", Toast.LENGTH_LONG).show();
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Toast.makeText(questionAdder.this, "Klappt nicht", Toast.LENGTH_LONG).show();
}
});
}
}
And this is how my questionObject looks like:
public class questionObject{
private Map<String, Object> content;
private String number;
public questionObject(){
}
public questionObject(Map<String, Object> pContent, String pNumber) {
this.content = pContent;
this.number = pNumber;
}
public Map<String, Object> getContent() {
return content;
}
public void setContent(Map<String, Object> content) {
this.content = content;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
}
Problem In that questionAdder class in the onClickListener I receive an "incompatible types" Error (Found: java.utils.list Required: questionObject).
query.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
CollectionReference questionRef = firebaseFirestore.collection("questions");
questionRef.whereEqualTo("content.number", "20").get().addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
#Override
public void onSuccess(QuerySnapshot queryDocumentSnapshots) {
questionObject pContent = queryDocumentSnapshots.toObjects(questionObject.class);
}
});
}
});
If if I change that to a List it is empty. So the actual question is, how do I get the CustomObject into my code using the Database. Thanks!

The reason you are getting this error in because the QuerySnapshot is a type which "contains" multiple documents. Firestore won't decide for you whether there are a bunch of objects to return as a result, or just one.
This is why you can take two different approaches:
Put the data in a custom object's list:
List<questionObject> questionsList=new ArrayList<>();
if (!documentSnapshots.isEmpty()){
for (DocumentSnapshot snapshot:queryDocumentSnapshots)
questionsList.add(snapshot.toObject(questionObject.class));
}
If you're sure that your gonna get only one queried object, you can just get the first object from the returned queryDocumentSnapshots:
questionObject object=queryDocumentSnapshots.getDocuments().get(0).toObject(questionObject.class);
A few more things you should be aware of:
Why do you write content.number instead of just number?
It seems like number is a separated field in your question document, so your code should be as follows:
CollectionReference questionRef = firebaseFirestore.collection("questions");
questionRef.whereEqualTo("number", "20").get().addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
#Override
public void onSuccess(QuerySnapshot queryDocumentSnapshots) {
questionObject pContent = queryDocumentSnapshots.toObjects(questionObject.class);
}
});
In addition, try to change your number field to int, because it's not a String but a just a number.
By the way, it is more acceptable to write classes' names with a capital letter at a beginning, for example: QuestionObject question=new QuestionObject();

Related

How to properly initialize value from firebase with model class

I am making a firebase app where the user is able to rate another user. I am occasionally getting a null pointer on this like of code:
averageStars+=Double.parseDouble(rate.getRates());
I seem to mess things up like this often, where I create a model class and then somehow never initialize it. However, even with some research, I am not sure why these are not considered initialized. Would anyone have an idea on how I initialize classes like this(Firebase). My main code for the activity looks like:
public class RateActivity extends AppCompatActivity {
Button btnSubmit;
MaterialRatingBar ratingBar;
MaterialEditText edtComment;
FirebaseDatabase database;
DatabaseReference rateDetailRef;
DatabaseReference driverInformationRef;
double ratingStars= 0.0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_rate);
database = FirebaseDatabase.getInstance();
rateDetailRef = database.getReference(Common.rate_detail_tbl);
driverInformationRef = database.getReference(Common.user_driver_tbl);
btnSubmit = (Button)findViewById(R.id.btnSumbit);
ratingBar = (MaterialRatingBar)findViewById(R.id.ratingBar);
edtComment = (MaterialEditText)findViewById(R.id.edtComment);
ratingBar.setOnRatingChangeListener(new MaterialRatingBar.OnRatingChangeListener() {
#Override
public void onRatingChanged(MaterialRatingBar ratingBar, float rating) {
ratingStars = rating;
}
});
btnSubmit.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
submitRateDetails(Common.driverId);
}
});
}
private void submitRateDetails(String driverId) {
SpotsDialog alertDialog = new SpotsDialog(this);
alertDialog.show();
Rate rate = new Rate();
rate.setRates(String.valueOf(ratingStars));
rate.setComments(edtComment.getText().toString());
rateDetailRef.child(Common.driverId)
.child(FirebaseAuth.getInstance().getCurrentUser().getUid())
.push()
.setValue(rate)
.addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
rateDetailRef.child(Common.driverId)
.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
double averageStars = 0.0;
int count = 0;
for(DataSnapshot postSnapshot : dataSnapshot.getChildren())
{
Rate rate = postSnapshot.getValue(Rate.class);
averageStars+=Double.parseDouble(rate.getRates());
count++;
}
double finalAverage = averageStars/count;
DecimalFormat df = new DecimalFormat("#.#");
String valueUpdate = df.format(finalAverage);
Map<String,Object> driverUpdateRate = new HashMap<>();
driverUpdateRate.put("rates",valueUpdate);
driverInformationRef.child(Common.driverId)
.updateChildren(driverUpdateRate)
.addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
alertDialog.dismiss();
Toast.makeText(RateActivity.this, "Thank you for your feedback", Toast.LENGTH_SHORT).show();
finish();
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
alertDialog.dismiss();
Toast.makeText(RateActivity.this, "Rating did not go through", Toast.LENGTH_SHORT).show();
}
});
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
alertDialog.dismiss();
Toast.makeText(RateActivity.this,"Rating failed?",Toast.LENGTH_SHORT).show();
}
});
}
}
My model class for the "getRates" feature looks like
public class Rate {
private String rates;
private String comments;
public Rate(String rates, String comments) {
this.rates = rates;
this.comments = comments;
}
public Rate(){}
public String getRates() {
return rates;
}
public void setRates(String rates) {
this.rates = rates;
}
public String getComments() {
return comments;
}
public void setComments(String comments) {
this.comments = comments;
}
}
Thank you.
Due to request, here is my logcat:
2020-01-26 17:59:25.792 25184-25184/com.example.usubx E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.usubx, PID: 25184
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String java.lang.String.trim()' on a null object reference
at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1838)
at sun.misc.FloatingDecimal.parseDouble(FloatingDecimal.java:110)
at java.lang.Double.parseDouble(Double.java:538)
at com.example.usubx.RateActivity$4$1.onDataChange(RateActivity.java:102)
at com.google.firebase.database.core.ValueEventRegistration.fireEvent(com.google.firebase:firebase-database##19.2.0:75)
at com.google.firebase.database.core.view.DataEvent.fire(com.google.firebase:firebase-database##19.2.0:63)
at com.google.firebase.database.core.view.EventRaiser$1.run(com.google.firebase:firebase-database##19.2.0:55)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
Here is the value of my datasnapshot
DataSnapshot { key = RateDetails, value = {UE7cSOf5Thbum6OwEmg9seAPD463={-LzZH15-YVs1m67EuJlD={comments=Colin, rates=4.5}, -LzZHvuClxb5Ef3jk23_={comments=, rates=5.0}}, -LzJrTz5FrzEaoWorqP-={comments=, rates=5.0}, -LzKQn7F1ybKVAxUj9NX={comments=heck cool, rates=5.0}, -LzNyBwBh0tVHKvMfgEk={comments=, rates=5.0}, vAdqbIhLKJasOtyXKYrCkrOSVq33={-Lz-hH6TXxKTUVvIUYnK={comments=he was cool, rates=5.0}, -LzNz80QZDhnZA1tJ27Y={comments=, rates=3.5}, -Lz-h35N3l0xnLVVNvwa={comments=, rates=1.5}, -LzJqTWwUXOsfKPDZh2E={comments=, rates=5.0}, -LzNzEjdyg_aYMAfdI14={comments=, rates=5.0}, -LzJomtnZH4zJ6nddk0c={comments=HECK YES IT WORKS, rates=5.0}}, -LzJt7VA3iVPLopRFD34={comments=let's go, rates=5.0}, -LzNxj1zaWAZukLPyTEw={comments=, rates=5.0}, -LzNv9bTAz7_3vXioMRe={comments=heck, rates=5.0}} }
I agree with the other answer that, just putting a null should suffice to handle the case here. However, from your question, it looks like you want to initialize the Rate class with default values so that you do not end up with some invalid/null values at any point in time. In that case, I would actually suggest modifying the Rate class getters as follows.
public class Rate {
private String rates;
private String comments;
public Rate(String rates, String comments) {
this.rates = rates;
this.comments = comments;
}
public Rate(){}
public String getRates() {
if (rates == null) return "0.0";
else return rates;
}
public void setRates(String rates) {
this.rates = rates;
}
public String getComments() {
if (comments == null) return ""; // Return empty string
else return comments;
}
public void setComments(String comments) {
this.comments = comments;
}
}
I hope that helps!
Because your database has null rates. Please check your database. some data did not have rates string.
and check null like this to avoid NullPointerException
if(rate.getRates() != null)
averageStars+=Double.parseDouble(rate.getRates());

How to Sort the List<Model> data after fetching Android

I am fetching data and adding it to List from firebase database.
Now i want to sort the list data based on time so that latest data will appear first on the list and then setting the updated list into my RecyclerView.Adapter. I have tried layoutmanager.setReverseLayout(true); and layoutmanager.setStackFromEnd(true); for reversing the RecyclerView but it always shows data from the middle and also I don't want to follow this method.
How can i do that.
public class HistoryActivity extends AppCompatActivity{
private String customerOrDriver, userId;
private String doctorId, patientId, pharmacyId, userDriverOrCustomer;
private Long timestamp;
private String name, service;
private SwipeRefreshLayout swipeRefreshLayout;
private RecyclerView mHistoryRecyclerView;
private RecyclerView.Adapter mHistoryAdapter;
private RecyclerView.LayoutManager mHistoryLayoutManager;
SharedPreferences sharedPreferences;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_history);
customerOrDriver = getIntent().getExtras().getString("customerOrDriver");
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(HistoryActivity.this);
userId = sharedPreferences.getString("UID","");
mHistoryRecyclerView = (RecyclerView) findViewById(R.id.historyRecyclerView);
mHistoryAdapter = new HistoryAdapter(getDataSetHistory(), HistoryActivity.this);
mHistoryLayoutManager = new LinearLayoutManager(HistoryActivity.this);
mHistoryRecyclerView.setLayoutManager(mHistoryLayoutManager);
mHistoryRecyclerView.setHasFixedSize(true);
/*// sort the recycler view to descending order
((LinearLayoutManager) mHistoryLayoutManager).setReverseLayout(true);
((LinearLayoutManager) mHistoryLayoutManager).setStackFromEnd(true);*/
mHistoryRecyclerView.setItemAnimator(new DefaultItemAnimator());
mHistoryRecyclerView.addItemDecoration(new DividerItemDecoration(this, LinearLayoutManager.VERTICAL));
mHistoryRecyclerView.setAdapter(mHistoryAdapter);
getUserHistoryIds();
}
private void getUserHistoryIds() {
//swipeRefreshLayout.setRefreshing(true);
DatabaseReference userHistoryDatabase = FirebaseDatabase.getInstance().getReference().child(Common.user_table).child(customerOrDriver).child(userId).child(Common.history_table);
userHistoryDatabase.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if(dataSnapshot.exists()){
for(DataSnapshot history : dataSnapshot.getChildren()){
FetchRideInformation(history.getKey());
//swipeRefreshLayout.setRefreshing(false);
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
//swipeRefreshLayout.setRefreshing(false);
}
});
}
private void FetchRideInformation(String rideKey) {
DatabaseReference historyDatabase = FirebaseDatabase.getInstance().getReference().child(Common.history_table).child(rideKey);
historyDatabase.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if(dataSnapshot.exists()){
String rideId = dataSnapshot.getKey();
timestamp = 0L;
for(DataSnapshot child : dataSnapshot.getChildren()){
if (child.getKey().equals("timestamp")){
timestamp = Long.valueOf(child.getValue().toString());
}
}
getRideInformation(rideId, timestamp);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
private void getRideInformation(final String rideId, final Long timestamp) {
DatabaseReference historyRideInfoDb = FirebaseDatabase.getInstance().getReference().child(Common.history_table).child(rideId);
historyRideInfoDb.addListenerForSingleValueEvent(new ValueEventListener() {
#SuppressLint("SetTextI18n")
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
for (DataSnapshot child : dataSnapshot.getChildren()) {
if (child.getKey().equals("patient")) {
patientId = child.getValue().toString();
if (!patientId.equals(userId)) {
userDriverOrCustomer = "Doctors";
getUserInformation("Patients", patientId, rideId, timestamp);
}
}
else if (child.getKey().equals("patient")) {
patientId = child.getValue().toString();
if (!patientId.equals(userId)) {
userDriverOrCustomer = "Phamacys";
getUserInformation("Patients", patientId, rideId, timestamp);
}
}
if (child.getKey().equals("doctor")) {
doctorId = child.getValue().toString();
if (!doctorId.equals(userId)) {
userDriverOrCustomer = "Patients";
getUserInformation("Doctors", doctorId, rideId, timestamp);
}
}
else if (child.getKey().equals("pharmacy")) {
pharmacyId = child.getValue().toString();
if (!pharmacyId.equals(userId)) {
userDriverOrCustomer = "Patients";
getUserInformation("Pharmacys", pharmacyId, rideId, timestamp);
}
}
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
private void getUserInformation(String otherUserDriverOrCustomer, String otherUserId, final String rideId, final Long timestamp) {
DatabaseReference mOtherUserDB = FirebaseDatabase.getInstance().getReference().child(Common.user_table).child(otherUserDriverOrCustomer).child(otherUserId);
mOtherUserDB.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
Map<String, Object> map = (Map<String, Object>) dataSnapshot.getValue();
if (map.get("name") != null) {
name = (map.get("name").toString());
}
if(map.get("service") == null)
{
service = (map.get("phone").toString());
}
else if (map.get("service") != null) {
service = (map.get("service").toString());
}
HistoryObject obj = new HistoryObject(rideId, name, service, getDate(timestamp));
resultsHistory.add(obj);
mHistoryAdapter.notifyDataSetChanged();
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
private String getDate(Long time) {
Calendar cal = Calendar.getInstance(Locale.getDefault());
cal.setTimeInMillis(time*1000);
String date = DateFormat.format("MMMM dd yyyy, hh:mm a", cal).toString();
return date;
}
private ArrayList resultsHistory = new ArrayList<HistoryObject>();
private ArrayList<HistoryObject> getDataSetHistory() {
return resultsHistory;
}
}
Simply use myList.sort() then read it the way its needed like ascending or descending amd put it in the RecyclerView
You can sort your by following way
Her i just showed you an Student object but in your case you can check with datetime
Using Lambda expression: The Java 8 equivalent code using Lambda expression would look like this:
studentlist.sort((Student s1, Student s2)->s1.getName().compareTo(s2.getName()));

FirebaseRecyclerAdapter Search

I have implemented a FirebaseRecyclerAdapter to populate cities from the database in to the RecyclerView. After several fails to implement a search feature I am seeking for help. I would like to let users search for a particular city by typing the city's name (postName). The idea is to populate all of the available cities at the beginning and the desired city after its name is typed in the search field.
My code to populate the view is:
searchField = view.findViewById(R.id.search_field);
searchButton = view.findViewById(R.id.imageButton);
searchButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String search_field = searchField.getText().toString().trim();
initialiseScreen(view, search_field);
Toast.makeText(getContext(), search_field, Toast.LENGTH_SHORT).show();
}
});
String search_field = null;
initialiseScreen(view, search_field);
return view;
}
private void initialiseScreen(final View view, String searchText) {
Query postQuery = mDataRef.orderByChild("postName").startAt(searchText).endAt(searchText + "\uf8ff");
mDataRef.keepSynced(true);
recyclerView = view.findViewById(R.id.post_RV);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
recyclerView.setAdapter(mPostViewAdapter);
FirebaseRecyclerOptions postOptions = new FirebaseRecyclerOptions.Builder<Post>()
.setQuery(postQuery, Post.class).build();
mPostViewAdapter = new FirebaseRecyclerAdapter<Post, PostViewHolder>(postOptions) {
#Override
protected void onBindViewHolder(PostViewHolder holder, int position, final Post model) {
final String post_key = getRef(position).getKey();
holder.setPostCityImage(model.getImageURL());
holder.setPostCityName(model.getPostName());
holder.setLikeBtn(post_key);
//When is clicked once go to city fragment
holder.cityImg.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//Add code here
Intent singlePostIntent = new Intent(getActivity(), CitiesActivity.class);
singlePostIntent.putExtra("blog_id", post_key);
startActivity(singlePostIntent);
}
});
//Likes button
holder.likes.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mProccessLike = true;
String postId = model.getmUid();
mDatabaseLikesRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if(mProccessLike) {
if (dataSnapshot.child(post_key).hasChild(current_user_id)) {
mDatabaseLikesRef.child(post_key).child(current_user_id).removeValue();
mProccessLike = false;
} else {
mDatabaseLikesRef.child(post_key).child(current_user_id).setValue("RandomValue");
mProccessLike = false;
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
});
//
}
Btw it populates only one city if instead of String search_field = null; I write something like String search_field = "Calp, Spain";

addChildEventListener is not working

In my app I want to add data to my Firebase database and read the data simultaneously. So I am using addChildEventListener() method to retrieve data. But this method is not working and the app is getting crashed everytime.
The code is given below:
public class ChatActivity extends AppCompatActivity {
LinearLayout layout;
RelativeLayout layout_2;
ImageView sendButton;
EditText messageArea;
ScrollView scrollView;
//Firebase reference1, reference2;
private DatabaseReference reference1, reference2,reference3;
private FirebaseAuth firebaseAuth;
private FirebaseUser firebaseUser;
private String username,userId;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_chat);
layout = (LinearLayout) findViewById(R.id.layout1);
layout_2 = (RelativeLayout)findViewById(R.id.layout2);
sendButton = (ImageView)findViewById(R.id.sendButton);
messageArea = (EditText)findViewById(R.id.messageArea);
scrollView = (ScrollView)findViewById(R.id.scrollView);
username=getIntent().getStringExtra("abc");
userId=getIntent().getStringExtra("abcd");
reference1= FirebaseDatabase.getInstance().getReferenceFromUrl("https://career-dna-bec2e.firebaseio.com/CHAT/user/" +username);
reference2=FirebaseDatabase.getInstance().getReferenceFromUrl("https://career-dna-bec2e.firebaseio.com/CHAT/admin/"+username);
sendButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String messageText = messageArea.getText().toString();
if(!messageText.equals("")){
Map<String, String> map = new HashMap<String, String>();
map.put("message", messageText);
map.put("user",userId);
reference1.push().setValue(map);
reference2.push().setValue(map);
messageArea.setText("");
}
}
});
try
{
reference1.addChildEventListener(new com.google.firebase.database.ChildEventListener() {
#Override
public void onChildAdded(com.google.firebase.database.DataSnapshot dataSnapshot, String s) {
Map<String, String> map = dataSnapshot.getValue(Map.class);
String message = map.get("message").toString();
String userName = map.get("user").toString();
if(userName.equals(userId)){
addMessageBox("You:-\n" + message, 1);
}
else{
addMessageBox("admin"+ ":-\n" + message, 2);
}
}
#Override
public void onChildChanged(com.google.firebase.database.DataSnapshot dataSnapshot, String s) {
}
#Override
public void onChildRemoved(com.google.firebase.database.DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(com.google.firebase.database.DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
catch (Exception e)
{
Toast.makeText(getApplicationContext(),"error:"+e,Toast.LENGTH_SHORT).show();
}
}
The app is crashing with this error:
02-23 20:43:15.832 12583-12583/com.ankush.anthroplace.careerdna
E/AndroidRuntime: FATAL EXCEPTION: main Process:
com.ankush.anthroplace.careerdna, PID: 12583
com.google.firebase.database.DatabaseException: Class java.util.Map
has generic type parameters, please use GenericTypeIndicator instead
Try using :
Map<String, Object> map = new HashMap<String, Object>();
While retrieving data use this :
Map<String, Object> map = dataSnapshot.getValue(Map.class);
But, if you really want to use Map class with 2 Strings as parameters, use this inside onChildAdded method :-
GenericTypeIndicator<Map<String, String>> genericTypeIndicator = new GenericTypeIndicator<Map<String, String>>() {};
Map<String, String> map = dataSnapshot.getValue(genericTypeIndicator);
There's no need to enter the full URL, use this instead
DatabaseReference reference1 = FirebaseDatabase.getInstance().getReference().child("CHAT").child("user").child(username);
DatabaseReference reference2 = FirebaseDatabase.getInstance().getReference().child("CHAT").child("admin").child(username);
And, one more thing you are doing wrong is, you are adding ChildEventListener everytime the sendButton is clicked, which is not neccesary, just create a ChildEventListener inside onCreate() and not in onClick() like this:-
ChildEventListener childEventListener = new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
Map<String, String> map = dataSnapshot.getValue(Map.class);
String message = map.get("message").toString();
String userName = map.get("user").toString();
if(userName.equals(userId)){
addMessageBox("You:-\n" + message, 1);
}
else{
addMessageBox("admin"+ ":-\n" + message, 2);
}
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.e("TAG", databaseError.toString());
}
};
//attaching the ChildEventListener to the DatabaseReference
reference1.addChildEventListener(childEventListener);
Don't forget to remove the listener in onStop()
#Override
protected void onStop() {
super.onStop();
reference1.removeEventListener(childEventListener);
}
I have solved the problem myself by using an object to store the data instead of hashmap. I am not sure why map is not working,but use of object is doing fine.
the code is given below:
sendButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String messageText = messageArea.getText().toString();
if(!messageText.equals("")){
map=new messageModel(messageText,userId);
reference1.child(""+n).setValue(map).addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if(task.isSuccessful())
{
reference2.child(""+n2).setValue(map).addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if(task.isSuccessful())
{
messageArea.setText("");
}
}
});
}
else
{
Toast.makeText(getApplicationContext(),"server problem try again",Toast.LENGTH_SHORT).show();
}
}
});
}
}
});
try
{
reference1.addChildEventListener(new com.google.firebase.database.ChildEventListener() {
#Override
public void onChildAdded(com.google.firebase.database.DataSnapshot dataSnapshot, String s) {
map = dataSnapshot.getValue(messageModel.class);
String message = map.myMessage;
String userName = map.user;
if(userName.equals(userId)){
addMessageBox("You:\n" + message, 1);
}
else{
addMessageBox("USER:\n" + message, 2);
}
}
#Override
public void onChildChanged(com.google.firebase.database.DataSnapshot dataSnapshot, String s) {
}
#Override
public void onChildRemoved(com.google.firebase.database.DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(com.google.firebase.database.DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
catch (Exception e)
{
Toast.makeText(getApplicationContext(),"error:"+e,Toast.LENGTH_SHORT).show();
}
as u can see no part of the code has been changed except the map portion.The code of messageModel class is as following:
public class messageModel {
public String myMessage;
public String user;
public messageModel()
{
}
public messageModel(String a,String b)
{
myMessage=a;
user=b;
}
}

What could be causing the failed bounce to type?

I am using Firebase, and I am trying to show data from Firebase through my Android app. Yet, when I run the app, it crashes and logcat says "failed to bounce to type". I mimicked the properties of the JSON structure in a java class.
Here is the MainActivity:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Firebase.setAndroidContext(this);
Firebase ref = new Firebase("https://fbandg.firebaseio.com/");
android.R.layout.simple_list_item_1, android.R.id.text1);
final TextView textbox = (TextView) findViewById(R.id.textbox);
Firebase.setAndroidContext(this);
ValueEventListener newCon = ref.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
fObject obj = dataSnapshot.getValue(fObject.class); //Line 49
textbox.setText(obj.toString());
}
#Override
public void onCancelled(FirebaseError firebaseError) {
}
});
Here is the Java class I created:
public class fObject
{
String newCond;
public String getCondition()
{
return newCond;
}
}
The errors produced are the following:
firebase.client.DataSnapshot.getValue(DataSnapshot.java:183)
com.example.elish_000.myfirstapp.MainActivity$1.onDataChange(MainActivity.java:49)
Try this,
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Firebase.setAndroidContext(this);
Firebase ref = new Firebase("https://fbandg.firebaseio.com");
final TextView textbox = (TextView) findViewById(R.id.textbox);
ref.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
fObject fobject = new fObject();
fobject.setNewCondition(dataSnapshot.child("condition").getValue().toString());
textbox.setText(fobject.getNewCondition());
}
#Override
public void onCancelled(FirebaseError firebaseError) {
}
});
modify your fObject class,
public class fObject
{
String newCond;
public String getNewCond()
{
return newCond;
}
public void setNewCond(String cond)
{
newCond = cond;
}
}
Firebase's JSON-to-Java mapper uses a JavaBean pattern to determine how to map fields. For a class to be a valid JavaBean, the field name and the getter/setter need to match.
To make your class work, change it to:
public class fObject
{
String newCond;
public String getNewCond()
{
return newCond;
}
}
You can then read it from a DataSnapshot with:
fObject obj = dataSnapshot.getValue(fObject.class);
I've covered this extensively a while ago: Why do I get "Failed to bounce to type" when I turn JSON from Firebase into Java objects?. You should probably read that too.

Categories