I am currently using the Firebase github example to create an app where users register and can post "status updates." I am able to do that correctly, but now I would like to add more parameters, like user location (latitude and longitude), but I am not sure where I would place this at. I am not sure at what point everything that is going to be added is added. Here is my current code:
NewPostActivity:
private DatabaseReference mDatabase;
private EditText mTextField;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_new_post);
mDatabase = FirebaseDatabase.getInstance().getReference();
mTextField = (EditText) findViewById(R.id.postText);
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fabSubmitPost);
assert fab != null;
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
submitPost();
}
});
}
private void submitPost() {
final String text = mTextField.getText().toString();
if (TextUtils.isEmpty(text)) {
mTextField.setError("Required");
return;
}
final String userId = getUid();
mDatabase.child("users").child(userId).addListenerForSingleValueEvent new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
User user = dataSnapshot.getValue(User.class);
if (user == null) {
Toast.makeText(NewPostActivity.this, "Could not fetch user", Toast.LENGTH_SHORT).show();
} else {
writeNewPost(userId, user.username, text);
}
finish();
}
#Override
public void onCancelled(DatabaseError databaseError) {
Toast.makeText(NewPostActivity.this, databaseError.toString(), Toast.LENGTH_SHORT).show();
}
});
}
private void writeNewPost(String userId, String username, String text) {
String key = mDatabase.child("posts").push().getKey();
Post post = new Post(userId, username, text);
Map<String, Object> postValues = post.toMap();
Map<String, Object> childUpdates = new HashMap<>();
childUpdates.put("/posts/" + key, postValues);
childUpdates.put("/user-posts/" + userId + key, postValues);
mDatabase.updateChildren(childUpdates);
}
and this is the post file:
public class Post {
public String uid;
public String author;
public String text;
public int likeCount = 0;
public Map<String, Boolean> likes = new HashMap<>();
public Post() {
}
public Post(String uid, String author, String text) {
this.uid = uid;
this.author = author;
this.text = text;
}
#Exclude
public Map<String, Object> toMap() {
HashMap<String, Object> result = new HashMap<>();
result.put("uid", uid);
result.put("author", author);
result.put("text", text);
result.put("likeCount", likeCount);
result.put("likes", likes);
return result;
}
}
In order to add Latitude & Longitude when you save a Post you can add both the parameters to your existing class, you will need to modify Post class constructor to add 2 more arguments like :
public double lat,lng;
public Post(String uid, String author, String text,double lat,double lng) {
this.uid = uid;
this.author = author;
this.text = text;
this.lat = lat;
this.lng = lng;
}
then in your toMap function you can add the parameters to result like :
result.put("lat", lat);
result.put("lng", lng);
So when you call the constructor in your writeNewPost function you can change this line :
Post post = new Post(userId, username, text);
to
Post post = new Post(userId, username, text, lat, lng);
now your new post will be posted alongwith with latitude and longitude
i am assuming that you already have the latitude and longitude with you
Update
As you want to see the Posts that are posted within a Location you have posted them, you can do something like this,
In the Firebase query where you are querying the posts you can add orderByChild and equalTofilter to compare with current latitude & Longitude,
and if you want filter them based on some distance then you will have to query all the posts and then compare them locally
Related
in my case, I can add different documents and different fields to my data collection in my firestore database. that means add curd operation is working well but I want complete my delete and update function to fulfill my application. my problem is I can't edit/delete my "description" and "title". I have initialized the variable as "DocumentReference" I think the problem is having that. anyone feel free to help me to solve this issue. thank you!
i have to make EDIT and DELETE functions. but them not working with every documents
public class MainActivity extends AppCompatActivity {
FirebaseAuth fAuth;
private static final String TAG = "MainActivity";
private static final String KEY_TITLE = "title";
private static final String KEY_AUDIOLIST = "audiolist";
private EditText editTextTitle;
private EditText editTextAudiolist;
private TextView textViewData;
private FirebaseFirestore db = FirebaseFirestore.getInstance();
private CollectionReference notebookRef = db.collection("Category");
private DocumentReference noteRef = db.document("Category/mindRelax");
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
editTextTitle = findViewById(R.id.edit_text_title);
editTextAudiolist = findViewById(R.id.edit_text_audioList);
textViewData = findViewById(R.id.text_view_data);
}
#Override
protected void onStart() {
super.onStart();
notebookRef.addSnapshotListener(this, new EventListener<QuerySnapshot>() {
#Override
public void onEvent(QuerySnapshot queryDocumentSnapshots, FirebaseFirestoreException e) {
if (e != null) {
return;
}
String data = "";
for (QueryDocumentSnapshot documentSnapshot : queryDocumentSnapshots) {
Note note = documentSnapshot.toObject(Note.class);
note.setDocumentId(documentSnapshot.getId());
String documentId = note.getDocumentId();
String title = note.getTitle();
String audiolist = note.getAudiolist();
data += "ID: " + documentId
+ "\nTitle: " + title + "\nAudiolist: " + audiolist + "\n\n";
}
textViewData.setText(data);
}
});
}
public void addNote(View v) {
String title = editTextTitle.getText().toString();
String audiolist = editTextAudiolist.getText().toString();
Note note = new Note(title, audiolist);
notebookRef.add(note);
}
public void loadNotes(View v) {
notebookRef.get()
.addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
#Override
public void onSuccess(QuerySnapshot queryDocumentSnapshots) {
String data = "";
for (QueryDocumentSnapshot documentSnapshot : queryDocumentSnapshots) {
Note note = documentSnapshot.toObject(Note.class);
note.setDocumentId(documentSnapshot.getId());
String documentId = note.getDocumentId();
String title = note.getTitle();
String audiolist = note.getAudiolist();
data += "ID: " + documentId
+ "\nTitle: " + title + "\nAudiolist: " + audiolist + "\n\n";
}
textViewData.setText(data);
}
});
}
public void updateAudiolist(View v) {
String audiolist = editTextAudiolist.getText().toString();
String title = editTextTitle.getText().toString();
Map<String, Object> note = new HashMap<>();
note.put( KEY_AUDIOLIST, audiolist);
note.put( KEY_TITLE, title);
noteRef.set(note, SetOptions.merge());
noteRef.update(KEY_TITLE,title, KEY_AUDIOLIST, audiolist);
}
public void deleteAudiolist(View v) {
Map<String, Object> note = new HashMap<>();
note.put(KEY_AUDIOLIST, FieldValue.delete());
noteRef.update(note);
noteRef.update(KEY_AUDIOLIST, FieldValue.delete());
}
public void deleteNote(View v) {
noteRef.delete();
}
public void logout (View view){
FirebaseAuth.getInstance().signOut();
startActivity(new Intent(getApplicationContext(),Login.class));
finish();
}
}
I am trying to update my databse:
This is my code, but it doesn't seem to update the database. (Write access is set to true in Firebase settings)
DatabaseReference ref = FirebaseDatabase.getInstance().getReference();
ref.child("items").child("1").child("itemAvailability").setValue("Not Available");
Java class
public class Item {
String itemName;
String itemAvailability;
public Item(String itemName, String itemAvailability) {
this.itemName = itemName;
this.itemAvailability = itemAvailability;
}
public Item() {
}
public String getItemName() {
return itemName;
}
public void setItemName(String itemName) {
this.itemName = itemName;
}
public String getItemAvailability() {
return itemAvailability;
}
public void setItemAvailability(String itemAvailability) {
this.itemAvailability = itemAvailability;
}
}
You can do something like this with a Map Data structure.
DatabaseReference ref = FirebaseDatabase.getInstance().getReference();
DatabaseReference itemRef = ref.child("items/1/itemAvailability");
Map<String, Object> itemUpdates = new HashMap<>();
itemUpdates.put("itemAvailability", "Not Available");
itemRef.updateChildrenAsync(itemUpdates);
This will take the item 1's availability and update it's availability to Not Available
DatabaseReference ref = FirebaseDatabase.getInstance().getReference();
ref.child("items").child("1").addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
HashMap<String, Object> updateMap = new HashMap<>();
updateMap.put("itemAvailability", "Not Available");
ref.updateChildren(updateMap);
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
Might work for you.
Here is the code for Firebase real-time database Insert, Update & Delete operation(CRUD).
//****UPDATE
var database = firebase.database();
let userRef = database.ref('myroot/items/');
userRef.child("1").child("itemAvailability").update("Not Available").then().catch();
//****Insert
var database = firebase.database();
let userRef = database.ref('myroot/items/');
userRef.child("1").child("itemAvailability").set("Not Available").then().catch();
//****Delete
let itemId=1;
let userRef = database.ref('myroot/items/' + itemId);
userRef.remove().then().catch();
The issue is that for my markers on the map I have the title which is fine, and then for the snippet() I inserted the postId so that later I can use that postId for the OnInfoWindowClickListener to search for it in the database and if it matches it takes the user to the PostDetailFragment which has all the post's data...
Obviously I don't want the user to see the postId when they click on the marker the info Window comes up, but at that moment the snippet should hide, so I need to replace it, or make it invisible, or GONE...
Also, to identify the markers I tried using setTag() and getTag(), but it didn't work.
Suggestions? I need to hide or make invisible the snippet in each tag so the users don't see the postid, BUT I need the postId to run the query in the database.
Maybe there's a better way to do this?
MapFragment
LatLng latLng = new LatLng(latitude, longitude);
// MarkerOptions markerOptions = new MarkerOptions().position(latLng).title(post.getText_event()).snippet(post.getText_location() + " \u25CF " + post.getTime());
MarkerOptions markerOptions = new MarkerOptions().position(latLng).title(post.getText_event()).snippet(post.getPostid());
markerOptions.icon(BitmapDescriptorFactory.defaultMarker());
mGoogleMap.addMarker(markerOptions);
// Info Window
mGoogleMap.setOnInfoWindowClickListener(marker -> {
DatabaseReference databaseReference = FirebaseDatabase.getInstance().getReference("Posts");
databaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot1) {
for (DataSnapshot snap : snapshot1.getChildren()) {
Post pos = snap.getValue(Post.class);
if (pos != null) {
if (marker.getSnippet().equals(pos.getPostid())) {
SharedPreferences.Editor editor = getActivity().getSharedPreferences("PREFS", Context.MODE_PRIVATE).edit();
editor.putString("postid", marker.getSnippet());
editor.apply();
getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new PostDetailFragment(), null).addToBackStack(null).commit();
}
}
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
});
}
Using the default marker has some of those limitations.
What you should do is create a class called CustomMarker that implements ClusterItem then you can use that as the Marker.
ClusterItem is simply a Marker.
public class Marker implements ClusterItem {
private final LatLng positiond;
private final String markerId;
private final String title;
private final String tag;
private final Post post;
private final String snippet;
public Marker(LatLng positiond, String markerId, String title, String snippet, Post post,String tag) {
this.positiond = positiond;
this.markerId = markerId;
this.title = title;
this.snippet = snippet;
this.post=post;
this.tag=tag;
}
#Override
public LatLng getPosition() {
return positiond;
}
#Override
public String getTitle() {
return title;
}
#Override
public String getSnippet() {
return snippet;
}
public String getMarkerId() {
return markerId;
}
public Post getPost() {
return post;
}
public String getTag() {
return tag;
}
}
The above is a Marker. Then you can just pass the Post into the Marker like so above.
When you create the marker/clusterItem you can pass the MarkerID as the PostId then when you click it. you can get the markerID then perform any of the logic you want.
Currently a have a floating action bottom in my detailView in this activity I bring the information of the Object with an intent. I want that when the user enters the detailView activity I have a filled heart if that Automoviles objectId already exist in the Favorites Node.if not add the information into the Database. If the favorite already exist and it has the filled heart if the user clicks again it will remove it from the database.
This is my favorites class:
public class Favorites {
private String id;
private String automovilesId;
private String userId;
private String fecha;
public Favorites() {
}
public Favorites(String automovilesId, String userId, String fecha) {
this.automovilesId = automovilesId;
this.userId = userId;
this.fecha = fecha;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getAutomovilesId() {
return automovilesId;
}
public void setAutomovilesId(String automovilesId) {
this.automovilesId = automovilesId;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getFecha() {
return fecha;
}
public void setFecha(String fecha) {
this.fecha = fecha;
}
}
At the moment i have this code:
databaseReference = FirebaseDatabase.getInstance().getReference(AppModel.Favorites);
favoritesButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
final DatabaseReference usersRef = rootRef.child("Favorites");
favorites = new Favorites(automoviles.getObjectId(), user.getUid(), AppModel.GetDate());
databaseReference.push().setValue(favorites);
}
});
Which Leads this entry in the database:
Firebase Data
This is all good but i need to verify also if favorites exist or not in the database or else everytime i run the android emulator it will create another favorites node.
Now i added more code . But when i run it and i add this AddFavorite method it will create infinite loops of Favorite Nodes in the database
databaseReference = FirebaseDatabase.getInstance().getReference(AppModel.Favorites);
favoritesButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
final DatabaseReference usersRef = rootRef.child("Favorites");
favorites = new Favorites(automoviles.getObjectId(), user.getUid(), AppModel.GetDate());
databaseReference.push().setValue(favorites);
usersRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for(DataSnapshot ds : dataSnapshot.getChildren()) {
String car = ds.child("automovilesId").getValue(String.class);
Favorites fav =ds.getValue(Favorites.class);
String carId =fav.getAutomovilesId();
Log.i("No","Este es el nombre------>:"+carId);
String id=ds.getKey();
AddFavoritesuser();
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
});
This is the AddFavorite method and the delete method:
private void AddFavoritesuser() {
favoritesButton.setImageResource(R.drawable.ic_favorite);
favorites = new Favorites(automoviles.getObjectId(), user.getUid(), AppModel.GetDate());
databaseReference.push().setValue(favorites);
}
And the delete:
private void deleteFavoritesUser(String key) {
favoritesButton.setImageResource(R.drawable.ic_favorite_border);
databaseReference.child(key).getRef().removeValue();
}
In short i want it to verify if that object of Automoviles object exist . If it exist the user enters and sees the filled heart, if he wants to delete this favorite then he clicks again and it will run the deleteFavoritesUser method. But my question is what if Favorites is still no created in the database how can i also validate this?.
I runned the app again and I have the same vale created again:
As you can see I have the same automovilesId entry
basically you need to make your favorite button as a toggle button
favoritesButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// in place of YES/NO you can take any values to present true/false state
boolean status = v.getTag() != null ? v.getTag().equals("YES") : false;
v.setTag(status ? "NO" : "YES");
if (status) {
// Do favorite me
//AddFavoritesuser();
} else {
// Do un favorite me
//deleteFavoritesUser(key);
}
}
}
everytime i run the android emulator it will create another favorites node.
This is happening because everytime you are trying to add a new object of Favorites class to the database, you are using the push() method, which generates a new random key everytime is called. This is what this method does. So in order to check a property from the database, you need to use in your reference the same key, not to generate another one. Please see in my answer from this post, where I have explained how you can achieve this.
I am using Firebase with my Android application. I am trying to use Firebase as a NOSQL database and this is my data retrieval object.
public class FirebaseManager {
private static final String DB_REF = "mainframeradio";
private static final String STREAM_REF = "streams";
public static List<MediaStream> getMediaStreams(Context context) {
final List<MediaStream> mediaStreams = new ArrayList<>();
FirebaseDatabase db = FirebaseDatabase.getInstance();
DatabaseReference dbRef = db.getReference(STREAM_REF);
dbRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Map<String, Object> streams = (Map<String, Object>) dataSnapshot.getValue();
if (!streams.isEmpty()) {
for (Object stream : streams.values()) {
String protocol = (String) ((Map) stream).get("protocol");
String host = (String) ((Map) stream).get("host");
int port = (int) ((Map) stream).get("port");
String media = (String) ((Map) stream).get("media");
String metadata = (String) ((Map) stream).get("metadata");
String streamName = (String) ((Map) stream).get("streamName");
MediaStream mediaStream = new MediaStream(protocol, host, port, media, metadata, streamName);
mediaStreams.add(mediaStream);
}
} else {
L.d("No media streams found on the server.");
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
L.w("Couldn't read the stream info from Firebase.");
}
});
return mediaStreams;
}
}
The thing is the event does not get triggered from the activity I am calling it from.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_player);
// Set components.
this.playerView = findViewById(R.id.playerView);
this.songTitleTextView = findViewById(R.id.songTitleTextView);
this.albumArt = findViewById(R.id.albumArt);
// Hide both the navigation and status bar (immersive).
ViewManager.setFullscreenImmersive(getWindow());
List<MediaStream> mediaStreams = FirebaseManager.getMediaStreams(this);
System.out.print(mediaStreams);
}
All I want to do is retrieve the data from firebase. This is the database.
Any help would be appreciated.
Try this to retrieve the data:
DatabaseReference reference = FirebaseDatabase.getInstance().getReference("streams");
reference.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot datas: dataSnapshot.getChildren()){
String hosts=datas.child("host").getValue().toString();
String medias=datas.child("media").getValue().toString();
String metadata=datas.child("metadata").getValue().toString();
String ports=datas.child("port").getValue().toString();
String protocol=datas.child("protocol").getValue().toString();
String steamname=datas.child("streamName").getValue().toString();
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
the datasnapshot is streams,you then will be able to iterate inside the child 0 and get the data