Android - 在Adapter中取消注册定义的ContentObserver

3

我有一系列要上传的文件,这些文件存储为内容提供者中的条目。每个条目还包含已上传百分比。

一个活动显示上传列表,每个文件都是一个带有进度条的项目,用于显示上传进度。

我通过ContentObserver更新进度条。在CursorAdaptor中,我为每个条目定义了ContentObserver,并将其保存为相应视图的标签。

现在我的问题是我不知道何时取消注册这样的ContentObservers。唯一找到的方法是在包含活动的onDestroy()中取消注册:

    for (int i = 0; i < mListView.getChildCount(); i++) {
        final View v = mListView.getChildAt(i);
        final ContentObserver obs = (ContentObserver) v.getTag();
        if (obs != null) {
            getContentResolver().unregisterContentObserver(obs);
        }
    }

这真的非常糟糕。它在Adapter和父Activity之间引入了依赖关系。另一方面,未注销的ContentObservers可能会防止Activity被销毁,从而引入内存泄漏。

您看有更好的方法吗?


2
你应该将取消注册循环至少转移到onPause()(因此,在onResume()上注册),因为您不能总是预测onDestroy()将何时被调用或系统是否会在不调用它的情况下杀死您的应用程序。 - ozbek
1
@shoe_rat,这不是真的,它取决于您在哪个生命周期方法中注册ContentObserver。如果您在onCreate中进行了注册调用,而在onPause中取消注册,那么在多次返回该Activity时它将失败(或者您需要进行其他检查)。此外,关于应用程序被系统杀死的情况,您所说的并不正确,因为如果系统杀死您,已注册的ContentObserver将被系统注销(当然,否则您将一直在被杀死时占用资源)。 - Pepster
1
不要将状态与视图绑定在一起,视图会来去。注册一个观察者,接收一个包含所有数据的对象,将该数据更新到适配器中,然后在适配器上调用 notifyDataSetInvalidated() - S.D.
S.D. 是正确的,只使用一个 ContentObserver,并且不要将视图与状态信息绑定。 - Mikel
1个回答

0
如果您有内容提供者,可以使用CursorLoader。

https://developer.android.com/training/load-data-background/setup-loader.html

public class PhotoThumbnailFragment extends FragmentActivity implements
        LoaderManager.LoaderCallbacks<Cursor> {
...
}

/*
* Callback that's invoked when the system has initialized the Loader and
* is ready to start the query. This usually happens when initLoader() is
* called. The loaderID argument contains the ID value passed to the
* initLoader() call.
*/
@Override
public Loader<Cursor> onCreateLoader(int loaderID, Bundle bundle)
{
    /*
     * Takes action based on the ID of the Loader that's being created
     */
    switch (loaderID) {
        case URL_LOADER:
            // Returns a new CursorLoader
            return new CursorLoader(
                        getActivity(),   // Parent activity context
                        mDataUrl,        // Table to query
                        mProjection,     // Projection to return
                        null,            // No selection clause
                        null,            // No selection arguments
                        null             // Default sort order
        );
        default:
            // An invalid id was passed in
            return null;
    }
}

你只需要定义一个游标加载器并实现回调函数,就不需要使用内容观察器了。这样效果更好。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接