我在Android应用中有一些固有的异步代码。我正在使用RxJava2。班级Thing
不受我的控制(但ThingFactory
是)。在一种方法(createThing()
)中,实例化新的Thing
。 Thing
的构造函数可以完成一些工作,并在完成后通过回调onThingInitialized()
通知我们。在调用回调时,我们应该保证thing
存在。在回调中,我计划在单独的线程上进行工作(在这种情况下,使用RxJava2,但我认为它不重要)。这段代码中没有任何地方可以调用类似thing = null
的内容。所以,一旦设定,它就会永远定下来。
我向它投了volatile
因为实例 得到了更新,但从未被取消。如果我误用了它,请随意指责我。
public class UsesAThing implements ThingCallbacks {
private volatile Thing thing; // I feel like I don't understand 'volatile'
// I call this method
public void createThing() {
thing = thingFactory.newThing(param1, param2);
}
// Thing's constructor does some work and notifies us when it's done
@Override
public void onThingInitialized() {
// Called on main thread, but I want to do some IO work, so:
Schedulers.io().scheduleDirect(() -> {
thing.doStuff(); // NPE!
});
}
}
那里的NPE怎么样?
修改
Thing
的构造函数以异步方式工作。正如我所说,这是在Android环境中,所以它实际做的工作是绑定到Service
。当绑定Service
时,其ServiceConnection::onServiceConnected()
回调会被点击,其实际上会触发AsyncTask
onPostExecute()
,在其onThingInitialized()
回调中,会调用Flowable.just(1)
.subscribeOn(Schedulers.io())
.subscribe(i -> createThing());
回调
编辑2:
我还应该注意到这个NPE不会一直发生。我已经完成了数百次这段代码,而且我只看过它一次。
编辑3:示例呼叫代码
我没有提供示例代码,因为它的内容与人们想象的一样简单,但这就是它的样子:
{{1}}
答案 0 :(得分:4)
如果我理解你的评论,则在工作线程中调用createThing()
。在Thing
构造函数启动导致回调的事件序列之后,线程调度程序可能会暂停此工作线程,但之前 newThing()
返回并分配thing
。如果整个回调序列在调用createThing()
的线程再次运行之前运行,您将看到此NPE。
要测试此理论,首先要创建一个重复运行的测试来重现该问题。然后更改它,以便在主线程中调用createThing()
并查看问题是否消失。这将是一种解决方法,而不是修复。但真正的解决方法是不要在Thing
的构造函数中进行操作,而您所说的是您无法控制的。