FirebaseUI - get random list using FirebaseRecyclerAdapter - android

Firebase data structure
{ "questions" : {
"-KkLGS71meu8aA_wcqTq" : {
"q_answer" : "....",
"q_category" : "....",
"q_qid" : "1",
"q_question" : "..."
},
"-KkLGkf8tNb-OKwu2qVa" : {
"q_answer" : "...",
"q_category" : "...",
"q_qid" : "2",
"q_question" : "..."
},
"-KkLH1T1ZhFKJaqYFuJ4" : {
"q_answer" : "...",
"q_category" : "...",
"q_qid" : "3",
"q_question" : "..."
} }
Database refrence
questionRef.orderByChild("q_qid")
how do i generate random query and display with FirebaseRecyclerAdapter?
Is there any other way to do it?
Edit :
I try this code
questionRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
long allNum = dataSnapshot.getChildrenCount();
int maxNum = (int)allNum;
int minNum = 1;
int randomNum = new Random().nextInt(maxNum - minNum + 1) + minNum;
int count = 0;
Iterable<DataSnapshot> ds = dataSnapshot.getChildren();
Iterator<DataSnapshot> ids = ds.iterator();
Map<String, Object> question;
while(ids.hasNext() && count < randomNum) {
question = (Map<String, Object>) ids.next().getValue();
String q = question.get("q_question").toString();
viewHolder.question.setText(q);
count ++; // used as positioning.
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
But some question appear more than once ?

What you need to do, is to find out the number of possible values, numVals in the database and then use that in the following line of code:
int random = new Random().nextInt(numVals);
If you are using in your code an iterator to iterate a DataSnapshot than just iterate a random number of times to get the required value.
Hope it helps.

Related

Firebase - Group specific type of data and store as single in new table

I have below structure for a table in my application with Firebase Database
"storePurchase":{
"$user_id":{
".read": "$user_id===auth.uid",
".write":"$user_id===auth.uid",
"$storeId":{
".validate":"root.child('stores/'+auth.uid+'/'+$storeId).exists()",
"$pId":{
"cId":{
".validate":"root.child('customers/'+auth.uid+'/'+newData.val()).exists()",
},
"amount":{
},
"rate":{
},
}
}
}
},
that stores data as below:
{
"-KeyN0kMSGZbb9hb9lNm" : {
"-Kf2_5kJoLctmlGcR4d1" : {
"amount" : "2500",
"cid" : "-KdChbdoV7nxwZoGLWsY", //cust1
"rate" : "5"
},
"-Kf2_e05toGelnjRMbfg" : {
"amount" : "10000",
"cid" : "-KdCggxld52mq0DsGRjH", //cust2
"rate" : "0.5"
},
"-Kf2auWq_hQtTErp55SY" : {
"amount" : "5869",
"cid" : "-KdChbdoV7nxwZoGLWsY", //cust1
"rate" : "58"
},
"-Kf2b1QoF4I7LAVAL0_4" : {
"amount" : "25000",
"cid" : "-KdChbdoV7nxwZoGLWsY", //cust1
"rate" : "0.8"
},
"-Kf2bEwN5PtwGUec_UFh" : {
"amount" : "2500",
"cid" : "-KdCggxld52mq0DsGRjH", //cust2
"rate" : "0.8"
},
"-Kf2b_tZo3rVJbegZNXa" : {
"amount" : "5000",
"cid" : "-KdCgJKh6_Rb8MOi-fIj", //cust3
"rate" : "1.5"
}
}
}
I am having cId i.e. customer ID and now I want to combine these data of each customer and store it in a separate table as unique values. How could I combine these data? I have tried using for loop and tried storing these values on addValueEventListener into a separate list, but couldn't get succeeded? How else can I combine these data based on cId and sum up the amount?
EDIT
Am trying to achieve below data structure.
"tallyBook":{
"$user_id":{
".read": "$user_id===auth.uid",
".write":"$user_id===auth.uid",
"$storeId":{
".validate":"root.child('stores/'+auth.uid+'/'+$storeId).exists()",
"cId":{
".validate":"root.child('customers/'+auth.uid+'/'+newData.val()).exists()",
"totalRate":{
},
"totalAmt":{
},
},
}
}
}
Running this transaction every time that a purchase is placed should keep your tallybook up to date in the way that you want it. So run this transaction every time you push a purchase to Firebase.
dbRef.child("tallyBook/"+FirebaseAuth‌​.getInstance().getCu‌​rrentUser().getUid()‌+"/"+storeId+"/"+purchase1.cid).runTransaction(new Transaction.Handler() {
#Override
public Transaction.Result doTransaction(MutableData mutableData) {
TallyBook tally = mutableData.getValue(TallyBook.class);
if (tally == null) {
tally = new TallyBook();
tally.totalRate = purchase1.rate;
tally.totalAmount = purchase1.amount;
} else {
tally.totalRate = String.valueOf(Double.parseDouble(tally.totalRate) + Double.parseDouble(purchase1.rate));
tally.totalAmount = String.valueOf(Double.parseDouble(tally.totalAmount) + Double.parseDouble(purchase1.amount));
}
mutableData.setValue(tally);
return Transaction.success(mutableData);
}
#Override
public void onComplete(DatabaseError databaseError, boolean b, DataSnapshot dataSnapshot) {}
});
}
With Purchase
public class Purchase {
public String rate;
public String cid;
public String amount;
public Purchase() {
}
}
And TallyBook
public class TallyBook {
public String totalRate;
public String totalAmount;
public TallyBook() {
}
}
Then you can use the following query to get the tallybook for a particular user and store.
dbRef.child("tallyBook/"+FirebaseAuth‌​.getInstance().getCu‌​rrentUser().getUid()‌+"/"+storeId).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot tally : dataSnapshot.getChildren()) {
// I called this TallyBook but it's more like one entry in a tallybook
TallyBook tally = tally.getValue(TallyBook.class);
// Do something with tally, display it or whatever
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});

Android Firebase create lists based on group membership

I'm trying to create a list that only contains items of a particular group. For example, I've created/written a "fruits" node and a "groups" node myself in the database console (including the groups' keys).
Relatively new to Firebase, so still trying to wrap my ahead around flattening data structures.
The JSON (showing "fruits" and "groups") looks like the following:
{
"fruits" : {
"apple" : {
"color" : "appleColorValueHere",
"groups" : {
"GroupABCKey" : true,
"GroupXYZKey" : true
},
"origin" : "appleOriginValueHere",
"size" : "appleSizeValueHere"
},
"orange" : {
"color" : "orangeColorValueHere",
"groups" : {
"GroupABCKey" : true,
"GroupXYZ" : true
},
"origin" : "orangeOriginValueHere",
"size" : "orangeSizeValueHere"
},
"strawberry" : {
"color" : "strawberryColorValueHere",
"groups" : {
"GroupJKLKey" : true
},
"origin" : "strawberryOriginValueHere",
"size" : "strawberrySizeValueHere"
}
},
"groups" : {
"GroupABCKey" : {
"members" : {
"apple" : true,
"orange" : true
},
"name" : "Group ABC Name Here"
},
"GroupJKLKey" : {
"members" : {
"strawberry" : true
},
"name" : "Group JKL Name Here"
},
"GroupXYZKey" : {
"members" : {
"apple" : true,
"orange" : true
},
"name" : "Group XYZ Name Here"
}
} ...
...
}
Within the app itself, a user can create a list which copies the entire fruits node into their newly created list (see JSON further down for user-list-items). I'm then displaying the items using FirebaseRecyclerAdapter
Here is the code for how I'm doing that:
private void writeNewFruitList(String userId, String username, String email, String title) {
final String key = databaseReference.child("fruit-lists").push().getKey();
UserLists userLists = new UserLists(userId, username, email, title);
HashMap<String, Object> updatedListToAddMap = new HashMap<>();
HashMap<String, Object> itemToAdd =
(HashMap<String, Object>) new ObjectMapper().convertValue(userLists, Map.class);
updatedListToAddMap.put("/fruit-lists/" + key, itemToAdd);
updatedListToAddMap.put("/user-fruit-lists/" + userId + "/" + key, itemToAdd);
databaseReference.updateChildren(updatedListToAddMap);
final DatabaseReference subDatabaseReference = FirebaseDatabase.getInstance().getReference();
subDatabaseReference.child("fruits").addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot child : dataSnapshot.getChildren()) {
Log.d(TAG, child.getKey());
Log.d("fruitValues::", dataSnapshot.getValue().toString());
final String fruitKey= child.getKey();
FruitModel fruitModel = child.getValue(FruitModel.class);
Map<String, Object> nodeValues = fruitModel.toMap();
Map<String, Object> childUpdates = new HashMap<>();
String new_path = "/user-list-items/" + key + "/" + fruitKey+ "/";
childUpdates.put(new_path, nodeValues);
subDatabaseReference.updateChildren(childUpdates);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.e(TAG, "onCancelled", databaseError.toException());
}
});
}
Q: How can I implement this process using groups? E.g., a user creates a list and only wants the newly created list to contain fruits that are of GroupABCKey but they also want the details of those fruits (size, origin etc).
Q2: What's the best way to edit my FruitModel.java to account for the groups?
public class FruitModel {
public String size;
public String origin;
public String color;
public FruitModel() {
}
public FruitModel(String size, String origin, String color) {
this.size = size;
this.origin = origin;
this.color = color;
}
#Exclude
public Map<String, Object> toMap() {
HashMap<String, Object> result = new HashMap<>();
result.put("size", size);
result.put("origin", origin);
result.put("color", color);
return result;
}
// getters & setters
}
Finally, here's what I believe the user-list-items node would look like if done correctly?
listKey1forUserA is what I am creating correctly (except for mapping the groups as mentioned previously).
listKey2forUserA is what I'm trying to accomplish - A user wants to create and populate a list only with items that are in "GroupJKLKey"
"user-list-items" : {
"listKey1forUserA" : {
"apple" : {
"color" : "appleColorValueHere",
"groups" : {
"GroupABCKey" : true,
"GroupXYZ" : true
},
"origin" : "appleOriginValueHere",
"size" : "appleSizeValueHere"
},
"orange" : {
"color" : "orangeColorValueHere",
"groups" : {
"GroupABCKey" : true,
"GroupXYZKey" : true
},
"origin" : "orangeOriginValueHere",
"size" : "orangeSizeValueHere"
},
"strawberry" : {
"color" : "strawberryColorValueHere",
"groups" : {
"GroupJKLKey" : true
},
"origin" : "strawberryOriginValueHere",
"size" : "strawberrySizeValueHere"
}
},
"listKey2forUserA" : {
"strawberry" : {
"color" : "strawberryColorValueHere",
"groups" : {
"GroupJKLKey" : true
},
"origin" : "strawberryOriginValueHere",
"size" : "strawberrySizeValueHere"
}
}
}
Is this the proper way to go about this? Any help or a point in the right direction would be great.
Although my usage has slightly changed since I originally posted this question, the two use cases below are still applicable with some minor adjusting. There's probably a better way to go about this, so I'd definitely welcome any suggestions or ideas from others.
The tl;dr is that you structure your database in such a way that you have a groups path and a users path. The users path contains no reference to groups. Get a datasnapshot of the children of a particular group (just need the keys) and add them to an ArrayList. > For each item in your ArrayList, plug that into the users path.
This will then allow access to the details of those users (or fruits, as used in my original question) and the ability to display that information or create new information however you see fit.
Create/Write a list of people based on group membership:
private void writeListFromGroupMembership(){
final DatabaseReference mainPathReference = FirebaseDatabase.getInstance().getReference();
final ArrayList<String> groupMembers = new ArrayList<>();
DatabaseReference groupsReference = FirebaseDatabase.getInstance().getReference()
.child("groups")
.child("someOtherChildYouMayHave")
.child("nameOfGroupYouAreInterestedIn");
/* Step 1: Get a list of people in a specific group that you are interested in */
groupsReference.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot child : dataSnapshot.getChildren()) {
String groupMemberKey = child.getKey();
if (child.getValue(Boolean.class) != null) {
groupMembers.add(groupMemberKey);
} else {
// TODO
}
}
/* Step 2: Loop through your list of people and insert them as a child like the following: */
for (int i = 0; i < groupMembers.size(); i++) {
final String singleGroupMember = groupMembers.get(i);
mainPathReference.child("all-groups").child("anotherChildYouMayHave").child(singleGroupMember)
.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
// Make a POJO for the item and immediately turn it into a HashMap
Person person= dataSnapshot.getValue(Person.class);
Map<String, Object> nodeValues = person.toMap();
// Make a map for the items you are adding
Map<String, Object> childUpdates = new HashMap<>();
// The path where the items will be copied/written to.
String newPath = "/master-list-items/" + listKey + "/" + singleGroupMember + "/";
// Add the items to the update map
childUpdates.put(newPath, nodeValues);
// Do the update
mainPathReference.updateChildren(childUpdates);
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.w(TAG, "onCancelled: ", databaseError.toException());
}
});
}
}
// your other onCancelled override method here
}
Display a list of people based on group membership (using a Spinner, for example) :
public List<Person> persons;
...
private void getGroupMembers(String groupSelected) {
groupRef= FirebaseDatabase.getInstance().getReference()
.child("someOtherChildThatYouHouseGroupsUnder")
.child(groupSelected)
.child("members");
groupRef.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot child : dataSnapshot.getChildren()) {
String groupMember= child.getKey();
selectedGroupMembers.add(groupMember);
}
for (int i = 0; i < selectedGroupMembers.size(); i++) {
String singleMember = selectedGroupMembers.get(i);
singleMemberDatabaseReference = FirebaseDatabase.getInstance().getReference()
.child("all-people")
.child(singleMember);
singleMemberDatabaseReference .addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Person person = dataSnapshot.getValue(Person.class);
persons.add(person);
personAdapter = new PersonAdapter(getApplicationContext(), persons);
recyclerView.setAdapter(personAdapter);
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.w(TAG,"onCancelled: ", databaseError.toException());
}
});
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.w(TAG, "onCancelled: ", databaseError.toException());
}
});
}
For displaying a list of people based on group membership, my database structure is similar to:
{
"all-groups":{
"groupNameorKeyOfGroupName":{
"details":{
"meetingLocation":"110 William Street",
"someOtherChild":"Your value"
},
"members":{
"fakeUserA":true,
"fakeUserB":true,
"fakeUserC":true,
"fakeUserD":true
}
}
}
"all-users":{
"fakeUserA":{
},
"fakeUserB":{
}
}
}

Firebase updating value for a field in a child

I have a Child in Firebase like this in my ANDROID project:
{
"posts" : {
"-KNnbTHJGm83zpSELWwB" : {
".priority" : "6gydj46kg0",
"branch" : "Branch",
"category" : "Categoria",
"expiration" : "24h",
"g" : "6gydj46kg0",
"l" : [ -23.5415083, -46.88642 ],
"photo" : "mPostPic_20160728192627.jpeg",
"price" : 10,
"priority" : 0,
"product" : "ipad",
"userKey" : "BNd8RP5qHoc0q7f9gn8cLjPy5Ux1",
"offerMessage": "Valido ate as 14:00 hs",
"likeCount": 0
}
}
}
I just need to read the likeCount value and increment it by 1 in specific situation.
I have read a lot of Firebase documentation and sample and most part of examples is related to push data or read data and handle value changed.
I just need to read value, increment, save value again but I am newbie in Firebase and not finding a efficient way to do that.
I have splited my Json in 2 files and now the code below is working as i expected.
public void writeUserSawPost(final String postkey, int mode){
final DatabaseReference mPostsRef = mDatabase.child("posts/" + postkey);
String user = mAuth.getCurrentUser().getUid();
final DatabaseReference mPostUser = mDatabase.child("posts-user/" + user + "/" + postkey + "/sentiment");
if (mode == Constants.LIKE) {
mPostsRef.runTransaction(new Transaction.Handler() {
#Override
public Transaction.Result doTransaction(MutableData mutableData) {
Post p = mutableData.getValue(Post.class);
if (p == null) {
return Transaction.success(mutableData);
}
p.likeCount = p.likeCount + 1;
mutableData.setValue(p);
return Transaction.success(mutableData);
}
#Override
public void onComplete(DatabaseError databaseError, boolean b,
DataSnapshot dataSnapshot) {
// Transaction completed
}
});
mPostUser.setValue("like");
} else if (mode == Constants.DISLIKE){
mPostUser.setValue("dislike");
}
}

DatabaseException: Expected a Map while deserializing, but got a class java.lang.Long

What is the root cause of this problem/error ? How to resolve it? Is my data model not properly structured? Or Am I making a wrong Query?
// Adding new Comment
String comment = medit.getText().toString();
Comment newComment = new Comment(user,comment,postKey);
db.child("Post-Comments").child(postKey).push().setValue(newComment);
// Retrieving All Comments in a post
//using FirebaseRecyclerView and fragment
DatabaseReference mRef = db.child("Post-Comments").child(postKey).getRef();
adapter = new FirebaseRecyclerAdapter<Comment, myViewHolder> (Comment.class,
R.layout.comment_list_layout,myViewHolder.class, mRef)
{
#Override
protected void populateViewHolder(myViewHolder viewHolder,
Comment model, int position) {
viewHolder.bindToComments(model);
}
};
rlm2 = new LinearLayoutManager(getActivity());
rv2.setLayoutManager(rlm2);
rv2.setAdapter(adapter);
// Comment Class
public class Comment {
public String comment;
public String reactUserId;
public Map<String,String> created_on;
public String postKey;
public Comment() {
}
public Comment(String reactUserId, String comment, String postKey) {
this.reactUserId = reactUserId;
this.postKey = postKey;
this.comment = comment;
this.created_on = ServerValue.TIMESTAMP;
}
public Map<String,Object> toMap(){
Map<String,Object> values = new HashMap<>();
values.put("userId",reactUserId);
values.put("postKey",postKey);
values.put("comment",comment);
values.put("created_on",created_on);
return values;
}
}// more getter and setters
// Stacktrace
10745-10745/com.dhiraj.firebaseapp E/AndroidRuntime: FATAL EXCEPTION: main
com.google.firebase.database.DatabaseException:
Expected a Map while deserializing, but got a class java.lang.Long
//JSON from Firebase DB
{
"Post-Comments" : {
"-KPE1qy6FgcwOnb1YXRw" :
"-KPE1zMFviLJvEKxexB7" : {
"AUTHOR" : "Dheeraj",
"comment" : "the first time I am not sure if you have any questions please ",
"created_on" : 1471278741281,
"postKey" : "-KPE1qy6FgcwOnb1YXRw",
"reactUserId" : "Dheeraj"
},
"-KPE221Xk5t9aMJfYoKD" : {
"AUTHOR" : "Dheeraj",
"comment" : "the first time I am not sure if you have any questions please ",
"created_on" : 1471278756332,
"postKey" : "-KPE1qy6FgcwOnb1YXRw",
"reactUserId" : "Dheeraj"
}
}
},
"Posts" : {
"-KPE1qy6FgcwOnb1YXRw" : {
"created on" : 1471278706910,
"desc" : "the only one who has been sent to you and your family and friends are invited to view the full image to open ",
"title" : "the following link ",
"userId" : "Dhiraj"
},
"-KPE1vlYc5vF7AyL2OHL" : {
"created on" : 1471278726738,
"desc" : "hi I was thinking that it will take place at all and all the best way is to have ",
"title" : "good afternoon ",
"userId" : "Dhiraj"
}
},
}
mFirebaseDatabaseReference = FirebaseDatabase.getInstance().getReference("Post-Comments")
Query queryRef = mFirebaseDatabaseReference.orderByKey();
queryRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot != null && dataSnapshot.getValue() != null) {
Log.e("Count ", "" + dataSnapshot.getChildrenCount());
Map<String, Object> objectMap = (HashMap<String, Object>)
dataSnapshot.getValue();
ArrayList<ItemsReceived> itemsReceivedList = new ArrayList<>();
for (Object obj : objectMap.values()) {
if (obj instanceof Map) {
Map<String, Object> mapObj = (Map<String, Object>) obj;
ItemsReceived itemsReceived = new ItemsReceived();
itemsReceived.setAccount((String) mapObj.get("AUTHOR"));
itemsReceived.setAdded((long) mapObj.get("comment"));
itemsReceivedList.add(itemsReceived);
Log.e(TAG, "Data is" + itemsReceived.getAdded());
}
}
itemsRecievedListAdapter = new ItemsRecievedListAdapter(MainActivity.this, itemsReceivedList);
mRecyclerView.setAdapter(itemsRecievedListAdapter);
//
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});`
Replace my variables where necessary i was just trying to make a point and not solve completely ...i hope it helps

Update ArrayAdapter with Firebase ChildEventListener()

I have a Firebase db structured like so:
{
"reviews" : {
"Star Trek Into Darkness" : {
"j" : {
"major" : "NONE",
"rating" : 3.0,
"username" : "j"
}
},
"Star Wars" : {
"badabing" : {
"major" : "Computer Science",
"rating" : 3.5,
"username" : "badabing"
},
"j" : {
"major" : "NONE",
"rating" : 5.0,
"username" : "j"
}
},
"Star Wars: The Clone Wars" : {
"j" : {
"major" : "NONE",
"rating" : 3.0,
"username" : "j"
}
},
"Star Wars: The Force Awakens" : {
"badabing" : {
"major" : "Computer Science",
"rating" : 5.0,
"username" : "badabing"
},
"j" : {
"major" : "NONE",
"rating" : 3.0,
"username" : "j"
}
}
}
There are movies under reviews and each movie has a username, major, and rating. I'm interested in getting those three children PER username (the parent of the three). What is supposed to be happening is when a user views the "Movie Details" screen of my app--they will see the reviews left by other users. Simple enough.
I'm having major difficulty with updating my custom ReviewAdapter. Currently, if we click on a movie that doesn't have a review--I can add them no problem. I can even submit an edit to the review I left. The only issue is that the submitted review submits two reviews--so I end up with a duplicate until I leave the activity and come back.
My issue can be seen in this recording here. (No sound)
I suspect it has something to do with the way I'm using Firebase's childEventListener(), but I couldn't figure out what to change after spending 4hrs+ on this issue alone.
MovieDetailActivity.java
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_movie_detail);
ButterKnife.bind(this);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
Intent intent = getIntent();
Bundle bundle = intent.getExtras();
if (bundle != null) {
mMovieTitle = (String) bundle.get("title");
mTempMovieTitle.setText(mMovieTitle);
}
setupReviews(); //calling it here
}
public void leaveReview() {
//get current username
final String currentUser = SessionManager.getInstance(MovieDetailActivity.this).getLoggedInUsername();
final MaterialDialog reviewDialog = new MaterialDialog.Builder(MovieDetailActivity.this)
.title(leaveReviewTitle)
.customView(R.layout.rating_movie_dialog, true)
.theme(Theme.DARK)
.positiveText(save)
.negativeText(cancel)
.onPositive(new MaterialDialog.SingleButtonCallback() {
#Override
public void onClick(#NonNull MaterialDialog reviewDialog, #NonNull DialogAction which) {
final RatingBar ratingBar = ButterKnife.findById(reviewDialog, R.id.rating_bar);
final double rating = ratingBar.getRating(); //get the rating
/*Get Major from Firebase, and also store the review while we're at it*/
mUserRef.child(currentUser).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String major = dataSnapshot.child("major").getValue(String.class);
final Firebase reviewRef = mReviewRef.child(StringHelper.reviewHelper(mMovieTitle, currentUser));
reviewRef.child("username").setValue(currentUser);
reviewRef.child("major").setValue(major);
reviewRef.child("rating").setValue(rating);
setupReviews(); //and here
}
#Override
public void onCancelled(FirebaseError firebaseError) {
}
});
}
}).build();
//Leave review as {current_username}
TextView reviewee = ButterKnife.findById(reviewDialog, R.id.reviewee);
reviewee.append(" " + (Html.fromHtml("<b>" + currentUser + "</b>"))); //bold the username text
reviewDialog.show();
}
/**
* *ATTEMPTS* to add and update the reviews list per each movie. It's hacky and I hate it.
*/
private void setupReviews() {
mReviewRef.child(mMovieTitle).addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String previousChildKey) {
ArrayList<String> usernames = new ArrayList<>();
ArrayList<String> majors = new ArrayList<>();
ArrayList<Double> ratings = new ArrayList<>();
ArrayList<Review> reviews = new ArrayList<>();
//iterate through all of the reviews for the movie
for (DataSnapshot child : dataSnapshot.getChildren()) {
switch(child.getKey()) {
case ("username"):
usernames.add(child.getValue(String.class));
break;
case ("major"):
majors.add(child.getValue(String.class));
break;
case ("rating"):
ratings.add(child.getValue(Double.class));
break;
}
}
if (!usernames.isEmpty()) { //only want to iterate if we're rating a movie that already has reviews
for (int i = 0; i < usernames.size(); ++i) {
try {
reviews.add(new Review(usernames.get(i), majors.get(i), ratings.get(i)));
} catch (IndexOutOfBoundsException ioobe) {
}
}
}
if (mReviewAdapter == null) {
mReviewAdapter = new ReviewAdapter(MovieDetailActivity.this,
R.layout.review_list_item, reviews);
mMovieReviewsList.setAdapter(mReviewAdapter);
} else {
try {
mReviewAdapter.addAll(reviews);
mMovieReviewsList.setAdapter(mReviewAdapter);
mReviewAdapter.notifyDataSetChanged();
} catch (NullPointerException npe) {
}
}
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String previousChildKey) {
ArrayList<String> usernames = new ArrayList<>();
ArrayList<String> majors = new ArrayList<>();
ArrayList<Double> ratings = new ArrayList<>();
ArrayList<Review> reviews = new ArrayList<>();
//iterate through all of the reviews for the movie
for (DataSnapshot child : dataSnapshot.getChildren()) {
switch(child.getKey()) {
case ("username"):
usernames.add(child.getValue(String.class));
System.out.println("username " + child.getValue(String.class));
break;
case ("major"):
majors.add(child.getValue(String.class));
System.out.println("major " + child.getValue(String.class));
break;
case ("rating"):
ratings.add(child.getValue(Double.class));
break;
}
}
if (mReviewAdapter != null) {
mReviewAdapter.clear();
}
if (!usernames.isEmpty()) {
for (int i = 0; i < usernames.size(); ++i) {
try { //I hate that checking if Usernames != empty isn't enough, and this is
//the only way I could get it to work...
reviews.add(new Review(usernames.get(i), majors.get(i), ratings.get(i)));
} catch (IndexOutOfBoundsException ioobe) {
}
}
}
if (mReviewAdapter == null) {
mReviewAdapter = new ReviewAdapter(MovieDetailActivity.this,
R.layout.review_list_item, reviews);
mMovieReviewsList.setAdapter(mReviewAdapter);
} else {
try {
mReviewAdapter.addAll(reviews); //this might break it
mMovieReviewsList.setAdapter(mReviewAdapter);
mReviewAdapter.notifyDataSetChanged();
} catch (NullPointerException npe) {
}
}
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String previousChildKey) {
}
#Override
public void onCancelled(FirebaseError firebaseError) {
}
});
}
You would need to use Push method for this to have their own Unique Key. You are using a key with the Username of the logged user. You need to do something like this.
{
"reviews" : {
"Star Trek Into Darkness" : {
"-K3dksosdfify" : {
"major" : "NONE",
"rating" : 3.0,
"username" : "j"
}
},
"Star Wars" : {
"-K3dksosdfify2" : {
"major" : "Computer Science",
"rating" : 3.5,
"username" : "badabing"
},
"-K3dksosdfify4" : {
"major" : "NONE",
"rating" : 5.0,
"username" : "j"
}
},
"Star Wars: The Clone Wars" : {
"-K3dksosdfify10" : {
"major" : "NONE",
"rating" : 3.0,
"username" : "j"
}
},
"Star Wars: The Force Awakens" : {
"-K3dksosdfify11" : {
"major" : "Computer Science",
"rating" : 5.0,
"username" : "badabing"
},
"-K3dksosdfify123" : {
"major" : "NONE",
"rating" : 3.0,
"username" : "j"
}
}
}
The Dashes is FireBase Generated. Check the push method in the Official Document
Now everytime you use push. It will generate a Unique key so The property of the other Rating will not be disturbed.
so something like this.
Firebase ref = new Firebase(yourURLtoReviews);
ref.child(SELECTEDMOVIES);
Map<String, String> post1 = new HashMap<String, String>();
post1.put("major", "gracehop");
post1.put("rating", "3.0");
post1.put("username", "Hwoarang");
ref.push().setValue(post1);
Now you don't need to care about the keys anymore. All you have to do is
ref.onChildAdded blah blah blah, itterate it with for loop and you're done.

Categories

Resources