This is hopefully an easy question regarding the thread-safety of the View.getWidth()
and View.getHeight()
methods.
I'm writing a background task that performs an operation given a View object. The only part of the view that is actually necessary is its dimensions. However, there is a possibility that the view hasn't gone through the layout process when my task is initiated and so its dimensions are set to 0. The task is initiated on the UI but runs a long operation in the background before returning to the UI thread to post the result (much like an AsyncTask
).
I was wondering what the repercussions are of calling those getter methods from a background thread. I know that the UI toolkit is designed to be single threaded and so I'm afraid that I may be running the risk of an unsafe publication.
Kcoppock has a great solution here about avoiding this problem all together by receiving a callback on the UI thread when the dimensions are known.
I wrote a small test to see when those dimensions would be visible from the background thread (attached below) and it seems that they are available at the same time as the callback.
Of course I understand that this doesn't prove anything so I would be grateful if someone with a greater knowledge of the UI framework could chime in.
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final ImageView view = new ImageView(this);
view.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
Log.d("TAG", Thread.currentThread().getName() + ": onGlobalLayout()");
Log.d("TAG", Thread.currentThread().getName() + ": view dimensions: " + view.getWidth() + "x" + view.getHeight());
}
});
// Bad code follows
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
Log.d("TAG", Thread.currentThread().getName() + ": view dimensions: " + view.getWidth() + "x" + view.getHeight());
try {
Thread.sleep(1);
} catch (InterruptedException ignored) {}
}
}
}).start();
setContentView(view);
Log.v("TAG", "Set view as content");
}