弱参考被无效



我正在使用静态处理程序内的弱参考来避免内存泄漏,但是,有时此参考被无效,我不明白为什么。

静态处理程序是在一个存储库中定义的,该存储库类具有在后台执行操作的方法,接收回调以通知呼叫者:

public class MyRepository {
    public void performOperation(ContentResolver cr, RepositoryCallback callback) {
        MyHandler handler = new MyHandler(cr, callback);
        handler.startQuery(...)
    }
    interface RepositoryCallback {
        void onSuccess(MyModel model);
    }
    // Handler class code here
}

处理程序的代码如下:

private static class MyHandler extends AsyncQueryHandler {
    private final WeakReference<RepositoryCallback> weakCallback;
    public MyHandler(ContentResolver cr, RepositoryCallback callback) {
        super(cr);
        this.weakCallback = new WeakReference<>(callback);
    }
    @Override
    protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
        RepositoryCallback callback = this.weakCallback.get();
        if (callback != null) { // --> Here sometimes it is null
            // Do some stuff with the cursor to create MyModel
            callback.onSuccess(model);
        }
    }
}

由于某种原因,this.weakCallback.get()有时是无效的,我正在尝试理解原因。

活动代码看起来像这样:

public class MyActivity extends AppCompatActivity {
    public void loadModel() {
        showLoadingView();
        myRepository.performOperation(context.getContentResolver(), new RepositoryCallback() {
            @Override
            public void onSuccess(MyModel model) {
                hideLoadingView();
                // Do something with model
            }
        });
    }
}

您可以看到我正在为回调创建一个匿名类,但是没有人持有对它的参考。

这是弱参考被无效的原因吗?

谢谢。

这是与弱参考相关的"经典"错误。

如果可观察到的观察者唯一的参考,并且该引用较弱,则可以清除并收集观察者。

由于您正在使用匿名类,因此可观察的唯一参考将被清除。

作为旁注 - 在我对Android开发的整个经历中,每当我使用弱参考文献看到开发人员时,这总是是一种代码气味。通常,这表明要么开发人员不了解弱参考的工作方式,要么不信任自己的代码。

一个好的经验法则是,您永远不要使用弱参考。

编辑:

我认为Handler通常是反模式。您可以在此Reddit线程中阅读有关此信息的更多信息。那里还有一个线程,我在其中帮助一个开发人员,看看他如何在代码库中摆脱HandlerThread

另一方面,杰克·沃顿(Jake Wharton(不同意我的陈述。

拿起您想要的东西,但是,总的来说,我想说的是静态Handler肯定是反平底入的。

如果您担心AndroidStudion警告,请记住Google负责AsyncTaskLoaders。此警告不仅没有用,而且实际上是不好的。他们应该把它做到you should not use static Hadlers

如果您只需要将工作卸载到BG线程,然后在UI线程上获得回调,那么使用RXJAVA之类的东西会更好。甚至邪恶的AsyncTask

我想您正在使用AsyncQueryHandler来访问ContentProvider。这是一种非常有争议的方法。如果您不需要与其他应用共享数据,则使用为您处理多线程的一些ORM可能会更好。

最新更新