0

i have an android mobile app and im trying to check if a specific LatLng is at water, so im using google static map api to get an image of the location, and then to check if the image is blue.

im using this code -

private boolean result;
    public boolean IsWater(LatLng position)
    {
        imageView = (ImageView) this.findViewById(R.id.imageView);
        checkText= (TextView) this.findViewById(R.id.checkText);
        String lati = Double.toString(position.latitude);
        String longi = Double.toString(position.longitude);
        String url = "http://maps.googleapis.com/maps/api/staticmap?center="+lati+"," + longi + "&zoom=20&size=1x1&style=element:labels%7Cvisibility:off&style=element:geometry.stroke%7Cvisibility:off";
        Picasso.with(MainActivity.this).load(url)
                .into(imageView, new com.squareup.picasso.Callback() {
                    @Override
                    public void onSuccess() {
                        Bitmap bitmap = ((BitmapDrawable) imageView.getDrawable()).getBitmap();
                        int pixel = bitmap.getPixel(0, 0);
                        int blueValue = Color.blue(pixel);
                        if(blueValue>250)
                        result =true;
                    }

                    @Override
                    public void onError() {
                        result =false;
                    }
                });
        return result;
    }

the problem, i think, is that it is not synchronized, and IsWater get to the last line and return a null for result before the onSuccess kicks in...

any thoughts?

Tamir Huber
  • 77
  • 1
  • 2
  • 9
  • Possible duplicate of [How to load a Bitmap with Picasso without using an ImageView?](http://stackoverflow.com/questions/24302431/how-to-load-a-bitmap-with-picasso-without-using-an-imageview) – Austyn Mahoney Nov 02 '15 at 21:00

3 Answers3

0

Picasso loads images on a background thread by default. The operation you are running is asynchronous. Therefore, it does not block your method from returning result before the onSuccess callback has been called.

Austyn Mahoney
  • 11,398
  • 8
  • 64
  • 85
0

The problem is Picasso is running Async. within the calling method "isWater", so what ends up happening is the method will return 'false' because instead of waiting on Picasso to finish because it isn't in serial execution. This is due to the function call's stack frame being popped off the stack once it reaches the return statement.

What you need to do is the following by using a Target.

// make sure to set Target as strong reference
private Target loadtarget;


public void loadBitmap(String url) {

    if (loadtarget == null){
        loadtarget = new Target() {

            @Override
            public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
                // do something with the Bitmap
                handleLoadedBitmap(bitmap);
            }

            @Override
            public void onBitmapFailed() {

            }
        };
    }

    Picasso.with(this).load(url).into(loadtarget);
}

public void handleLoadedBitmap(Bitmap b) {
    // do something here
}

This code was taken from here, and should offer you some insight on how to get it work for your goal.

A Target is essentially an object that holds the bitmap you need so it is still in memory. Generally used for custom view objects though as a field. Here is documentation Target docs

Community
  • 1
  • 1
Lucas Crawford
  • 3,078
  • 2
  • 14
  • 25
0

Asynchronous execution is one of the hardest things to wrap ones head (and subsequently ones code) around. In all of the JavaScript frameworks I've used, the network communication is done in a background thread. The intended effect is that the User Interface thread is left free to keep the user from thinking that things locked up. Mouse-overs and tool-tips will all still work, while a background thread is dragging data out of a slow server.

The code patterns, on the other hand, aren't as nicely shaped.

My problem is/was still basically thinking linearly, or functionally, instead of embracing the event-driven nature of modern JavaScript: Passing a function to an asynchronous method to completely handle that response. Not just return a value, but perform the full task that the value was needed for. The callback can call the other functions to assist with that task, and may be able to fill in a cache (of whatever sort) so that other functions that may need this data do not necessarily have to wait for another response. This often (to me) feels backwards from the logic pattern I was following to solve the original purpose of the code.

I've stumbled on this pattern-flip many times, coming from C/C++ as my first programming language. It can sometimes help to avoid the anonymous function pattern of callback definition and define one's callback functions with names, then pass the name to the asynchronous call, but that is extra steps and extra memory use in the long run. The big hurdle is thinking in terms of Event and EventHandler, versus function and data.

I hope this helps a little.

Alderin
  • 150
  • 1
  • 8