Search code examples
javaandroidstackmob

Proper way to extract object from StackMob query (anonymous inner class) in Android


The StackMob Documentation lets us know how to properly perform a query: https://developer.stackmob.com/tutorials/android/Query-an-Object

My question is what is the correct way in Java to actually extract this information from the query's inner class?

MyObject valueToReturn;

MyObject.query(MyObject.class, 
    new StackMobQuery().field(
    new StackMobQueryField(field).isEqualTo(val)), 
    new StackMobQueryCallback<MyObject>() {
        @Override
        public void failure(StackMobException arg0) {
            //nothing to see here.
        }
        @Override
        public void success(List<MyObject> arg0) {
            //
            //How do I set valueToReturn = arg0.get(0)?
            //or in any way access this list outside the
            //inner class.
            return;
        }
});

There seems to be a solution here, but surely there is a better way. https://stackoverflow.com/a/5977866/1528493


Solution

  • I'm from StackMob, though this is more of a general Android question.

    It sounds like you're trying to do synchronous IO. MyObject.query is asynchronous, meaning that it will return immediately and execution will continue on. By the time the success callback is called, the method you're in may well have completed and valueToReturn may well have gone out of scope, which is why you're not allowed to set it.

    The query method is asynchronous for a reason. You don't want to be doing IO on the main thread on android, since that would be blocking everything else. On Android you need to think more in terms of callbacks. Rather than trying to do this:

    void myMethod() { MyObject valueToReturn;
    
        MyObject.query(MyObject.class, ..., new StackMobQueryCallback<MyObject>() {
            @Override
            public void failure(StackMobException arg0) {
              //nothing to see here.
            }
            @Override
            public void success(List<MyObject> arg0) {
                valueToReturn = arg0.get(0);
            }
        });
        blockUnilItReturns()
        doSomethingWith(valueToReturn);
    }
    

    You want to do something like:

    void myMethod() {
        MyObject.query(MyObject.class, ..., new StackMobQueryCallback<MyObject>() {
            @Override
            public void failure(StackMobException arg0) {
              //nothing to see here.
            }
            @Override
            public void success(List<MyObject> arg0) {
                doSomethingWith(arg0.get(0));
            }
        });
    }
    

    You may then want to do runOnUiThread to show a Toast or other UI actions. It's a different way of thinking about programming, but it's how you handle the asynchronous nature of IO in a mobile application.

    If you have a really good reason for wanting your method to be synchronous, you can do so with the array trick you link to and something that blocks like CountDownLatch http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/CountDownLatch.html Just be sure it's really what you want, I suspect it isn't.