bitwise bitwise - 7 months ago 21
Java Question

How to capture enclosing scope in Runnable

I'm trying to do a stream of updates on a

HandlerThread
using the class below, but I have a couple of questions about how variable capture works in Java.

[1] Is
ret
captured from the enclosing scope by reference?

[2] Does
this
refer to the
Runnable
, or is it captured from the enclosing scope?

[bonus]
StartStream
should post a
Runnable
to the handler thread, and only return when the
Runnable
has completed. Will the code below work as expected?

public class Stream extends HandlerThread {
Handler handler = null;

Stream() {
super("Stream");
handler = new Handler(getLooper());
start();
}

private int _startStream() { // Start some repeating update
return 1;
}

public int StartStream() {
int ret = -1;

handler.post(new Runnable(){
@Override public void run() {
synchronized(this) {
ret = _startStream(); // [1]
this.notify(); // [2]
}
}
});

synchronized(this) {
while(ret == -1) {
try {
this.wait();
}
catch (InterruptedException e){}
}
}

return ret;
}
}

Answer

Inner classes have implicit references to outer class.

To use ret in anonymous inner class it should be final. The reason local variables cannot reference as non-final is because the local class instance can remain in memory after the method returns. It also depends on java version. Still it should be "effectively final" or move it to a member variable.

this refers to the Runnable, you should use Stream.this for enclosing one.