I'm using Parse.com as my backend and while there seems to be a method, saveInBackgroundWithBlock, to prevent duplicate entries. It doesn't appear to exist on Android. I'd like to upload only unique entries but can't figure out a way to do so.
The only thing I can think of is to query then insert if the entry doesn't exist, but that's doing twice as many network calls and I feel like it needs to.
Thanks
As I had mentioned in the comment earlier, I had faced the same problem. Ended up writing a query to find the existing objects and then save only the non-existing ones. Like below.
//Say you have a list of ParseObjects..this list contains the existing as well as the new objects.
List<ParseObject> allObjects = new ArrayList<ParseObject>();
allObjects.add(object); //this contains the entire list of objects.
You want to find out the existing ones by using the field say ids.
//First, form a query
ParseQuery<ParseObject> query = ParseQuery.getQuery("Class");
query.whereContainedIn("ids", allIds); //allIds is the list of ids
List<ParseObject> Objects = query.find(); //get the list of the parseobjects..findInBackground(Callback) whichever is suitable
for (int i = 0; i < Objects.size(); i++)
existingIds.add(Objects.get(i).getString("ids"));
List<String> idsNotPresent = new ArrayList<String>(allIds);
idsNotPresent.removeAll(existingIds);
//Use a list of Array objects to store the non-existing objects
List<ParseObject> newObjects = new ArrayList<ParseObject>();
for (int i = 0; i < selectedFriends.size(); i++) {
if (idsNotPresent.contains(allObjects.get(i).getString(
"ids"))) {
newObjects.add(allObjects.get(i)); //new Objects will contain the list of only the ParseObjects which are new and are not existing.
}
}
//Then use saveAllInBackground to store this objects
ParseObject.saveAllInBackground(newObjects, new SaveCallback() {
#Override
public void done(ParseException e) {
// TODO Auto-generated method stub
//do something
}
});
I had also tried using beforeSave method on ParseCloud. As you may know, before saving the objects this method is called on the ParseCloud and is ideal to make any validation required. But, it didn't quite run well. Let me know if you need something from the ParseCloud code.
Hope this helps!
I'm not sure I understand your question, but you can get the same functionality as saveInBackgroundWithBlock in Android like this:
myObject.saveInBackground(new SaveCallback() {
public void done(ParseException e) {
if (e == null) {
myObjectSavedSuccessfully();
} else {
myObjectSaveDidNotSucceed();
}
}
});
Related
final FirebaseRecyclerAdapter adapter = new FirebaseRecyclerAdapter(Service.class, R.layout.browse_service_detail, ServiceHolder.class, mReference){
#Override
protected void populateViewHolder(ServiceHolder serviceHolder, Service service, int position) {
serviceHolder.setServiceName(service.getName());
serviceHolder.setInfo("От " + service.getPrice1());
service.setQuantitySelected(service.getQuantityEnabled());
if (Order.getInstance().getServices() != null) {
for (Service serviceFromSingleton : Order.getInstance().getServices()) {
if (serviceFromSingleton.getName() == serviceHolder.getServiceName().getText().toString()) {
serviceHolder.getServiceName().setSelected(true);
serviceHolder.getServiceName().setTextColor(getResources().getColor(R.color.yellow));
}
}
}
//add item to array
servicesList.add(service);
}
}
};
When I run this activity, it records the visible list objects to an array, but when I scroll down and go back up, it duplicates the first elements again into the array. How to fix it? For an item to be added only once.
I don't think there is any issue in RecyclerAdapter..I think the list only inserting same data multiple times.
why not you check whether the list is empty or not before adding data into it and clear the data if its not empty and then add new.
if(servicesList.isEmpty())
servicesList.add(service);
//else clear and add data
else{
servicesList.clear();
servicesList.add(service);
}
To handle data duplicacy, you can use a Set which will ignore duplicate inserts on scrolling.
servicesList.add(service);
Set<Service> mSet= new HashSet<Service>();
mSet.addAll(servicesList);
servicesList.clear();
servicesList.addAll(mSet);
OR use Set other than ArrayList
little clumsy but will work for you.
Hi I am trying to update the location of the current device into the parse database using the objectId of this device.
ParseQuery innerQuery = new ParseQuery("_Installation");
innerQuery.whereEqualTo("objectId", ParseInstallation.getCurrentInstallation());//current phone
ParseQuery<PhoneFinder> query = ParseQuery.getQuery(PhoneFinder.class);
query.whereMatchesQuery("identification", innerQuery);
query.findInBackground(new FindCallback<PhoneFinder>() {
#Override
public void done(List<PhoneFinder> list, ParseException e) {
for (PhoneFinder loc : list)
{
loc.setLocation(geoPoint);
loc.saveInBackground();
}
}
});
If I use the objectId explicitly is works fine.
Any suggestions?
You haven't said what's wrong with the code you posted (that is, exactly what it does wrong) but I'm going to guess innerQuery doesn't return any rows. If that is the case, this information from the API docs may help:
Note: We only allow the following types of queries for installations:
query.get(objectId)
query.whereEqualTo("installationId", value)
query.whereMatchesKeyInQuery("installationId", keyInQuery, query)
whereEqualTo("objectId",value) isn't on that list, so that is probably why it's not working. Also, ParseInstallation.getQuery is the best way to get a query to use for installations.
i made a listview with all the posts in the list.
what i want is when i click the child in the list i want another activity to be opened showing that specific post and the related comments
the question is how to know which item is clicked and how to show that particular post ParseObject in next activity
as they do in messaging app in which you click the message from the listview and subsequent messages are shown in the next activity
i might be very thankful to you if you solve this for me!!
Please Try this code:
Please implement your object class with Serializable
listView.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapter, View v, int position,
long arg3) {
try
{
Log.v("position",position); // hear is your list item position
MyClass obj = new MyClass(); // Class must be implements with Serializable
Intent showintent = new Intent(context,<activity class to open>);
showcontactintent.putExtra("obj",obj);
startActivity(showintent);
}
catch(Exception e)
{
e.printStackTrace();
}
}
});
Use: Relational Data
Objects can have relationships with other objects. To model this behavior, any ParseObject can be used as a value in other ParseObjects. Internally, the Parse framework will store the referred-to object in just one place, to maintain consistency.
For example, each Comment in a blogging app might correspond to one Post. To create a new Post with a single Comment, you could write:
// Create the post
ParseObject myPost = new ParseObject("Post");
myPost.put("title", "I'm Hungry");
myPost.put("content", "Where should we go for lunch?");
// Create the comment
ParseObject myComment = new ParseObject("Comment");
myComment.put("content", "Let's do Sushirrito.");
// Add a relation between the Post and Comment
myComment.put("parent", myPost);
// This will save both myPost and myComment
myComment.saveInBackground();
You can also link objects using just their objectIds like so:
// Add a relation between the Post with objectId "1zEcyElZ80" and the comment
myComment.put("parent", ParseObject.createWithoutData("Post", "1zEcyElZ80"));
By default, when fetching an object, related ParseObjects are not fetched. These objects' values cannot be retrieved until they have been fetched like so:
fetchedComment.getParseObject("post")
.fetchIfNeededInBackground(new GetCallback<ParseObject>() {
public void done(ParseObject post, ParseException e) {
String title = post.getString("title");
// Do something with your new title variable
}
});
You can also model a many-to-many relation using the ParseRelation object. This works similar to List, except that you don't need to download all the ParseObjects in a relation at once. This allows ParseRelation to scale to many more objects than the List approach. For example, a User may have many Posts that they might like. In this case, you can store the set of Posts that a User likes using getRelation. In order to add a post to the list, the code would look something like:
ParseUser user = ParseUser.getCurrentUser();
ParseRelation<ParseObject> relation = user.getRelation("likes");
relation.add(post);
user.saveInBackground();
You can remove a post from the ParseRelation with something like:
relation.remove(post);
For more read: https://parse.com/docs/android/guide#objects-relational-data
^why did I copy all the words here instead of just providing the link? Because parse links are broken sometimes and doesn't direct you to the section you need (instead it just sends you to https://parse.com/docs/android/guide and because the doc is so large, you won't be able to find it.
Using latest Parse library v1.5.1
Thanks to the update now I can do:
ParseQueryAdapter<ParseObject> mAdapter = new ParseQueryAdapter<ParseObject>(MainActivity.this, new ParseQueryAdapter.QueryFactory<ParseObject>() {
#Override
public ParseQuery<ParseObject> create() {
ParseQuery<ParseObject> query = new ParseQuery<ParseObject>(ParseObject.class);
query.fromLocalDatastore();
return query;
}
});
mListView.setAdapter(mAdapter);
Now I have some pinned objects and they appear correctly, but when I unpin them like so:
//Some ParseObject in the above adapter
object.unpinInBackground(new DeleteCallback() {
#Override
public void done(ParseException e) {
if(e == null) {
//I beleive this would be the correct approach.
mAdapter.notifyDataSetChanged();
}
}
});
Naturally I want that item to disappear from the corresponding ListView, but it doesn't. But say I go back to a different activity and revisit this activity, the ListView is displayed properly without the recently unpinned object.
Is this a bug? If not what am I doing wrong?
I have the same problem) I solve it with invoke method ParseQueryAdapter.loadObjects().
You can try mAdapter.remove(object) before calling notifyDataSetChanged();
unpinInBackground removes the object from the database. Probably the adapter has a local copy of the object.
Looks like there is no remove method in ParseQueryAdapter.
Here is an response from official source:
Since a ParseQueryAdapter is designed to always show the results of a
ParseQuery, you would need to use an API request to reload the query.
https://www.parse.com/questions/delete-a-object-using-parsequeryadapter
Currently I'm using Parse.com in order to create multiple ParseUsers. This works perfectly and each user can login individually. However from here I want to expand my app to allow Users to create groups of users and therefore have data that is only relevant and shared between these Users. This will mean that when the User logs in, they can see a List of the groups they are members of and from there can share data simply just to those users of that individual group. What would be the best way to tackle this and does anybody have any examples or tutorials that I could follow in order to understand this concept?
I've considered creating a Group class and then making this store User's IDs in an array and then allow each User to store an array of the Group IDs that they're currently members of. I'm just not really sure how to broach this issue.
Thanks in advance!
I ended up doing as shown below:
ParseQuery<ParseRole> query = ParseRole.getQuery();
Intent intent = getActivity().getIntent();
String groupId = intent.getStringExtra("groupId");
query.whereEqualTo("objectId", groupId);
groupUsers = new ArrayList<String>();
query.findInBackground(new FindCallback<ParseRole>() {
#Override
public void done(List<ParseRole> objects, ParseException e) {
if(e == null) {
for(ParseRole role : objects) {
ParseRelation<ParseUser> usersRelation = role.getRelation("users");
ParseQuery<ParseUser> usersQuery = usersRelation.getQuery();
usersQuery.findInBackground(new FindCallback<ParseUser>() {
#Override
public void done(List<ParseUser> objects, ParseException e) {
for(ParseUser user : objects) {
groupUsers.add(user.getUsername());
}
}
});
}
} else {
Toast.makeText(getActivity(), "ERROR", Toast.LENGTH_SHORT).show();
}
}
});
I passed in the group ID from the Intent that sent me to that Fragment that I was checking and then populated my ListView with the list that I've returned from the query on the Parse database with the specific group ID. I hope this helps anyone else who had the same issue as me. Good luck!
Since you probably want to use it for security as well as making it easier for code/users, look at the Roles security feature.
You can add/remove Users from Roles, and assign ACL permissions to Roles instead of Users. This way when people are added-to/removed-from the Role the permissions don't require any changes.
Initially there was a limit to the number of Roles you were allowed to create based on account type, but this restriction was removed last year I believe.