Обратный вызов 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, а не функций и данных.
Надеюсь, это немного поможет.