So I have a Trip class and Place class that both extend ParseObject and have a many to many relationship between them. So I am using a ParseRelation like so:
Trip trip = ...
Place place = ...
trip.getRelation('place_relation').add(place);
trip.saveEventually();
Then, later on I fetch the places like so:
final ArrayList<Place> places;
ParseRelation<Place> placeParseRelation = trip.getRelation("place_relation");
ParseQuery<Place> placeParseQuery = placeParseRelation.getQuery();
placeParseQuery.findInBackground(new FindCallback<Place>() {
#Override
public void done(List<Place> objects, ParseException e) {
if (e != null) {
...
} else {
places = (ArrayList<Place>) objects;
}
}
});
I realize that because I'm using saveEventually() there might be a lag between when it is written to the db and fetching from the DB, but realistically it should be <1 sec for this to save properly. However I've found that it can take up to 5 minutes before the Places are returned in the query. It's quite variable how long it takes before the results show up, sometimes it is almost instant and, like I mentioned, sometimes it can be several minutes. I am on a fast internet connection using a new GenyMotion emulator.
Any ideas why this might be happening?
Related
I'm trying to get notifications from a bluetooth device sending records, and periodically update the UI to display the records. The while loop below sits in its own thread to handle UI updates while the rest of the module takes care of other tasks. gattCallback is an instance of a BluetoothGattCallback class that adds to a list of received records and returns that list when getHistory() is called.
My problem is that when I hit the foreach line, after so many iterations I get an error:
System.InvalidOperationException: Collection was modified; enumeration operation may not execute.
As far as I can tell, history isn't being updated here or anywhere else in my code so I'm confused by the error. I specifically retrieve a copy of the record history through getHistory() to avoid modifying it during the foreach. Can anyone suggest what might be causing it or any tips to find out?
It might be relevant that this has only caused issues since switching to a Moto E4 on Android 7.1.1 from a Moto G Play on Android 6.0.1.
// Periodically check to see what needs updating
while (!finishedDisplayThread)
{
// See if there are any new records to display
int count;
List<Record> history = gattCallback.getHistory();
if (history == null)
{
count = 0;
}
else
{
count = history.Count;
}
// Only update the display if it has changed
if(count != prevCount)
{
prevCount = count;
List<string> recordList = new List<string>();
if (history == null)
{
recordList = new List<string>();
recordList.Add("No history.");
}
else
{
foreach (Record record in history)
{
recordList.Add(record.ToRow());
}
}
//Update the display
RunOnUiThread(() =>
{
ListAdapter = new ArrayAdapter<string>(this,
Resource.Layout.ListItemLayout,
recordList);
recordCountText.Text = "" + count;
});
}
Thread.Sleep(100);
}
I specifically retrieve a copy of the record history through getHistory() to avoid modifying it during the foreach.
Are you certain that you're getting a copy? Imagine this implementation:
public List<Record> getHistory() {
return history;
}
This will not return a copy of history, but a reference directly to history itself. If two different places call this method, any changes to one of the returned values will affect the other returned value.
If you want a copy, you have to do something like this:
public List<Record> getHistory() {
return new ArrayList<>(history);
}
I'm working in an app using Parse.com and I've been experiencing some random behavior, I made a simpler version of my code to show you and while it keeps being random (the results I expect happen about 4 in 5 times) it got better (in my code it's correct about 2/5 of the runs).
So the method is this, a very simple creation and filling of a new object:
public void test(){
final List<ParseObject> list = new ArrayList<>();
for(j=0;j<4;j++){
list.add(new ParseObject("Object"));
list.get(j).put("Column1", "sup");
list.get(j).put("Column2", "bro");
if(j==3){
ParseObject.saveAllInBackground(list, new SaveCallback() {
#Override
public void done(ParseException e) {
Toast.makeText(MainActivity.this, "NANANANANANANANA BATMAN!",Toast.LENGTH_LONG).show();
}
});
}
}
}
}
Problem is it creates 4 ParseObjects (as it should) only 4/5 of the tries, then 1/4 it's only 3. Why does this happen?
Why don't you create and store your ParseObject in a variable and then, use put("Column1", "sup"); and put("Column2", "bro"); on it before adding this variable directly to your list? because you are accessing your list two times for nothing where it can be avoided.
It would be cleaner and it would allow you to debug better.
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 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.
I have recently managed to switch to Local Datastore, moving all the needed parts of the database to the client. Furthermore I send a push notification whenever data changes so that the client data stays up to date.
Now my problem is that one of the pointers in my data keeps returning the old pointer after updating.
Here is the code that I use:
public ParseQuery<CircuitUnit> circuitUnits() {
ParseQuery<CircuitUnit> query = CircuitUnit.getQuery();
query.include(CircuitUnit.circuits);
query.include(CircuitUnit.guard);
query.setLimit(1000);
return query;
}
circuitUnits().findInBackground(
new FindCallback<CircuitUnit>() {
#Override
public void done(List<CircuitUnit> objects, ParseException e) {
Log.d(TAG, "Pinning circuitUnits " + objects.size());
// debugging loop of results
for (CircuitUnit circuitUnit : objects) {
if (circuitUnit.getObjectId().equals("TXEZDch6wK")) {
Guard guard = circuitUnit.getGuard();
Log.d(TAG, "Guard: " + guard.getObjectId());
}
}
// This function updates the Local datastore with the newly fetched objects
// updateServerDataPin(objects, PinsGlobal.CIRCUIT_UNITS,
e, callback);
}
});
The Logged output is: "Guard: L440gHXKTY" where it should be SDDg23rR4h
I have added a screenshot of the CircuitUnit table showing that SDDg23rR4h is indeed the expected objectId of the pointer.
I tried to create a sample project showing the issue as part of the bug report for parse.com, but that returned the correct pointer.
My theory is then that this problem lies in having data in the Local Datastore which somehow interferes with the result. Not that I understand why, cause I am clearly querying the network and not locally.
It seems as if the include statements are ignored and simply filled with the known data from the Local Datastore.
Has anyone experienced something similar or have a possible explanation to this behaviour?