I want to perform some operations when quitting a Processing sketch. I found on forums that method stop() is called before the application quits.
I tried it, but it seems to me it is never called.
Here follows a minimal (not working) example:
void setup()
{
size(100, 100);
println("start");
}
void draw()
{
//nothing here
}
void stop()
{
println("called stop()");
super.stop();
}
When quitting the application , through stop button on the IDE or
through X button on App, I never see the message "called stop()".
I tried both with and without super.stop(), nothing changes.
Thanks
Processing 2.2.1, on Linux Debian Wheezy
The stop() function is a leftover from the fact that PApplet extends Applet. Unless you're deploying as an applet, the stop() function will never be called. Even if you are deploying as an applet, the stop() function is still not guaranteed to be called! More info in the PApplet API.
Assuming you're using Java mode, you might look into adding a shutdown hook, or just add a WindowListener to your frame.
In addition to Kevin's answer, you an override the exit() method:
void setup(){
println("start");
}
void draw(){}
void exit(){
println("stop");//do your thing on exit here
super.exit();//let processing carry with it's regular exit routine
}
Related
My code looks like this:
public void Init() {
if (AS.pti == PTI.UserInput)
{
AS.runCardTimer = false;
}
else
{
AS.runCardTimer = true;
Device.BeginInvokeOnMainThread(() => showCards().ContinueWith((arg) => { }));
}
}
The Init method is called from the constructor. Can someone please explain to me why the developer might have added the Device.BeginInvokeOnMainThread() instead of just calling the method showCards?
Also what does the ContinueWith((arg)) do and why would that be included?
The class where this Init() method is might be created on a background thread. I'm assuming showCards() are updating some kind of UI. UI can only be updated on the UI/Main thread. Device.BeginInvokeOnMainThread() ensures that the code inside the lambda is executed on the main thread.
ContinueWith() is a method which can be found on Task. If showCards() returns a task, ContinueWith() makes sure the task will complete before exiting the lambda.
UI actions must be performed on UI thread (different name for main thread). If you try to perform UI changes from non main thread, your application will crash. I think developer wanted to make sure it will work as intended.
The simple answer is: Background thread cannot modify UI elements because most UI operations in iOS and Android are not thread-safe; therefore, you need to invoke UI thread to execute the code that modifies UI such MyLabel.Text="New Text".
The detailed answer can be found in Xamarin document:
For iOS:
IOSPlatformServices.BeginInvokeOnMainThread() Method simply calls NSRunLoop.Main.BeginInvokeOnMainThread
public void BeginInvokeOnMainThread(Action action)
{
NSRunLoop.Main.BeginInvokeOnMainThread(action.Invoke);
}
https://developer.xamarin.com/api/member/Foundation.NSObject.BeginInvokeOnMainThread/p/ObjCRuntime.Selector/Foundation.NSObject/
You use this method from a thread to invoke the code in the specified object that is exposed with the specified selector in the UI thread. This is required for most operations that affect UIKit or AppKit as neither one of those APIs is thread safe.
The code is executed when the main thread goes back to its main loop for processing events.
For Android:
Many People think on Xamarin.Android BeginInvokeOnMainThread() method use Activity.runOnUiThread(), BUT this is NOT the case, and there is a difference between using runOnUiThread() and Handler.Post():
public final void runOnUiThread(Runnable action) {
if (Thread.currentThread() != mUiThread) {
mHandler.post(action);//<-- post message delays action until UI thread is scheduled to handle messages
} else {
action.run();//<--action is executed immediately if current running thread is UI thread.
}
}
The actual implementation of Xamarin.Android BeginInvokeOnMainThread() method can be found in AndroidPlatformServices.cs class
public void BeginInvokeOnMainThread(Action action)
{
if (s_handler == null || s_handler.Looper != Looper.MainLooper)
{
s_handler = new Handler(Looper.MainLooper);
}
s_handler.Post(action);
}
https://developer.android.com/reference/android/os/Handler.html#post(java.lang.Runnable)
As you can see, you action code is not executed immediately by Handler.Post(action). It is added to the Looper's message queue, and is handled when the UI thread's scheduled to handle its message.
I have Processing 3 code that is exhibiting some odd behavior. I have a void exit() method defined that is being executed at random times without the user actually telling the code to exit. Here is the method:
void exit()
{
println("clearing buffer and closing file");
if (output != null) {
print("output is not null");
try {
output.close();
}
catch (IOException e) {
println("Error while closing the writer");
}
}
super.exit();
}
As you can see, the only thing that it does is attempt to close a buffered writer called output. Flushing this writer is not critical, so for now I am just removing it from my sketch. But long term, I am curious how this can be happening. Nowhere else in my code is the exit method explicitly called. IE, the code cannot decide to exit. It is only when the user closes the problem using the X.
Note: I cannot upload the entire code this method is attached too because it is too long. I think perhaps a better way to phrase my questions would be something like:
"Hi, I am a noob that doesn't know anything about the exit method. Is there anyway that this method could somehow get called without me explicitly calling it or hitting the exit button?"
Add this at the beginning of your exit() method.
new Exception().printStackTrace();
The resulting stacktrace should allow you to figure out what is calling your exit() method.
Or if you can't tweak the code, you can run the application using a debugger and set a breakpoint at the start of the exit() method.
To answer your question about whether it is possible, the answer depends on what you mean by "without me explicitly calling". There are various ways to call a method, some of which are quite obscure; e.g.
You can use reflection to get the Method object for the exit method from the declaring class, and then call invoke(...) on it.
You can call a Java method from native code via the JNI or JNA apis.
You can generate Java source code that contains an exit() call, compile it, load it, and run it.
You can insert an exit() call into an "innocent" method using BCEL or similar.
And ...
If there is a debug agent attached to the JVM, the debugger can call exit() on some thread in the JVM.
In short, the answer to your question is Yes.
Your method could be found and invoked dynamically using reflection by any class in the same classloader or any other that is below in the hierarchy.
Also, it has a default access. So it could be invoked statically by any class in the same package.
+1 for #Andres, reflection is one possibility.
Have you tried using a breakpoint on the method and looking at the thread's stacktrace?
Personally I don't use breakpoints (just my style) and would try and look at the thread programmatically. Maybe some of the following code can help you look at the thread and get an idea of what's going on:
public class ThreadUtil {
/** Blocked constructor **/
private ThreadUtil() {
}
/**
* Get the stackstrace of the current {#link Thread}.
* The stacktrace will be returned in the form of a string.
*/
public static String getStackTrace() {
return getStackTrace(Thread.currentThread());
}
/**
* Get the stackstrace of a {#link Thread}.
* The stacktrace will be returned in the form of a string.
*/
public static String getStackTrace(Thread thread) {
StringBuilder sb = new StringBuilder();
StackTraceElement[] currThreadStackTraceElementList = thread.getStackTrace();
appendStackTrace(sb, currThreadStackTraceElementList);
return sb.toString();
}
public static String getAllStackTraces() {
StringBuilder sb = new StringBuilder();
Map<Thread, StackTraceElement[]> threadList = Thread.getAllStackTraces();
for (StackTraceElement[] currThreadStackTraceElementList : threadList.values()) {
appendStackTrace(sb, currThreadStackTraceElementList);
}
return sb.toString();
}
private static void appendStackTrace(StringBuilder sb,
StackTraceElement[] currThreadStackTraceElementList) {
sb.append("Thread stack trace: \n");
for (StackTraceElement currThreadStackTraceElement : currThreadStackTraceElementList) {
sb.append("\t" + currThreadStackTraceElement + "\n");
}
sb.append("\n");
}
}
It's a Processing-specific thing.
void exit() is a method already defined by processing in PApplet.java
As explained in the reference:
Rather than terminating immediately, exit() will cause the sketch to
exit after draw() has completed (or after setup() completes if called
during the setup() function).
For Java programmers, this is not the same as System.exit(). Further,
System.exit() should not be used because closing out an application
while draw() is running may cause a crash (particularly with P3D).
exit() it is expected to be used something like this:
void draw() {
line(mouseX, mouseY, 50, 50);
}
void mousePressed() {
exit();
}
It is called within PApplet.java in a few places, notably in handleKeyEvent to close the sketch when ESC is pressed, or when ⌘w is pressed.
Just rename your method to something other than exit()
I am using this example:
Android - Setting a Timeout for an AsyncTask?
in the following way:
al.setOnClickListener(new OnClickListener(){
public void onClick(View w)
{
final AlogLoader loader = new AlogLoader();
loader.execute();
Handler handler = new Handler();
handler.postDelayed(new Runnable()
{
public void run()
{
if(loader.getStatus() == AsyncTask.Status.RUNNING)
{
loader.cancel(true);
}
}
}, 1);
}
});
I set it to "1" because I wanted to see if I can stop it practically before it even starts - to see if my handler is working - in reality I would probably set it to 15000 (15 seconds).
However what happens is confusing:
Running the application, causes my onPreExecute() to draw a loading screen, which doesn't ever exit, so the user just sees a loading screen perpetually.
Running it in the debugger with the breakpoint at loader.cancel(true) -> Causes the debugger to stop at that line, which is expected because its only allowed to run for 1 millisecond. However, when I hit the resume button in the debugger after that - my onPostExecute() is called... How is that possible?
Clearly, I'm very new to timing out asynctasks - after some research, I found the example above and it seemed to make the most sense to me, definitely more then
loader.get(15000, TimeUnit.MILLISECONDS);, since that blocks the UI Thread.
Any help is appreciated...even an explanation on the process..
Okay,
So I essentially solved my problem but I am still confused... Don't know if that's all good.
I was unclear on how loader.cancel(true) actually works. Based on the API level (read this question : AsyncTask.onCancelled() not being called after cancel(true)) you need to have an onCancelled() or onCancelled(params) method, or both in your AsyncTask.
I did not have this, so this explains why I saw a loading screen forever. Okay Good.
Yet, it doesn't explain how in the debugger, I managed to still call the onPostExecute(), because according to Android API's, onPostExecute is never called once cancel(true) has been called...
The answer is:
Add this to your AsyncTask-
#Override
protected void onCancelled()
{
Toast.makeText(FriendsActivity.this,"Blah- reason", Toast.LENGTH_LONG).show();
loadingScreen.dismiss();
}
I have a BlackBerry App that has a Listener for the Send Button implemented in the CheckIn Screen. Data is sent through a web service. If the data is sent successfully, a confirmation message of "OK" is received. I am trying to switch screens in my BlackBerry App depending on the response received.
FieldChangeListener sendBtnListener = new FieldChangeListener() {
public void fieldChanged(Field field, int context)
{
try {
String alertMsg=sendTextCheckIn();
if(alertMsg.equals("OK"))
{
UiApplication.getUiApplication().invokeLater( new Runnable()
{
public void run ()
{
UiApplication.getUiApplication().pushScreen(new MyScreen());
}
} );
}
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
However, the above is throwing an App Error 104: IllegalStateException. Can anyone please guide on how to switch screens between a BlackBerry App.
EDIT: I can switch to any other screen but I CAN NOT switch to MyScreen. NOTE: MyScreen is the main (first) screen of the App. The above method sendTextCheckIn() calls another method that is placed inside MyScreen. Has this got anything to do with the error? Please advice.
The 'fieldChanged' event is already running on the UI event thread, so you shouldn't need to do the invokeLater call within it, just call pushScreen directly.
You mention that your problem with IllegalStateException only happens for MyScreen. That makes it sound like something specific with the implementation of MyScreen. Start narrowing down the problem - look at what happens in the constructor of MyScreen, and any events that might get called before the screen is visible. Some of that code is what is causing the problem.
Wrap everything that could possibly raise in exception in try/catch.
Don't do e.printStackTrace() - that won't give you much.
Instead do something like System.err.println ("KABOOM in method abc() - " + e); - seems like more effort, but trust me, that becomes INVALUABLE when debugging issues like this.
Catch Exception, unless you have a VERY good reason to catch a specific a subtype - otherwise you WILL end up with unexpected, and uncaught exceptions, which you will hunt for DAYS.
Im am making an Java SWT program that is required to run on both Linux and Windows.
I use the following Code to listen for KeyUp events:
Control.addListener(SWT.KeyUp, new Listener() {
public void handleEvent(Event arg0) {
System.out.println("Event");
}
});
But this does not trigger when no control has focus.
Do anyone know of a place i can add a listener that acts as a Catch-all?
The only way of doing this that I'm aware of is by placing a filter on the Display. Take note that multiple Shells may operate on one Display, so you should be careful!
shell.getDisplay().addFilter(SWT.KeyDown, new Listener() {
public void handleEvent(final Event event) {
System.out.println(event);
}
});
try following method in Display class:
public void addListener ( int eventType, Listener listener )
I have not been able to find a solution to this. I suspect none exist