Just came across a less reproducible NPE around WeakReferences and no wonder this wasn't caught in a code review. In this case, the back end logic held a WeakReference on a ListView's adapter and the idea is to update the ListView only when its necessary. The code was very simple and is often overlooked.
if (mAdapter.get() != null) {
mAdapter.get().notifyDataSetChanged();
}
And this worked fine except for a crash once in a while. Basically, the WeakReference was holding on to the object in the check but not when it was being used to update the adapter. So the object was basically garbage collected. Thats a tiny window for a race and yet the GC found its way. So just to demonstrate, how about repeated attempts?
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.gc();
}
}
});
if (mAdapter.get() != null) {
while (true) {
Log.e("GC", "Actual object is [" + mAdapter.get() + "]");
}
}
A thread is launched just to trigger garbage collection once a second and that basically illustrates the problem.
if (mAdapter.get() != null) {
mAdapter.get().notifyDataSetChanged();
}
And this worked fine except for a crash once in a while. Basically, the WeakReference was holding on to the object in the check but not when it was being used to update the adapter. So the object was basically garbage collected. Thats a tiny window for a race and yet the GC found its way. So just to demonstrate, how about repeated attempts?
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.gc();
}
}
});
if (mAdapter.get() != null) {
while (true) {
Log.e("GC", "Actual object is [" + mAdapter.get() + "]");
}
}
A thread is launched just to trigger garbage collection once a second and that basically illustrates the problem.
No comments:
Post a Comment