This is an extension of Android implement Parcelable objects with hashmap that contains another hashmap where I was having trouble passing 2 classes between activities using Parcelable.
I'm now able to successfully pass both classes together using Parcelable. However, I'm having trouble putting the retrieved data into an array list.
Here's the EventDetails class:
public class MatchedEvent implements Parcelable {
Private String eventId;
Private String eventName;
Private Long eventUnixTime;
Private Map <String, User> attendees = new HashMap<String, User>();
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(eventId);
dest.writeString(eventName);
dest.writeLong(eventUnixTime);
final int N = attendees.size();
dest.writeInt(N);
if (N > 0) {
for (Map.Entry<String, User> entry : attendees.entrySet()) {
dest.writeString(entry.getKey());
User user = entry.getValue();
dest.writeString(user.getEmail());
dest.writeString(user.getUserName());
dest.writeString(user.getUserPicture());
}
}
}
protected MatchedEvent(Parcel in) {
eventId = in.readString();
eventName = in.readString();
eventUnixTime = in.readLong();
final int N = in.readInt();
for (int i = 0; i < N; i++) {
String key = in.readString();
User user = new User();
user.email = in.readString();
user.userName = in.readString();
user.userPicture = in.readString();
attendees.put(key, user);
}
}
public Map<String, User> getAttendees() {
return attendees;
}
Here's the User class:
public class User implements Parcelable {
public String email;
public String userName;
public String userPicture;
private Boolean hasLoggedInWithPassword;
private HashMap<String, Object> dateJoined = null;
}
public User(Parcel in) {
email = in.readString();
userName = in.readString();
userPicture = in.readString();
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(email);
dest.writeString(userName);
dest.writeString(userPicture);
}
Here's the Fragment to retrieve the data. The EventDetails class should return a few Users. My goal is to display the name of all Users in a TextView that lists out the names with a line break. I was able to retrieve the users in an array but was not able to create an array just for the userName.
public class EventDetailsFragment extends BaseFragment {
TextView attendees;
private Map<String, User> attendeeMap;
#Override
public void onCreate(Bundle savedInstanceState) {
MatchedEvent matchedEvent = getArguments().getParcelable("eventDetailsData");
attendeesMap = matchedEvent.getAttendees();
List<User> users = new ArrayList<>();
for (String key : attendeesMap.keySet()) {
User user = attendeesMap.get(key);
users.add(user);
Log.i("Attendees Details", String.valueOf(user)); //I was able to get all users in this log.
ArrayList<String> attendeesDetails = new ArrayList<>();
attendeesDetails.add(user.getEmail());
attendeesDetails.add(user.getUserName());
attendeesDetails.add(user.getUserPicture());
for (User user1 : users) {
Log.i("Attendees Details", String.valueOf(attendeesDetails)); //?????????????????
}
}
}
The problem is where i put the mark "//?????????????????".
I'm getting duplicate data. I know I shouldn't be putting a loop inside another loop. Can someone please advise how I can break this down? My goal is to put all the users' names in an array and display them in the TextView with a line break after each name.
This is what I got from the log:
I/Attendees Details: com.test.entities.User#f2b14s9
I/Attendees Details: [user1#gmail.com, Deric, https://dropbox.xxxxxx]
I/Attendees Details: com.test.entities.User#e6s26k2
I/Attendees Details: [user2#gmail.com, Jose, https://dropbox.xxxxxxxxx]
I/Attendees Details: [user2#gmail.com, Jose, https://dropbox.xxxxxxxxx]
I/Attendees Details: com.text.entities.User#b9k03l6
I/Attendees Details: [user3#gmail.com, Matt, https://dropbox.xxxxxxxxxxxxx]
I/Attendees Details: [user3#gmail.com, Matt, https://dropbox.xxxxxxxxxxxxx]
I/Attendees Details: [user3#gmail.com, Matt, https://dropbox.xxxxxxxxxxxxx]
I believe the reason why there are duplicate entries is because "attendeesDetails" is inside the loop “attendeesMap” where I got the key of each user. I’m not sure how to separate them but still able to get the data.
Thanks in advance for helping out.
-R
this will help you:
#Override
public void onCreate(Bundle savedInstanceState) {
EventDetails eventDetails = getArguments().getParcelable("eventDetailsData");
attendeesMap = eventDetails.getAttendees();
List<User> users = new ArrayList<>();
for (String key : attendeesMap.keySet()) {
User user = attendeesMap.get(key);
users.add(user);
Log.i("Attendees Details", String.valueOf(user)); //I was able to get all users in this log.
attendees.append(user.getEmail()+user.getUserName()+user.getUserPicture()+"\n");
}
I think I'd resolved the problem. I actually need to create an ArrayList<HashMap<String, String>> to store the details for each and every user first. Then, I'll be able to create another array list to store the names. No more nested loops.
List<User> users = new ArrayList<>();
ArrayList<HashMap<String, String>> userArrayList = new ArrayList<HashMap<String, String>>();
HashMap<String, String> usersDetailsHashMap = new HashMap<String, String>();
ArrayList attendeesNames = new ArrayList();
for (String key : attendeesMap.keySet()) {
User user = attendeesMap.get(key);
users.add(user);
usersDetailsHashMap.put("name", user.getUserName());
usersDetailsHashMap.put("email", user.getEmail());
usersDetailsHashMap.put("picture", user.getUserPicture());
userArrayList.add(usersDetailsHashMap);
attendeesNames.add(userArrayList.get(0).get("name"));
}
Log.i("userNames", String.valueOf(attendeesNames));
This will return in the log:
[Deric, Jose, Matt]
Related
So, i am creating a virtual assistant app which after listening to user suppose to update the ui and then take another input but it updating the ui at once and then listening and speaking at once and taking no input
messageHolder = "The Global text get from Recognizer";
private void sendChatMessage(boolean side){
if(side != true){
tts.speak(messageHolder,TextToSpeech.QUEUE_ADD,null);
}
chatArrayAdapter.add(new ChatMessage(side,messageHolder));
chatArrayAdapter.notifyDataSetChanged();
}
startSpeechToText() -> get the result from the speechrecognizerIntent
private class SeprateQuery extends AsyncTask<String,String,query>{
#Override
protected query doInBackground(String... strings) {
String v_query = strings[0].toString();
Log.e("APP","String recieved inn seprateQuery and is"+v_query);
if(v_query.indexOf("create contact")!=-1){
v_query = v_query.replace("create contact ","");
return new query(4,v_query);
return new query(-1,"null");
}
#Override
protected void onPostExecute(query code) {
super.onPostExecute(code);
if(code.code==4){
messageHolder = "Enter the name";
sendChatMessage(false);
startSpeechToText(speechRecognizerIntent,false);
String name = messageHolder;
messageHolder = "Enter the number";
sendChatMessage(false);
startSpeechToText(speechRecognizerIntent,false);
String contact = messageHolder;
addContact(name,contact);
//addContact(name,contact);
}else
is there any way i can perform the code in onPostExecute procedurally one by one instead ui updating at once without listening to users
Am trying to get data from 3 tables and every time I end up getting an error
Ljava.lang.Object; cannot be cast to .model.ISECO at
java.util.ArrayList.forEach
This are my entities
#Entity
public class IS01 {
private String IEA;
private String INUM;
private String ILINE;
private String I0103;
#Entity
public class ISOVER {
private String IEA;
private String ILINE;
private String INUM;
private String IRESULT;
private String ICON;
private String IBCON;
private String CASE;
private String RPTID
#Entity
public class POSTCO {
private String CEA;
private String CNUM;
private String CLINE;
private String PSCONTACT;
And this is my Repository
public interface LineSummary extends CrudRepository<ISOVER , String> {
#Query("select c.ILINE , c.IRESULT,e.PSCONTACT, \n" +
"c.ICON,c.IBCON, c.RPTID, c.CASE, d.i0103 as age\n" +
"FROM ISOVER c \n" +
"inner join IS01 d \n" +
"on c.IEA = d.IEA and c.INUM = d.INUM and c.ILINE = d.ILINE\n" +
"inner join POSTCO e on d.IEA = e.CEA and d.INUM = e.CNUM and d.ILINE = e.CLINE\n" +
"where c.CASE like %?1%")
Iterable<ISOVER> findEntriesByUserId(#Param("Case") String Case);
And this is my service
public ResponseEntity<Map<String, Object>> retrieveLineListingSQL(String Case){
Iterable <ISOVER > stud = lineSummary.findEntriesByUserId(Case);
Map<String, Object> parents = new HashMap<>();
parents.put("totalMembers", 9);
parents.put("questionaryinfo", new ArrayList<HashMap<String,Object>>());
ArrayList<HashMap<String,Object>> listings = (ArrayList<HashMap<String,Object>>) parents.get("questionaryinfo");
if (stud != null) {
stud.forEach(d -> {
HashMap<String,Object> entry = new HashMap<>();
entry.put("adultquestionary","Yes");
entry.put("caseNumber", d.getCASE());
listings.add(entry);
});
}
parents.put("DMStatus", "No review");
parents.put("ages", new HashMap<String, Object>());
return ResponseEntity.ok().body(parents);
}
How can I return the results from the query and map them accordingly?
I believe this is your culprit:
if (stud != null) {
stud.forEach(d -> {
HashMap<String, Object> entry = new HashMap<>(); // < -- here
entry.put("adultquestionary","Yes");
entry.put("caseNumber", d.getCASE());
listings.add(entry);
});
}
Have your tried using *.model.ISECO instead of java.lang.Object? Does that work, any particular limitation?
Additionally, you could refactor you code to something way more simple, if you follow the same explanation provided in here: How to make nested JSON response with Array from a Stored procedure
Create a response model that outputs the format you expect as response.
There is no need for you to do all that collections handling one-by-one. The representation of an object in JSON is a MAP, basically let the
Jackson JSON library do all that work for you.
Cut to the chase:
I've got a class User, which holds an instance of Security:
public class User {
private long id;
private String name;
Security security;
public User(String nname, String password, String userName, String email) {
this.id = 0;
this.name = nname;
this.security = new Security(password, userName, email);
}
/**
* getters and setters
*/
}
Yes, the id is currently temporary for testing, and Security has a very similar format.
Next I run this code for setting up my firebase entry:
FirebaseApp app = FirebaseApp.initializeApp(options);
this.db = com.google.firebase.cloud.FirestoreClient.getFirestore(app);
ApiFuture<WriteResult> collectionsApiFuture =
db.collection("users").document(user.getName()).set(user);
System.out.println(collectionsApiFuture.get().getUpdateTime().toString());
And I use this as my test data:
FirebaseInitialise testFirebase = new FirebaseInitialise();
User tempUser = new User("Ollie", "123", "OlliesRealm", "email#mail.com");
testFirebase.initialize(tempUser);
However, when I run the code, the relation appears in the firestore application as:
id: 0
name: "Ollie"
security:
unlocked: true
userName: "OlliesRealm"
I would like it to either properly hold the full information for security, which it seems to be unable to do, or to just hold an ID of it without actually having the security info stored in user.
If anyone could suggest anything or help me out that would be greatly appreciated!!
To be able to get Security as a full object you just need to save it specifically when uploading on the Firestore database.
#Override
public String createUser(user user) {
String id = UUID.randomUUID().toString();
DocumentReference document = userCollection.document(id);
Map<String, Object> data = Maps.newHashMap();
data.put("name", user.getName());
data.put("security", user.getSecurity());
try {
document.set(data).get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
If you want to have them separately you just need to create a different collection for the Security and save it there with something like that:
#Override
public String createUser(user user) {
String id = UUID.randomUUID().toString();
DocumentReference userDocument = userCollection.document(id);
DocumentReference securityDocument = SecurityCollection.document(id);
Security temp = user.getSecurity();
Map<String, Object> userData = Maps.newHashMap();
Map<String, Object> securityData = Maps.newHashMap();
userData.put("name", user.getName());
userData.put("security", user.getSecurity());
securityData.put("username", security.getUserName());
securityData.put("password", security.getPassword());
securityData.put("email", security.getEmail());
try {
userDocument.set(userData).get();
securityDocument.set(securityData).get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
I have an ArrayList of Objects in Firebase and I would like to retreive it.
I have 2 array lists. One String and one Grade. When I try to use the array of objects it has a problem:
java.lang.ClassCastException: java.util.HashMap cannot be cast to com.example.gradecalculator.Grade
mDocRef:
private DocumentReference mDocRef = FirebaseFirestore.getInstance().document("myData/Arrays");
Uploading the arrays:
Map<String, Object> dataToSave = new HashMap<String, Object>();
dataToSave.put("StringsArray", stringGrades); // Save Strings Array
dataToSave.put("ObjectsArray", grades); // Save Objects Array
mDocRef.set(dataToSave).addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
Log.d(TAG, "Document has been saved!");
Toast.makeText(getApplicationContext(), "List has been saved successfully!", Toast.LENGTH_SHORT).show();
Downloading the arrays:
mDocRef.get().addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() {
#Override
public void onSuccess(DocumentSnapshot documentSnapshot) {
isListEmpty = false;
if (documentSnapshot.exists()) {
Map<String, Object> dataToLoad = (HashMap<String, Object>) documentSnapshot.getData();
stringGrades = (ArrayList<String>) dataToLoad.get("StringsArray");
grades = (ArrayList<Grade>) dataToLoad.get("ObjectsArray");
for (Grade grade : grades) { // <------------Fails here
System.out.println(grade.toString());
}
First time I'm trying to use Firebase. It seems that it saves the data in the server successfully. Any advice?
The get method of DocumentSnapshot return a List of Map :
List<Map<String, Object>>
You can create another class with your List :
class GradeContainer{
private List<Grade> grades;
public GradeContainer(){}
public List<Grade> getGrades(){
return grades;
}
}
And use dataToLoad.toObject() :
grades = List<Grade> dataToLoad.toObject(GradeContainer.class).getGrades();
You can read this documentation for more informations :
https://firebase.google.com/docs/reference/android/com/google/firebase/firestore/DocumentSnapshot?hl=en
And this tutorial :
https://medium.com/firebase-tips-tricks/how-to-map-an-array-of-objects-from-cloud-firestore-to-a-list-of-objects-122e579eae10
I am using an addChildEventListener on the users level of my firebase database which contains usernames email and latest_post. The recyclerView will only use latest_post which is optional and not all users will have it, so I need to filter the userPosts object so that it contains only the users that have the field `latest_post'. here is the event listener:
query.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String prevChildKey) {
User userPost = dataSnapshot.getValue(User.class);
System.out.println("User" + userPost.getUsername());
}
This is how I setUp the recyclerView cells:
void setPost(final User user) {
final Post post = user.getLatest_post();
final Long date = post.post_date;
final String post_id = post.getPost_id();
final String key = post.getPost_id();
final Integer reads = post.getReads();
final String titleString = post.getTitle();
final String bodyString = post.getBody();
final String usernameString = post.getAuthor();
final String category = post.getCategory();
final String author_id = post.getAuthor_id();
...
}
So unless I filter userPosts before I setUp the view it will crash because it will try even on the paths where there is no latest_post. How can I filter so that the object I use when setting up the recycler view only contains objects where latest_post is not null? I cannot change the database structure as this point. Thank you.
UPDATE:
By doing this I can see that It knows which values have latest_post and which don't, but im still not sure how to make it into a nice object I can do my setup with. I've updated the code like so:
query.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String prevChildKey) {
Post latestPost = dataSnapshot.child("latest_post").getValue(Post.class);
Boolean userPost = dataSnapshot.hasChild("latest_post");
System.out.println("User" + userPost);
System.out.println("latestPost" + latestPost);
}
So somehow I can just use the Post class contained in User:
void setPost(final Post post) {
final Post latest = post;
final Long date = latest.post_date;
final String post_id = latest.getPost_id();
final String key = latest.getPost_id();
final Integer reads = latest.getReads();
final String titleString = latest.getTitle();
final String bodyString = latest.getBody();
final String usernameString = latest.getAuthor();
final String category = latest.getCategory();
final String author_id = latest.getAuthor_id();
...
}
After a lot of research, it turns out you can order a query, for example:
query = query.child("users").orderByChild("latest_post")
This would allow the recycled view to work but once you scroll to a certain point, it would crash.
You cannot filter a query to exclude items that don't exist.
I had to create my own recycler adapter, and use a list of my post class, and then filter that list after querying the database.