Обратный вызов Android Piccaso перед загрузкой

У меня есть мобильное приложение для Android, и я пытаюсь проверить, находится ли конкретный LatLng в воде, поэтому я использую API статической карты Google, чтобы получить изображение местоположения, а затем проверить, является ли изображение синим.

я использую этот код -

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;
    }

проблема, я думаю, в том, что он не синхронизирован, и IsWater переходит к последней строке и возвращает нулевой результат до того, как включится onSuccess...

Какие-нибудь мысли?

3 ответа

Проблема в том, что Пикассо работает под управлением Async. в вызывающем методе "isWater", так что в итоге метод вернет "ложь", потому что вместо ожидания завершения Пикассо, потому что он не находится в последовательном исполнении. Это связано с тем, что кадр стека вызова функции выталкивается из стека, как только он достигает оператора return.

Что вам нужно сделать, это с помощью цели.

// 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
}

Этот код был взят отсюда и должен дать вам некоторое представление о том, как заставить его работать для вашей цели.

По сути, цель - это объект, который содержит растровое изображение, которое вам нужно, поэтому оно все еще находится в памяти. Обычно используется для пользовательских объектов просмотра, хотя и как поле. Вот документация Target Docs

Пикассо загружает изображения в фоновом потоке по умолчанию. Операция, которую вы выполняете, является асинхронной. Следовательно, он не блокирует возврат вашего метода result перед onSuccess обратный вызов был вызван.

Асинхронное выполнение - одна из самых трудных вещей, чтобы обернуть голову (и впоследствии код) вокруг. Во всех JavaScript-фреймворках, которые я использовал, сетевое взаимодействие осуществляется в фоновом потоке. Предполагаемый эффект заключается в том, что поток пользовательского интерфейса остается свободным, чтобы пользователь не думал, что все заблокировано. Наведите курсор мыши и всплывающие подсказки будут работать, пока фоновый поток перетаскивает данные с медленного сервера.

Шаблоны кода, с другой стороны, не так хорошо оформлены.

Моя проблема заключается в том, что я до сих пор в основном мыслил линейно или функционально, вместо того, чтобы принять управляемый событиями характер современного JavaScript: передача функции в асинхронный метод для полной обработки этого ответа. Не просто вернуть значение, но выполнить всю задачу, для которой это значение было необходимо. Обратный вызов может вызывать другие функции, чтобы помочь с этой задачей, и может быть в состоянии заполнить кэш (любого рода), так что другие функции, которые могут нуждаться в этих данных, не обязательно должны ждать другого ответа. Это часто (для меня) кажется отсталым от логического шаблона, которому я следовал, чтобы решить первоначальную цель кода.

Я много раз сталкивался с этим переворотом, исходящим из C/C++ как моего первого языка программирования. Иногда это может помочь избежать шаблона анонимной функции определения обратного вызова и определить функции обратного вызова с именами, а затем передать имя асинхронному вызову, но это дополнительные шаги и дополнительное использование памяти в долгосрочной перспективе. Большим препятствием является мышление в терминах Event и EventHandler, а не функций и данных.

Надеюсь, это немного поможет.

Другие вопросы по тегам