I've learned how to add and delete from Firebase. It's quite straightforward.
My delete code which is activated when clicking the delete button, it's found in my adapter class (it's the only way I could get the delete button click registered correctly)
public void deleteJournal(int position) {
getSnapshots().getSnapshot(position).getReference().delete();
}
And to add (which is in another class)
CollectionReference diaryRef = FirebaseFirestore.getInstance()
.collection("Diary");
diaryRef.add(new Diary(growName, description, priority));
But I don't even know where to begin to update. I will be putting the edit code in the adapter class which will open a dialog window to edit values.
I know how to create the window and edit the values and set new variables for this data. But how do I make sure I'm applying this updated data to the document with the corresponding edit button that clicked? Then update Firebase correctly.
diaryRef.add(new Diary(growName, description, priority)).addOnSuccessListener(documentReference -> {
String id = documentReference.getId();
db.collection("Diary").document(id).update("entryId", id);
});
now you will have a unique id to delete or update the entry
But how do I make sure I'm applying this updated data to the document
In the same way, you are deleting the document. Please see the method below:
public void updateJournal(int position) {
Diary diary = getSnapshots().getSnapshot(position).toObject(Diary.class);
//Make the changes
}
Once you have the Diary object, you can make the desired updates and then write the document back to the database, as shown in your question.
Related
I'm creating an app on Android Studio with Java and Firestore that lets users make publications and show them on a Fragment with a RecyclerView. The users create a profile (name, avatar) that gets saved in a document named after the user UID inside a collection named "Users". The publications are saved into another collection named "Posts" (title, content, picture, avatar, name).
I wrote two queries, one to get the title and content from the posts from the "Posts" collection, as well as the UID, to then do the other query that gets the name and picture from the poster and then all of those fields go inside a "Post" object and sent to the ArrayList that fills the RecyclerView.
Problem: The posts load perfectly on the RecyclerView but the user picture (the one I'm getting from a different collection) is giving me lots of problems. Sometimes it loads, sometimes it doesn't, and sometimes it loads only for the first post or even the first three posts. I don't understand what could be wrong. I'm posting the code:
private void loadPosts() {
Query postQuery = collectionReferencePosts.orderBy("timestamp", Query.Direction.DESCENDING);
postQuery.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
for (QueryDocumentSnapshot document : task.getResult()) {
Post post = new Post();
post.setTitle(document.getString("title"));
post.setContent(document.getString("content"));
post.setImage(document.getString("image"));
String posterUid = document.getString("useruid");
DocumentReference docRef = collectionReferenceUsers.document(posterUid);
docRef.get().addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() {
#Override
public void onSuccess(DocumentSnapshot documentSnapshot) {
post.setName(documentSnapshot.getString("name").toString());
post.setAvatar(documentSnapshot.getString("image").toString());
}
});
postList.add(post);
postAdapter.notifyDataSetChanged();
}
}
});
}
If you want to display post details, along with user details at the same time, then you have to notify the adapter about the changes when the second request for getting the name and the image is complete. So you have to move the following two lines of code:
postList.add(post);
postAdapter.notifyDataSetChanged();
Right after:
post.setAvatar(documentSnapshot.getString("image").toString());
Besides that, there is another option that you should consider using, which is called denomalization. This means that you can add the name and the image of the user inside the post document. In this way, there is no need to perform the second query, since all the data already exists inside the post document. If you're new to NoSQL databases, this might sound some kind of weird, but I assure you it's quite common practice.
Please also note, that neither solution is better than the other. According to the number of changes that can occur in your app, regarding the update of name and user image, you have to check which solution is better to be used inside your project.
You can also take a look at the following post to have a better understanding of the asynchronous nature of Firebase API:
How to return a DocumentSnapShot as a result of a method?
I am programming an app for Android. I uploaded it to GitHub: app
I have a ViewPager (MainActivity.java) controlling two Fragments. On the first Fragment (FirstFragment.java) you can add People (People.java) which appears on the RecyclerView (also on FirstFragment.java). When you click one of the list items on the RecyclerView its details (name and id) appear on the second fragment (SecondFragment.java). The SecondFragment.java also contains a button you can delete the selected People with.
To store the People objects I used a List of People and managed it with the methods in PeopleLab.java. The program was working fine: I could add/remove People objects to the list and it appeared on the RecyclerView fine.
After that, I decided to replace the List with a database. It only meant creating the database (the 3 files in database folder) and editing the already existing and two new methods in PeopleLab.java. The other files remained untouched.
The database is working as expected (checked it with sqlite3), I can add/remove People like before and the queries work. My only problem is that the changes don't appear on the RecyclerView. But if I close and reopen the app, the changes appear.
It's like the RecyclerView doesn't care about the database in runtime, only do when the app starts (or closes, not sure).
Do you have any idea what could cause the problem? My only guess is I miss something about how Android apps handle databases.
P.S.: sorry for my English.
You do call notifyDataSetChanged() on the adapter but you don't provide any new data for that adapter.
In your FirstFragment :
private void updateUI() {
PeopleLab peopleLab = PeopleLab.get(getActivity());
List<People> peoples = peopleLab.getPeople();
if(mAdapter == null) {
mAdapter = new PeopleAdapter(peoples);
mRecyclerView.setAdapter(mAdapter);
} else {
// You actually have to change your dataset
mAdapter.changeDataSet(peoples);
}
}
And in your Adapter :
public void changeDataSet(List<People> people) {
this.mPeoples = people;
notifyDataSetChanged();
}
This some brutal way to do it though.
It would be better to notify your adapter on insertion / removal calling notifyItemInserted(int itemPosition) or notifyItemRemoved(int itemPosition). (And refreshing your dataset, by the way)
It will not work automatically.You can either use to notify the adapter the underlying data has been changed so that adapter can fetch and reload the data.It can be done using adapter.notifyDataSetChanged()
Or use can use CursorLoader to achieve the same
I am creating a TextBox dynamically ,I get the values from server ,values could be 5,some times 10 etc , so No of textboxes i create will be different..
After all textboxes created .
There is an update button in page , When i click on this update button , Whatever changes user may have entered in any of the textBox,should Need to go to the server .. That I am not able to do ..
below is the code where i create the textBoxes
public void fetchData(){
public void onSuccess(ArrayList<Details> result) {
for(int i =0;i<result.size();i++){
name = new TextBox();
name.setText(result.get(i).getName());
verticalPanel.add(name);
namesList.add(name);
}}
Suppose name value is at this time : admin
Now user goees to the UI and change admin to adminNew
then click update button
Here what i do on update Button
public void Update(){
for(int i =0;i<namesList.size(); i++){
String updatedNanme = namesList.get(i).getText());
}
}
Now how will I get the updated name which user have changed from UI(i.e adminNew), in updatedName field.
Right now i am getting the old name(i.e admin) which i got from fetchData Method.
thanks
You should get textbox's value by calling getText(), not the "old value". I think there's a problem with your textbox list. maybe instantiate the textbox two times!
I suggest you debug your code, put a breakpoint on when textbox is instantiated and when the update occures. See if both are the same instance (for example if you're using eclipse watching a variable, id of the variable is shown in front of it. this is the object's id for VM. check if id of textbox that was instantiated is the same as id of textbox you are getting value from)
Could it be possible that you override the content of text box with the user entry ? Your update method will always set updatedNanme to the content of the last element from your namesList array.
And how do you access the updatedNanme string ? This string is only available in the for loop ?
TLDR:
I'm setting myListView.setVisibility(View.GONE);, but it's not dissappearing until later... do I need to let it know somehow that I've changed it's visibility? Or do I need to also hide it's inner elements or something?
Description of Problem:
I have a normal news app. You see a list of articles for the "main" section, then you can click the options to select a new section.
When the user clicked, the section title changed, but the articles in the list would just sit there with "old" content until the new content is loaded, then it would flash to the new content.
This isn't ideal obviously. I'd like the list to disappear, show a loading animation, then, after the new data is retrieved (either from DB or online, then DB), it shows the new content.
I found this SO question which seemed like what I want, but...
I'm setting GONE immediately upon selection of the menu, then VISIBLE after it import the articles and loads the new ones... but it's not disappearing at all during that. I know the GONE code works, because if I remove my VISIBLE code, the articles never reappear.
Do I need to say "View.GONE", then tell it to update it's visibility or something?
My Code (MainActivity):
public static void sectionSelected()
{
String selectedText = sectionsSpinner.getSelectedItem().toString();
String[] selectedSection = Section.stringToSection(selectedText);
//check if it was already the current section
if(!Section.isEqual(Section.currentSection, selectedText))
{
//hides list of articles
articleEntryListView.setVisibility(View.GONE);
//sets new currentSection
Section.currentSection = selectedSection; // Section.stringToSection(sectionsSpinner.getSelectedItem().toString());
//imports articles (if it's been more than an hour since last import)
articlesDataSource.importArticles(Section.currentSection, true, false);
//loads article from database to the list
loadArticlesIntoList(Section.currentSection);
}
}
public static void loadArticlesIntoList(String[] section)
{
//clears the list
//articleEntryAdapter.clear(); //don't think I need this now that I'm just going to hide it
//articleEntryAdapter.notifyDataSetChanged();
//POPULATES THE LIST OF ARTICLES, THROUGH THE ADAPTER
for(final Article a1 : articlesDataSource.getArticles(section))
{
articleEntryAdapter.add(a1);
}
articleEntryAdapter.notifyDataSetChanged();
//shows list of articles
articleEntryListView.setVisibility(View.VISIBLE);
}
ADDITION: here is my importAricles() code: http://pastebin.com/8j6JZBej
You have to invalidate the view anytime you make a change to its appearance, so make a call to articleEntryListView.invalidate() after setting the visibility.
i am working on an app to develop my knowledge so far i have created a calendar app which user can make appointment when clicking on a date. i then have a delete button which opens all the appointments created in a fresh activity, there i have: a list view which displays all appointments a textview which displays the selected appointment (selected by the user to delete) and a button remove. the remove button removes all the items from the sqlite but i can only see this working when the application is restarted i know i am missing something else in my code.. how do i clear the listview at the same time any help would be much appreciated
my code:
delete all method
public void deleteAll() {
db.delete(TABLE_NAME, null, null);
}
button code:
public void onClick(View v) {
switch(v.getId()){
case R.id.removeBtn:
dm.deleteAll();
break;
}
thank you
}
Maybe not the most elegant, but I don't build my UI in onCreate(). Instead, in onCreate(), I call another method initializeUI(), and that is where I build my user interface. Then, anytime I do something that should be reflected in the interface (update the database or whatever), I just need to call my method initializeUI() again.
Edit: Also look into notifyDataSetChanged() for your adapter as exampled here
First check if your database is writable (getWritableDatabase)
Then check that your "TABLE_NAME" is in fact the table name.
Then you could try to use execSQL("delete from " + TABLE_NAME);
if that does not work, you could try to close the db.
finally try putting it in a transaction
beginTransaction();
.. delete..
endTransaction();
If you are actually changing the data from the Adapter used in the ListView, you could use requery() method on the cursor used to populate the Adapter. This should reflect your changes!