弱引用无效

时间:2018-02-16 20:37:05

标签: android weak-references android-cursor

我在静态处理程序中使用弱引用来避免内存泄漏,但是,有时这个引用无效,我无法理解为什么。

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

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
            }
        });
    }
}

正如您所看到的,我为回调创建了一个匿名类,但没有人持有对它的引用。

这是弱引用无效的原因吗?

感谢。

1 个答案:

答案 0 :(得分:1)

那是&#34; classic&#34;与弱引用相关的错误。

如果Observable只保留对Observer的引用,并且此引用很弱,则可以将其清除并将Observer置为垃圾回收。

由于您正在使用匿名类,因此Observable将保留对它的唯一引用,因此它将被清除。

作为旁注 - 在我对Android开发的整个体验中,每当我看到devs使用弱引用时,它总是代码味道。通常它表明开发人员不了解弱引用的工作方式,或者他们不相信自己的代码。

一个好的经验法则是你绝不应该使用弱引用。

修改

我认为Handler一般都是反模式。您可以在this Reddit thread中详细了解相关信息。还有一个主题,我帮助一个开发人员看看他如何摆脱代码库中的HandlerThread

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

从那里得到你想要的东西,但是,一般来说,我会说静态Handler肯定是反模式。

如果您担心AndroidStudion警告,请记住Google负责AsyncTaskLoaders。这个警告不仅没用,而且实际上很糟糕。他们应该you should not use static Hadlers

如果你需要的是将工作卸载到BG线程然后在UI线程上获得回调那么你会更喜欢像RxJava这样的东西。甚至是邪恶的AsyncTask

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