Android piccaso callback return before load - android

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?

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.

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

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.

Related

How to synchronously wait the Result callback from Android to Flutter using the invokeMethod?

I am trying to synchronously call some Flutter methods from Android (Java) using the Flutter MethodChannel.
invokeMethod(String method, #Nullable Object arguments, MethodChannel.Result callback)
I already tried CountDownLatch, locks and even Threads but would just stop after calling the countdown await or synchronize(lock) or even thread.join.
public class MainActivity extends AppCompatActivity {
// code/methods initializations..
public String testData(){
final String[] result = new String[1];
final CountDownLatch latch = new CountDownLatch(1);
flutterMethods.invokeMethod("getString", "abcdefg", new MethodChannel.Result() {
#Override
public void success(Object o) {
result[0] = o.toString();
Log.e(TAG,"success);
latch.countDown();
}
#Override
public void error(String s, String s1, Object o) {
latch.countDown();
}
#Override
public void notImplemented() {
latch.countDown();
}
}
Log.e(TAG,"about to wait forever!");
latch.await();
Log.e(TAG,"done!");
return result[0];
}
Of course, this will work asynchronously without the waits, but I want to make this into a synchronous library function at some point. How can this be done?
This cannot be done.
Flutter architecture is unique in the sense that communication with the OS always asynchronous.
The principle is that Flutter and the native side sends messages to each others by both listening to the same port on the device.
This allows increased performances as there is no "language bridge" but comes at the cost of being forced to be asynchronous.
First of all, this is a really terrible idea and you likely shouldn't do it. Callbacks are fine in 99% of use cases.
If you still really want to though, a simple way would be to just use a while(!messageRecieved) { // do something } style loop. The key important factor here is that you can't actually suspend the thread, because if you do it will be unable to receive any messages.
If you don't want to cause unneeded CPU usage, you could try to do a small IO operation in the body of the loop.

How to synchronize two methods in Android?

I use OpenCV's JavaCameraViewto capture images. So it has onCameraFrame method.
#Override
public Mat onCameraFrame(CvCameraViewFrame inputFrame) {
rgb = inputFrame.rgba();
if(viewMode == VIEW_MODE_EDGE){
Mat mIntermediateMat = new Mat(rgb.size(), rgb.type());
Imgproc.Canny(rgb, mIntermediateMat, 80, 90);
Imgproc.cvtColor(mIntermediateMat, rgb, Imgproc.COLOR_GRAY2BGRA, 4);
mIntermediateMat.release();
}
return rgb;
}
That method is always runing and I convert the incoming image to Canny edge and display.
I implemented a button to copy that Canny image and pass to another activity. For that I made a global public static Mat Canny_image; When the button is pressed the rgb image from onCameraFrame is copied to Canny_image. Then the next activity is called.
My code is
ImageCapture.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
if (mOpenCvCameraView != null)
{
Canny_image= rgb.clone();
}
final Intent intent = new Intent(ctxt, TextExtraction.class);
intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(intent);
}
});
Problem: when i press the button and if canny conversion is finished in onCameraFramemethod, I receive the canny image (the image with only edges). But if it is not converted yet or half way converted, I receive original rgb image (original rgb image) or half way converted image. How can I make sure I receive only canny image and make sure the conversion process is completed and do cloning as Canny_image= rgb.clone();in ImageCapture.setOnClickListener(new OnClickListener(){};
Thanks
To synchronise two methods in Android Java you can use the synchronized(this) syntax:
Public void OnFrameAvailable() {
synchronized(this) {
// Wair for condition false...
// Flag condition true.
}
}
And
Public void ProcessFrame() {
synchronized(this) {
// Wair for condition true...
// Do something with incoming data...
// Flag condition false
}
}
This would ensure that both methods execute in mutual exclusion, although in general is not a good idea to make a callback wait... If you fully want to decouple both, you should have a thread for processing, with a Looper, and post() a Runnable to it from the OnFrameAvailable().
I don't have any knowledge of android but just a suggestion..isn't possible for you to set a flag (e.g set Flag=1) after getting the Canny image onCameraFrame method and in the another method you made a check that whether the flag ==1 or not?
first()
{
flag = 0;
convert to canny;
flag=1;
}
second()
{
if(flag ==1)
try to get the Canny image
}
And excuse me if its not possible :)
Assuming rgb is a static then one immediate thing to point out is that this will be 4 channel Mat on the call (use inputFrame.gray() if you want a single channel). Canny is expecting a single channel as is the call to CvColor viz the COLOR_GRAY2BGRA conversion type. I don't think that is causing your particular problem but worth checking out.
As onCameraFrame is a callback you could well be processing rgb when another call comes in so rgb could be getting overwritten before you return it in the method. Adding synchronized to the onCameraFrame method should help in that regard but this might impact performance. Alternatively, making rgb local to onCameraFrame should also avoid that particular concurrency issue.
One final thought is rather than do the copy when you click the button, you could do the copy to Canny_image when you finish processing in onCameraFrame so it is always available and onClick will take the current version.

Getting results from an AsyncTask

I'm trying to use AsyncTask to download a string and return the string. I want to use AsyncTask because it might take a while.
One problem is that nowhere on the internet can I find an example of an AsyncTask returning any kind of value. So I took the example in the Commonsware book and modified it to return a value and I get the value as follows:
String mystr = new AddStringTask().execute().get();
While this works, it seem that this line of code is waiting for the return value and therefore synchronous. There must be some way to have an event trigger with the results of the AddStringTask.
How is that done?
Thanks, Gary
An AsyncTask cannot return a value, because to get the returned value you would have to wait before the task is finished. That would make the AsyncTask meaningless.
Instead, you should move your code in onPostExecute() (which runs on the UI thread, if this is what you worry about). This is where you handle the value returned by doInBackground() and typically update the UI or show an error message.
Also if you wanted to implement a more general AsyncTask you could implement something like the following to compartmentalize your code inside the activity.
#Override
protected void onPostExecute(Bitmap r){
if (r != null) {
processListeners(r);
}
}
protected void processListeners(Object data) {
for (final AsyncTaskDone l : listeners) l.finished(data);
}
public void addAsyncTaskListener (final AsyncTaskDone l){
listeners.add(l);
}
Where AsyncTaskListener is an interface with one function called finished implemented in the Activity the same way an onClickListener would be.

Android AndEngine - How can I update ChangeableText value

I have a little problem with ChangeableText in AndEngine. I want to know how to update it's text without freezing the screen? For now I'm using this way, but it's freezing my phone for maybe 2-3 seconds :
private void removeFace(final Sprite face) {
hm = getIconNames();
if(face.getUserData().equals("petrol")){
elapsedText.setText(hm.get(25));
final PhysicsConnector facePhysicsConnector = this.mPhysicsWorld.getPhysicsConnectorManager().findPhysicsConnectorByShape(face);
this.mPhysicsWorld.unregisterPhysicsConnector(facePhysicsConnector);
this.mPhysicsWorld.destroyBody(facePhysicsConnector.getBody());
this.mScene.unregisterTouchArea(face);
this.mScene.detachChild(face);
} else {
}
System.gc();
}
Any ideas how to do that?
Remember that when you detachChild you should do this in thread because if you don't it can causes errors. Use this construction
runOnUpdateThread(new Runnable(){
#Override
public void run() {
if(yourSprite.hasParent())
scene.detachChild(yourSprite);
}});
You can put there all code if you want then your phone shouldn't freez
private void removeFace(final Sprite face) {
runOnUpdateThread(new Runnable(){
#Override
public void run() {
hm = getIconNames();
if(face.getUserData().equals("petrol")){
elapsedText.setText(hm.get(25));
final PhysicsConnector facePhysicsConnector = this.mPhysicsWorld.getPhysicsConnectorManager().findPhysicsConnectorByShape(face);
this.mPhysicsWorld.unregisterPhysicsConnector(facePhysicsConnector);
this.mPhysicsWorld.destroyBody(facePhysicsConnector.getBody());
this.mScene.unregisterTouchArea(face);
this.mScene.detachChild(face);
} else {
}
System.gc();
}});
}
Thats probably because you are fetching some information while setting the text.
What you should do is, get your
String hm = hm.get(25); //What ever the correct object is or variable. im guessing its a string or int.
Then
pass it to the Changeable text to be set.
elapsedText.setText(hm); //If its a int make sure you do String.valueOf(hm);
The only 3 methods here that have the possibility to take long are getIconNames() and get(), and System.gc()
The others are usually methods that return immediately, or have a very low complexity. For example, getPhysicsConnectorManager() returns immediately. findPhysicsConnectorByShape, unregisterPhysicsConnector, unregisterTouchArea and detachChild all have complexity of O(n), (And most of the others methods also have complexity of O(1) or O(n)).
I recommend you to look in the LogCat and when System.gc() is called, you will see a Log.i (blue) message of the tag of dalvikvm which will begin with GC_EXPLICIT and will give you some information about how long did the garbage collection took, etc....
If that GC call isn't taking the time, it must be your 2 methods, getIconNames() and hm.get(). You can put a Log.d message after each code line, which will write the last code line executed. This way you can follow the times.

Android activity life cycle - restarting (destroying) app does not remove reference to (custom) listener?

I have an application using a GlSurfaceView and renderer. I have it set so that when the user exits the application via the back button I call myActivity.finish();
This is fine and I can see the activity getting calls to onStop() and onDestroy();
The app works fine the first time run however when I subsequently run I have had a problem with my motionEvents.
I handle motion events by queuing them into a pool and having the renderer access the pool at the right time like so:
try
{
//Get the history first
int hist = event.getHistorySize();
if (hist > 0)
{
//Oldest is first in the list. (I think).
for (int i=0;i <hist; i++)
{
InputObject input = inputObjectPool.take();
input.useEventHistory(event, i);
defRenderer.feedInput(input);
}
}
//The current one still needs to be added
InputObject input = inputObjectPool.take();
input.useMotionEvent(event);
defRenderer.feedInput(input);
}
And in the renderer:
synchronized (inputQueueMutex)
{
ArrayBlockingQueue<InputObject> inputQueue = this.inputQueue;
while (!inputQueue.isEmpty()){try
{
InputObject input = inputQueue.take();
if (input.eventType == InputObject.EVENT_TYPE_TOUCH)
{
screenManager.processMotionEvent(input);
}
else if (input.eventType == InputObject.EVENT_TYPE_KEY)
{
screenManager.processKeyPress(input);
}
input.returnToPool();
}
catch (InterruptedException ie)
{
DLog.defError("Interrupted blocking on input queue.", ie);
}
}
}
As you can see in the above code I hand these motion events to the ScreenManager which basically is my way of having several "scenes" which I render out. This works fine the first time I run the application and the screen interprets my motion touches into movement of a simple square at the moment.
However the second time I run the application the square is drawn to the screen fine however the motion events do nothing.
I have followed the motion events and although they are given to the "new" renderer it seems to be giving the motion events to an old screen. Or rather to an old object on the screen. This is confusing as in my code in the onCreate() method I do this:
//Set up the renderer and give it to the SurfaceView
defRenderer = new DefRenderer();
defView = new DefView(this);
defView.setRenderer(defRenderer);
//Set out content to the surface view.
setContentView(defView);
//Set up the input queue
createInputObjectPool();
OnCreate is called both the first time and the second time my app is run (and the app was destroyed!) the screens are made new in defRenderer and are given to a new defView.
I am very confused how data could remain in the defRenderer to receive the motionEvents as the app is completely remade.
Is there something obvious going on that I am missing here? I would have thought that when onDestroy is called the app would be completely dereferenced and so no trace of it would remain. Is this not true? Does somehow when I call new Renderer(); is it referencing an old one?
I am at a loss as to what is going on really. Especially as this app is a basic copy of another I have written which works completely fine!
EDIT:
After a small amount of experimentation I have discovered that the motion events are actually going to an old ScrollPanel (an object I made..) which is registered as a listener (and by listener I mean my own implementation ..) for MotionEvents. I have made my own event system for these like so:
public interface TouchSource
public static final int TYPE_TOUCHDOWN = 0;
public static final int TYPE_TOUCHDRAG = 1;
public static final int TYPE_TOUCHCLICK = 2;
public Vector<TouchListener> listeners = new Vector<TouchListener>();
public void addTouchListener(TouchListener listener);
public void removeTouchListener(TouchListener listener);
public void touchOccured(int type, int xPos, int yPos);
}
And the listener interface:
public interface TouchListener
public boolean touchDownOccured(int xPos, int yPos);
public boolean touchDragOccured(int xPos, int yPos);
public boolean touchClickOccured(int xPos, int yPos);
So the Screen implements touchSource and so has a list of the listeners. Now despite being REMADE by Screen currentScreen = new Screen(); called in the OnCreate(); of the manager this list of listeners is still populated with the old ScrollPanel?
How is this? I'm clearly missing something obvious. Like somehow the list of listeners is static for some reason and not getting dereferenced despite the app being completely remade?
I suspect the issue you're facing might have something to do with the fact that the original motionevents are recycled (returned to their pool) by the framework after the onMotionEvent() returns.
From the way you're using your InputObjects, I think you might be keeping a reference to the original motionevents in there, and not copying the event data.
Quickly try using MotionEvent.obtain(event) whereever you use event now (this makes a copy) and see if this makes the weird behaviour go away. Naturally, if this works you will eventually have to recycle() those copies after you're done with them. Do not call recycle() on the original motionevents though.
Cheers, Aert.

Categories

Resources