0

In my application I try to synchronize books with the MBaaS Backendless. Therefor I generate a List to save all book titles inside after getting them from Backendless. I get the correct data from the Server (without duplicates) but my for-loop is starting too early, so there is no data to iterate through. How can I easy achieve to finish the filling of the List first before starting my for-loop? This is my code:

final List<String> all_books_without_duplicates = new ArrayList<String>();
// queryId = Id of the user
Backendless.Data.of(Books.class).find(queryId, newLoadingCallback<BackendlessCollection<Books>>(this, getString(R.string.loading_books), true) {
@Override
public void handleResponse(BackendlessCollection<Books> booksBackendlessCollection) {
    Iterator<Books> booksIterator = booksBackendlessCollection.getCurrentPage().iterator();
    while (booksIterator.hasNext()) {
    Books booksonline = booksIterator.next();
    final String book_title = booksonline.getBookTitle();
    // avoid duplictes
    if (!all_books_without_duplicates.contains(book_title)) {
    all_books_without_duplicates.add(book_title);
    Log.d("added book title:", book_title);
    }}}});
    Log.d("for-loop elements: ", String.valueOf(all_books_without_duplicates));
    for (int x=0; x<all_books_without_duplicates.size(); x++){
    final String book_title_value = all_books_without_duplicates.get(x);
    String whereClause = "booktitle LIKE '%" + book_title_value + "%'";
    QueryOptions queryOptions = new QueryOptions();
    queryOptions.setRelated(Arrays.asList("book"));
    BackendlessDataQuery query = new BackendlessDataQuery(queryOptions);
    query.setWhereClause(whereClause);
    // get all book-ids from Backendless where title is x
    Backendless.Data.of(BookIds.class).find(query, new LoadingCallback<BackendlessCollection<BookIds>>(MainActivity.this, getString(R.string.loading_books), true) {
    @Override
    public void handleResponse(BackendlessCollection<BookIds> bookIDsBackendlessCollection) {
    super.handleResponse(bookIDsBackendlessCollection);
    Iterator<BookIds> bookIDsSyncIterator = bookIDsBackendlessCollection.getCurrentPage().iterator();
    while (bookIDsSyncIterator.hasNext()){
    BookIds book_ids = bookIDsSyncIterator.next();
    String book_id_be = book_ids.getObjectId();
    // get all book-ids from SQLite-DB
    DatabaseHelper db=new DatabaseHelper(getApplicationContext());
    final List<String>bookIds_sql = db.getAllBookIds();
    // save new book in SQLite if it lacked so far
    if(bookIds_sql.contains(book_id_be)){
    // book already exists
    }
    else{
    saveNewBookFromBackendless(book_id_be);
    }
    }}});}
Timitrov
  • 211
  • 1
  • 3
  • 14

1 Answers1

0

What is happening is that your code is executing the find method, which asynchronously does the backend call (in a different thread), then it's going straight into the Log.d and for loop instructions, and only when the backend response is ready, it calls the handleResponse method.

The easiest way to fix it is to move the for loop inside the handleResponse, after your while loop; Depends on how you want to structure your code there are other ways of doing it by writing your for loop in a method and calling this method from the handleResponse, and there are also ways of choosing which thread should execute this code. But there's no enough information in the question to give you a proper recommendation for that.

palako
  • 3,342
  • 2
  • 23
  • 33
  • I already tried to move the for loop inside the handleResponse, but it didn't work because I make a second synchronization with Backendless in my for loop (not visible in the code) and the combination of these two is problematic... – Timitrov Nov 20 '16 at 10:54
  • I added the rest of the code. I hope you can better comprehend now where my problem is... – Timitrov Nov 20 '16 at 12:53
  • I don't see anything inside that loop that would stop you from running it inside the handleResponse method. If that's giving your problems maybe explain those and we can see what it is. Now, if you really don't want to do this, you can use something like while(!handleResponseFinished); and set handleResponseFinished to true inside handleResponse. Either that or some other mutex/semaphore. I do not recommend doing this, but it should work. – palako Nov 20 '16 at 13:13
  • Mate, believe me, that is not a good solution, it will lock the thread defeating the purpose of the asynchronous query. If this is the UI thread, your application will be unresponsive. If the query hangs, you might get into an infinite loop. Unless this is some sort of quick PoC work, don't do it. – palako Nov 20 '16 at 15:43