I am currently writing a program in which I need to upload multiple parseObjects like this:
List<ParseObject> listObjects;
ParseObject.saveAllInBackground(listObjects, new SaveCallback() {
#Override
public void done(ParseException e) {
}
}
But when the list increases, I need a way of notifying user the save progress is underway...
ParseFile has a built in
ParseFile.saveInBackground(SaveCallback saveCallback, ProgressCallback progressCallback)
My question is, how do I implement progresscallback using parseobject. If it's not possible, do I have to convert my parseobject to a parsefile?
Related
I don't understand how is the Parse working?
I download data in parse to my arraylist , but when I show the Pets.size inside (//here) method "done" it will show 4, but when I show pets.size outside the done's method it will show 0?
public class Test extends AppCompatActivity {
ArrayList<Pet> pets;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
pets = new ArrayList<>();
ParseQuery<Pet> query = new ParseQuery<>("Pets");
query.findInBackground(new FindCallback<Pet>() {
#Override
public void done(List<Pet> list, ParseException e) {
if (e!=null){
Toast.makeText(Test.this,"Error",Toast.LENGTH_LONG).show();
}
for (Pet pet : list){
Pet newPet = new Pet();
newPet.setName(pet.getName());
newPet.setType(pet.getType());
pets.add(newPet);
}
// here
}
});
Toast.makeText(Test.this,"You have "+pets.size()+" pets",Toast.LENGTH_LONG).show();
}
Here's my Pet class:
#ParseClassName("Pets")
public class Pet extends ParseObject {
public String getName(){
return getString("name");
}
public void setName(String name) {
put("name", name);
}
public String getType(){
return getString("type");
}
public void setType(String type) {
put("type", type);
}
}
And an orther question , what should I do if I wanna save the data in local data?
Explanation:
findInbackground performs an operation to find all ParseObjects in a background thread (outside the main thread, or UI thread). So when it completes in the place where you have the comment
//here
That is when the background thread finishes it's call to find the objects. When you try to look at the size of the array outside that call where it shows size of 0, it is because it reached that point before the background thread finishes it's work (of adding to your array from objects it found).
What is happening is the operation for find() is happening in parallel with your main threads code.
And for your second question, make sure you enableLocalDatastore and then you can pin results from queries to your local cache. This data is stored on the device until the user deletes your app or clears cached data in settings.
Follow this guide to setup local cache Local Datastore with Parse
Note: A solution to your problem for when the background task of finding the pets is complete is to call a method from within the Callback for the findInBackground call that will handle the newly found Pet ParseObjects. Also remember to handle if the query fails either by finding no objects or some failure in connection / timeout.
just calling pet.pin() or pet.pinInBackground(); you can save a parseObject in local storage , to query objects in local storage you need set query.fromPin(true)
https://parse.com/docs/android/guide#objects-the-local-datastore
"done" method fires when the background task ends.
I want to retrieve data from parse.com and show it in listview. but when i retrieve it and it shows me in hashcode. I have pasted picture of output.Please look into my query code and correct me.
Here is code for pulling data from parse.com
ParseQuery<ParseUser> query = ParseUser.getQuery();
query.findInBackground(new FindCallback<ParseUser>() {
#Override
public void done(List<ParseUser> list, ParseException e) {
if (e != null) {
Toast.makeText(getActivity(), "Error" + e, Toast.LENGTH_SHORT).show();
} else {
for (ParseUser user : list) {
ParseUser newUser = new ParseUser();
newUser.getString(user.getString("username"));
newUser.getString(user.getString("Latitude"));
newUser.getString(user.getString("Longitude"));
newUser.getString(user.getString("Bloodtype"));
newUser.getString(user.getString("Mobile"));
user1.add(newUser);
}
ArrayAdapter<ParseUser> adapter = new ArrayAdapter<>(getActivity(),android.R.layout.simple_list_item_1,user1);
setListAdapter(adapter);
}
}
});
ArrayAdapter just use the toString of each object in the array.
Every user that you add to list is displayed as a pointer, this is the to string method of the ParseUser object.
If you are trying to display all information about the user you should create a custom adapter and implement the getView method.
If you want to check for now if it works correctly you can pass a list of just username for example and check if it works, then you can move on and implement your own adapter.
Edit:
For creating custom adapter check this question
Can I keep some object fields on local storage and not sync them with cloud?
Imagine we have a "Quote" object on network and we want to keep quotes synced between app and cloud. And we have favorite part in our app to keep user favorite quotes separately.
Also we don't want to keep favorites synced with cloud. Can we have property/field like "starred" on local data-store and keep this property/field just in local storage and prevent that from sync with cloud?
I have encountered the same problem now while using parse.
In my case I have restaurant catalog app which allows user to bookmark some of the restaurants in order to view them offline. So I want to store a "bookmarked" flag with each restaurant stored locally. Such flag belongs to an individual user and i don't want to sync this flag with parse class. I already have Relation to restaurants in the User class for syncing purposes.
I discovered that if I simply put some data to ParseObject with a key which is not stored in the cloud(ie isn't column of the class) and pin this object locally, such data will be saved localy and will note synced until i intentionally sync restaurant with the cloud. But you can only retrieve such local data with ParseObject when you do query 'fromLocalDatastore()'. Here is my code:
Here I bookmark a restaurant
ParseUser user = ParseUser.getCurrentUser();
restaurant.setBookmarked(doBookmark);
if (doBookmark) {
UserHelper.bookmarksRelation(user).add(restaurant);
restaurant.pinInBackground(ParseRestaurant.BOOKMARKED_PIN);
} else {
UserHelper.bookmarksRelation(user).remove(restaurant);
restaurant.unpinInBackground(ParseRestaurant.BOOKMARKED_PIN);
}
user.saveEventually();
ParseRestaurant :
public class ParseRestaurant extends ParseObject {
...
public static final String LOCAL_KEY_BOOKMARKED = "bookmarked";
...
public Boolean isBookmarked() {
return (containsKey(LOCAL_KEY_BOOKMARKED)) ? getBoolean(LOCAL_KEY_BOOKMARKED) : false;
}
public ParseRestaurant setBookmarked(Boolean bookmarked) {
put(LOCAL_KEY_BOOKMARKED, bookmarked);
return this;
}
...
}
In the result when i query details of the restaurant, its data come with or without "bookmarked" flag, just as i needed:
#Override public Observable<ParseRestaurant> getRestaurant(#NonNull final String restaurantId) {
return Observable.create(new RxUtils.OnSubscribeParse<ParseRestaurant>() {
#Override public ParseRestaurant just() throws ParseException {
ParseRestaurant restaurant = ParseRestaurant.createWithoutData(restaurantId);
try {
restaurant.fetchFromLocalDatastore();
Timber.d("Restaurant is cached locally :)");
return restaurant;
} catch (ParseException unnecessary) {
Timber.d("Restaurant is not cached locally :(");
}
restaurant.fetchIfNeeded();
restaurant.pinInBackground(ParseRestaurant.TEMPORARY_DETAILED_PIN);
return restaurant;
}
}).subscribeOn(Schedulers.io());
}
I am writing an address book APP and using the Parse service.
I also use the listview and BaseAdapter to implement the APP
There are many people I saved as the ParseObject.
And each ParseObject includes a photo saved as file.
I get all ParseObjects by :
ArrayList<ParseObject> list = new ArrayList<ParseObject>();
ParseQuery<ParseObject> query = new ParseQuery<ParseObject>("member");
query.findInBackground(new FindCallback<ParseObject>() {
#Override
public void done(List<ParseObject> objects, ParseException e) {
if (e == null) {
list = (ArrayList<ParseObject>) objects;
mMyadapter = new MyAdapter(context, list);
}
else {
}
});
in the adapter, I want to show the image from the ParseFile
My question is :
How do I get the ParseFile from the list?
I tried below code but the APP will shut down suddenly.
I wrote the getView method in the MyAdapter like below:
ParseFile pf = (ParseFile) list.get(position).get("photo1");
pf.getDataInBackground(new GetDataCallback() {
#Override
public void done(byte[] bytes, ParseException e) {
if (e == null) {
Bitmap bm = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
viewTag.imageView1.setImageBitmap(bm);
}
else {
Log.d("debug", "bad");
}
}
});
I can not use the getUrl() neither....
Can someone tell me how to modify it? Many thanks for your help!
You don't need to initialize list.
How are you setting the adapter of your ViewGroup? At the moment, you're creating a new adapter only when your ParseQuery is done. Your adapter may not be set properly.
Since list could point to new ArrayList<ParseObject>() or (ArrayList<ParseObject>) objects depending on whether ParseQuery is done, it's possible that you're calling list.get() on an invalid position.
In short, make your member variables local. Also, if MyAdapter is an anonymous class, pull that code out into a static inner class so it doesn't refer to its containing class' member variables. Use getItem() to access your ParseObjects, not list.get().
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();
}
}
});