0

I'm having an embarrassing problem. For the life of me, I can't figure out why my code isn't working.

private void getParseObject(String title) {
    final String parseTitle = title;
    ParseQuery<ParseObject> query = ParseQuery.getQuery(title);
    query.findInBackground(new FindCallback<ParseObject>() {
        public void done(List<ParseObject> objects, ParseException e) {
            if (e == null) {
                if (objects.isEmpty()){
                    createParse(parseTitle);
                } else {
                    ParseObject event = objects.get(0);
                    int likes = event.getInt("likes");
                    JSONArray comments = event.getJSONArray("comments");
                    setParseInfo(likes, comments);
                }
             } else {
                Log.v("Miles", String.valueOf(e.getCode()));
             }
        }
    }); 
    Log.v("Miles", "LIKES FROM GOT " + likes);
}

public void setParseInfo(int likesFromParse, JSONArray commentsFromParse) {
    this.likes = likesFromParse;
    this.comments = commentsFromParse;
    Log.v("Miles", "LIKES FROM SET " + likes);
}

Within setParseInfo(int, JSONArray), I'm setting the global variable of my fragment. I can get the info fine, it's not null; In that log "LIKES FROM SET", the "likes" int appears more than normally. However, when I try to do the same within getParseObject() in that "LIKES FROM GOT" log, the "likes" int show up as 0. Any ideas on how I can fix this?

EDIT 1:

With the advice of Ryan J, I've tried doing something like this, and it has the same effect.

private void getParseObject(String title) {
    final String parseTitle = title;
    ParseQuery<ParseObject> query = ParseQuery.getQuery(title);
    query.findInBackground(new FindCallback<ParseObject>() {
        int nestedLikes = likes;
        JSONArray nestedComments = comments;

        public void done(List<ParseObject> objects, ParseException e) {
            if (e == null) {
                if (objects.isEmpty()){
                    createParse(parseTitle);
                } else {
                    ParseObject event = objects.get(0);
                    nestedLikes = event.getInt("likes");
                    nestedComments = event.getJSONArray("comments");
                    setParseInfo(nestedLikes, nestedComments);
                }
             } else {
                Log.v("Miles", String.valueOf(e.getCode()));
             }
        }
    }); 
    Log.v("Miles", "LIKES FROM GOT " + likes);
}

Which is what I think the suggestion was. However, the log "LIKES FROM GOT" still returns 0.

10
  • Set a global variable inside your nested function to the value of likes. It's not appearing as the expected value because once your inner function terminates, the variable goes out of scope. Commented Jul 20, 2014 at 4:12
  • You mean inside the findInBackground() function? Because I've tried that method to no avail. As in, I initialize an empty global variable right under findInBackground, set that to event.getInt("likes"), then pass that to setParseInfo(). It has the same effect; the "likes" int is still 0. Commented Jul 20, 2014 at 4:17
  • I mean inside your anonymous FindCallback class (the done method). Have you verified the proper value is being output in that class via the debugger or printing to console? Create a global variable in your top-level class, and set it to the value of likes in your anonymous class. That hasn't worked for you? Commented Jul 20, 2014 at 4:19
  • Yeah, as far as I can tell, that method doesn't work. Maybe I'm just not implementing it correctly... And yes, I have verified that. The event.getInt("likes") gets the correct value. The problem is getting that value to be assigned to the fragment's top-level global variable. Commented Jul 20, 2014 at 4:21
  • Maybe you can post more code where you've tried that method to no avail, with the corresponding output and we can be of further help. Commented Jul 20, 2014 at 4:22

1 Answer 1

1

You need to make the main thread wait for the background thread to complete.

Here is a simple way to make the main thread wait with a CountDownLatch:

import java.util.concurrent.CountDownLatch;

public class PassOutResult {
    public static void main(String[] args) {
        new PassOutResult().doMainThread();
    }

    void doMainThread() {
        try {
            final CountDownLatch latch = new CountDownLatch(1);
            Thread background = new Thread() {
                public void run() {
                    int r = 2;
                    setResult(r);
                    System.out.println("BackgroundThread: r=" + r);
                    latch.countDown();
                }
            };
            background.start();
            System.out.println("MainThread A: theResult=" + theResult);
            latch.await();
            System.out.println("MainThread B: theResult=" + theResult);
        } catch (InterruptedException ex) {
            System.err.println(ex);
        }
    }
    void setResult(int r) {
        theResult = r;
    }
    int theResult;
}

The above technique will work in Android Java, as well as Oracle Java (JRE).

By the way, if several threads are accessing a single variable (e.g. "theResult" in my sample code), then you should synchronize access to it. In my sample code the CoundDownLatch effectively synchronizes access. But in a large program where you cannot trust your knowledge of what threads are doing, it is usually simpler to wrap the variable in getter/setter methods, and make those methods synchronised.

synchronized int getResult() {
   return theResult;
}
synchronized void setResult(int r) {
   theResult=r;
}

Here is how to use CountDownLatch in the original code:

    private void getParseObject(String title) {
        final String parseTitle = title;
        final CountDownLatch latch = new CountDownLatch(1);
        ParseQuery<ParseObject> query = ParseQuery.getQuery(title);
        query.findInBackground(new FindCallback<ParseObject>() {
            public void done(List<ParseObject> objects, ParseException e) {
                if (e == null) {
                    if (objects.isEmpty()){
                        createParse(parseTitle);
                    } else {
                        ParseObject event = objects.get(0);
                        int likes = event.getInt("likes");
                        JSONArray comments = event.getJSONArray("comments");
                        setParseInfo(likes, comments);
                    }
                 } else {
                    Log.v("Miles", String.valueOf(e.getCode()));
                 }
                latch.countDown();
            }
        }); 
        latch.await();
        Log.v("Miles", "LIKES FROM GOT " + likes);
    }
Sign up to request clarification or add additional context in comments.

4 Comments

Your post is very confusing, as I am unused to working with threads. I'm using Parse API, so the findinBackground() automatically runs in background in its own thread; how am I supposed to wait for it if I have not directly created its own thread?
Miles - I answered your question with a more general program (Android or Oracle JRE) to help other users with the same question. I have edited my answer to show using CountDownLatch in your original code too. Please vote my answer up if it works.
Much appreciated, @Adam Gawne-Cain.
The only problem is that calling latch.await() blocks the UI thread indefinitely.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.