i'm having an issue that soon enough going to blow me.
i have Database table lets call it A. table A has field that determines if this row is processed or no. i update the field myself from within the Parse Browser to either True | False, and trying to call query.findInBackground() to check with the Boolean value however the returned List always returns False if its True and vice versa. enough talking let me show you what i'm doing.
public static void getMyRequests(ParseUser user, final FindCallback<ServicesModel> callback) {
ParseQuery<ServicesModel> query = new ParseQuery<>(ServicesModel.class);
if (!user.getBoolean(ParseHelper.CAN_UPLOAD)) {
query.whereEqualTo("user", user);
}
query.findInBackground(new FindCallback<ServicesModel>() {
#Override public void done(final List<ServicesModel> objects, ParseException e) {
if (e == null) {
if (objects != null && !objects.isEmpty()) {
for (ServicesModel object : objects) {
object.setHandlerUser(object.getParseUser("handlerUser"));
object.setProcessedTime(object.getLong("processedTime"));
object.setCategoryType(object.getString("categoryType"));
object.setUser(object.getParseUser("user"));
object.setUserRequest(object.getString("userRequest"));
object.setImageUrl(object.getString("imageUrl"));
object.setProcessed(object.getBoolean("isProcessed"));
Logger.e(object.getBoolean("isProcessed") + "");
}
callback.done(objects, null);
} else {
callback.done(null, new ParseException(1001, "No Services"));
}
} else {
callback.done(null, e);
}
}
});
}
the code above suppose to refresh my data but however my log always shows that isProcessed is False even tho it's set to True inside the Parse Browser
what i have tried besides this? fetchAllInBackground & fetch() you name it. the object will always return false until i re-run the application from Android Studio what i'm doing here wrong? btw here is how i initialize Parse
Parse.setLogLevel(BuildConfig.DEBUG ? DEBUG_LEVEL : Parse.LOG_LEVEL_NONE);
ParseObject.registerSubclass(ProductsModel.class);
ParseObject.registerSubclass(ProductRentalModel.class);
ParseObject.registerSubclass(ServicesModel.class);
Parse.enableLocalDatastore(context);
Parse.initialize(context, context.getString(R.string.app_id), context.getString(R.string.client_id));
the answer was to remove
Parse.enableLocalDatastore(context);
which is bad anyway, without the datastore enabled the data are refreshed probably, however with enabling the local database, the data will not refresh unless if i killed the app and/or re-install it. that's bad. but did the trick.
Related
I'm working on an existing Android App with parse back-end (localDatastore is enabled but not used in this context) which has the following object structure:
Object A has an array of objects B
Object B has an array of objects C
I save this object structure using saveInBackground in calling the next saveInBackground in the done SaveCallback in reverse Order(C,B,A). For the inner two that works fine, but the top level object isn't saved.
Here's the code (frame, newStep and order are objects of classes inheriting from the ParseObject class)
frame.saveInBackground(new SaveCallback() {
#Override
public void done(ParseException e) {
if (e == null) {
Log.i("Info", "frame.save callback OK");
frames.add(frame);
newStep.setTimeFrames(frames);
newStep.saveInBackground(new SaveCallback() {
#Override
public void done(ParseException e) {
if (e == null) {
Log.i("Info", "newStep.save callback OK");
List<ProcessingStep> steps = order.getProcessingSteps();
steps.add(newStep);
order.setProcessingSteps(steps);
order.saveInBackground(new SaveCallback() {
#Override
public void done(ParseException e) {
if (e == null){
Log.i("Info", "order.save callback OK");
}else{
Log.i("Info", "order.save callback FAIL");
}
}});
} else {
Log.i("Info", "newStep.save callback FAIL");
e.printStackTrace();
}
}
});
} else {
Log.i("Info", "frame.save callback FAIL");
e.printStackTrace();
}
}
});
In the console log I see only "frame.save callback OK", the "newStep.saveInBackground()" seems to be executed too (object appears in backend) however I never get the log message in the callback.
If I save all objects before synchronously without references to each other first and then call the code here, it seems to work (worked at least once) but took for ever (minutes). Queries from the back-end are super fast and the frame object is also saved almost instantly but the done-callbacks seem to bugging. When it fails I do not get any exception, log anything it just seems to fail silently.
I'm looking for any insight why Parse behaves like that as well as how to fix it.
edit: The problem seems to be with the double relation (A to B and B to C). If I try with only A to B or B to C it works just fine. What remains mysterious to me, however, is why splitting the operation up with callbacks doesn't seem to work.
The problem was the enabled localdatastore. Without localdatastore enabled everything works as it should.
I have an android app with Azure Mobile Services and implemented Offline Sync. The app works well but when syncing data it seems not to complete so there is always a few rows on tables which have not synced?
Anyone have any ideas what the problem might be. I believe that on the next try it would finish where it left off or am I wrong?
Thanks in advance
The app works well but when syncing data it seems not to complete so there is always a few rows on tables which have not synced?
I would recommend you use fiddler to capture the network traces when handling the sync operations.
For Incremental Sync, the request would be as follows:
Get https://{your-app-name}.azurewebsites.net/tables/TodoItem?$filter=(updatedAt%20ge%20datetimeoffset'2017-11-03T06%3A56%3A44.4590000%2B00%3A00')&$orderby=updatedAt&$skip=0&$top=50&__includeDeleted=true
For opting out of incremental sync, you would retrieve all records without the filter updatedAt.
Get https://{your-app-name}.azurewebsites.net/tables/TodoItem?$skip=0&$top=50&__includeDeleted=true
Note: If there are too many items, the SDK would send multiple requests to pull all items that match your given query from the associated remote table. Also, you need to make sure you specify the includeDeleted() in your query.
In summary, you need to make sure that all items could be retrieved via the above requests. Additionally, if the pull operation has pending local updates, then the pull operation would first execute a push operation. So, I assume that you could catch the exception when calling pull operation for handling the conflict resolution.
Bruce's answer is fine but I used a slightly different method without the need to use fiddler.
I change my connection from this
mClient = new MobileServiceClient("[AZUREWEBSITE]", cntxall);
mClient.setAndroidHttpClientFactory(new MyOkHttpClientFactory());
To this
mClient = new MobileServiceClient("[AZUREWEBSITE]", cntxall).withFilter(
new ServiceFilter() {
#Override
public ListenableFuture<ServiceFilterResponse> handleRequest(ServiceFilterRequest request, NextServiceFilterCallback nextServiceFilter) {
// Get the request contents
String url = request.getUrl();
String content = request.getContent();
if (url != null) {
Log.d("Request URL:", url);
}
if (content != null) {
Log.d("Request Content:", content);
}
// Execute the next service filter in the chain
ListenableFuture<ServiceFilterResponse> responseFuture = nextServiceFilter.onNext(request);
Futures.addCallback(responseFuture, new FutureCallback<ServiceFilterResponse>() {
#Override
public void onFailure(Throwable e) {
Log.d("Exception:", e.getMessage());
}
#Override
public void onSuccess(ServiceFilterResponse response) {
if (response != null && response.getContent() != null) {
Log.d("Response Content:", response.getContent());
}
}
});
return responseFuture;
}
}
);
This is the logging method for Azure connections and shows the request in the log.
i am making an android app in which i am getting the data from the server side by making doinbackground method and assigning these values to the variables which are declared globally. Problem is that i am using that variables in oncreate method where it give me null values because the doinbackground method finishes after the variables are used in oncreate. what could be the solution for this?
public void getProfileInfo() {
String currentUserId = ParseUser.getCurrentUser().getObjectId();
ParseQuery<ParseObject> query = ParseQuery
.getQuery(ParseConstants.KEY_USER_INFO);
query.whereEqualTo(ParseConstants.KEY_USER_ID_INFO, currentUserId);
query.findInBackground(new FindCallback<ParseObject>() {
public void done(List<ParseObject> objects, ParseException e) {
if (e == null) {
for (ParseObject thisUser : objects) {
name = thisUser
.getString(ParseConstants.TYPE_INFO_FULLNAME);
email = ParseUser.getCurrentUser().getEmail();
}
} else {
Log.d("Activity", "Error: " + e.getMessage());
}
}
});
}
i am calling this method in oncreate before i use the variables name and email.i checked the value of name and email. it gave me the right values.
It sounds like you have a bit of timing problem.
Just to state the obvious, you can't start an asynchronous task on a background thread, and then blindly use the results without knowing that the task has completed.
The use of the results needs to be triggered by the completion of the task.
So, whatever you're doing to access these 'global variables' that is getting nulls - don't do it at a deterministic time (e.g. in onCreate) - do it when you actually get the results back.
If there's a chance that the results may come back before the point where you're currently trying to access them, check to see if they have come back, and if they have, use them. If they haven't, wait until they do come back.
I'll leave the implementation of this as an "exercise for the reader"
I'm using Parse.com in my Android app. I'm making a collaborative shopping list which allows the user to mark items for deletion (they turn grey), but they only get actually deleted when I press the Sync button (and there's a network available). Currently, the objects are erased from parse database but not from the local datastore. I'm trying this:
ParseQuery<ShoppingItem> queryDeletes = ShoppingItem.getQuery();
queryDeletes.fromPin(MyApplication.ALL_ITEMS);
queryDeletes.whereEqualTo("isDeleted", true);
queryDeletes.findInBackground(new FindCallback<ShoppingItem>() {
#Override
public void done(final List<ShoppingItem> items, ParseException e) {
if (e == null) {
ShoppingItem.deleteAllInBackground(items, new DeleteCallback() {
#Override
public void done(ParseException e) {
if (e == null) {
ShoppingItem.unpinAllInBackground(items, new DeleteCallback() {
#Override
public void done(ParseException e) {
if (e == null) {
if (!isFinishing()) {
shoppingListAdapter.loadObjects(); // update the list view
}
}
}
});
}
}
});
}
}
});
}
Already tried clearing app data and overriding equals() in ShoppingItem with no success. Any ideas?
Thanks!
Ok, so I solved it. From what I understood, what I was trying to do is not possible using the parse library.
First of all, deleteAllInBackground() also unpins objects, so the unpinAllInBackground() is not needed.
The problem is that I was pinning the objects using item.pin(MyApplication.ALL_ITEMS), thus the only way to unpin them is by passing the pin name using item.unpinInBackground(MyApplication.ALL_ITEMS). However, the batch version does not allow to pass as argument both a collection of items AND the pin name. Thus, it isn't possible to batch unpin items with a named pin.
I ended up unpinning the objects individually passing the pin name. The big complain I have is that doing item.unpinInBackground() without the pin name does not throw an exception and thus I was not aware what the problem was.
I'm using parse to store my data and do a lot of queries while using my program.
The issue is that after about +/-20 similar queries, parse findInBackground() or getFirstInBackground() doesn't return a callback and app stuck at that possition.
My query code:
ParseQuery<OptionCodeDTO> mQuery;
mQuery = ParseQuery.getQuery(OptionCodeDTO.class);
mQuery.whereEqualTo("code", prCode);
mQuery.getFirstInBackground(new GetCallback<OptionCodeDTO>() {
#Override
public void done(OptionCodeDTO optionCodeDTO, ParseException e) {
if (isVisible()) {
if (e == null) {
OptionCode opCode = new OptionCode(optionCodeDTO);
mCodes.push(opCode);
printCodes();
prDescrLayout.setVisibility(View.VISIBLE);
prDescProgress.setVisibility(View.GONE);
mPRLable.setVisibility(View.GONE);
} else {
if (e.getCode() == ParseException.CONNECTION_FAILED) {
mPrDescr.setText(R.string.dtc_lookup_check_network);
} else if (e.getCode() == ParseException.OBJECT_NOT_FOUND) {
mPrDescr.setText(R.string.pr_lookup_code_not_found);
} else {
mPrDescr.setText(R.string.dtc_lookup_other_problems);
}
prDescrLayout.setVisibility(View.VISIBLE);
prDescProgress.setVisibility(View.GONE);
}
}
}
});
First of all, if your app ANRs (application not responding) because of something from UI thread that relies on background threads, that is incorrect architecture.
Probably you have to optimize your app's interaction with Parse. Generally it is a bad practice to make lots of saveInBackground, for example from inside a loop. You can add objects, those need to be saved, to a list and then use ParseObject.saveAllInBackground(objectList)
Also an idea to optimize is to use local storage - android's built in SQLite. For example if your app relies on something being saved to Parse, the logic is like this:
When saving object first you save to local DB and run a saveInBackground method.
When fetching objects you first fetch from your local DB and then run a getInBackground method, which inside a callback persists the information to your local DB.
This way you will make your app usable without internet connection.