关于Android中SQLite数据库游标的几个问题
为了在我的应用程序中实现数据库访问,我遵循了 Lars Vogel 教程,但是我'我对一些事情感到非常困惑...
每次调用
fetchTodo
时,都会创建并返回一个新游标。将前一个光标留给垃圾收集器。因此,如果我不使用startManagingCursor
甚至不使用CursorLoader
,我是否应该在光标上调用.close()
我已经完成了吗?当然,在fetchTodo
范围之外,例如:光标cursor = mNotesAdapter.fetchTodo(); // 做某事... 光标.close();
我已经完成了这个游标,并且将在下一次获取时创建新的游标,我应该像这样关闭它还是应该将其留给垃圾收集器?虽然我认为我正在谈论两件完全不同的事情......重点是,我是否应该像上面的示例那样关闭它?
- Cursor 也有一个 .deactivate() 方法,文档称它使用更少的资源(比活动光标)。我到底什么时候应该使用这个?例如,在我的应用程序中,我有一个通过
SimpleCursorAdapter
填充的 ListActivity(代码初始化仅调用一次)。正在使用的光标是一个类成员变量,因为我需要它在填充列表的方法之外。当从数据库中删除某些内容时,我需要它来重新查询数据库。但是,在删除记录之前(这是用户操作,可能需要一段时间才能发生),我是否应该同时停用光标?因为当我再次调用.requery()
时它会再次激活。或者SimpleCursorAdapter
将停止工作,因为光标未处于活动状态?
编辑:我刚刚测试了这个,发现在设置光标适配器后我无法调用deactivate()
。如果光标未处于活动状态,列表将为空,因此只要显示 ListActivity,列表就需要保持活动状态。最后,我们应该让 StartManagingCursor 来处理它。或者新的CursorLoader。
- 我知道
startManagingCursor
/stopManagingCursor
已被弃用,但我不以 Honeycomb 为目标(至少暂时如此),并且我不想处理新的CursorLoader。但在上面的教程中,
startManagingCursor
随处使用,但stopManagingCursor
从未被调用过一次。为什么不呢? Android 是否以自己的方式处理这个问题?在什么情况下我应该调用stopManagingCursor
?
To implement database access in my application I followed Lars Vogel tutorial, but I'm very confused about a couple of things...
Every time a call is made to
fetchTodo
a new cursor will be created and returned. Leaving the previous cursor for the garbage collector. So, if I don't usestartManagingCursor
or even theCursorLoader
for that matter, should I call a.close()
on the cursor when I'm done with it ? Outside offetchTodo
scope of course, example:Cursor cursor = mNotesAdapter.fetchTodo();
// do something...
cursor.close();
I'm done with this cursor and new one will be created on the next fetch, should I close it like this then or should I leave it for the garbage collector? Although I think I'm talking about 2 things entirely different... Point being, should I close it like in the example above or not?
Cursor
also has a.deactivate()
method and the documentation says it uses less resources (than active cursors). When exactly should I use this? For instance, in my app, I have aListActivity
which is populated through aSimpleCursorAdapter
(the code initialization for this is only called once). The cursor being used is a class member variable, because I need it outside the method that populates the list. I need it to requery the database when something is deleted from it. But until a record is deleted, which is a user action and may take a while to happen, should I deactivate the cursor in the meantime? Cause it will be active again when I call.requery()
again. Or theSimpleCursorAdapter
is going to stop working because the cursor is not active?
EDIT: I just tested this one and found out that I can't call deactivate()
after setting up the cursor adapter. The list will be empty if the cursor is not active, so it needs to remain active for as long as the ListActivity is displayed. In the end, we should just let StartManagingCursor
handle it then. Or the new CursorLoader
.
- I know that
startManagingCursor
/stopManagingCursor
are deprecated but I'm not targeting Honeycomb (at least for the time being) and I don't want to deal with the newCursorLoader
for now. But in the tutorial above,startManagingCursor
is used everywhere, butstopManagingCursor
is never called once. Why not? Does Android deals with that in it's own way? Any situation I should callstopManagingCursor
?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
编辑:更新答案以反映更新的问题 1:
是的,您绝对应该告诉 Android
startManagingCursor()
、使用LoaderManager
/CursorLoader
或close()
你自己。不这样做会泄漏内存,GC 对此无济于事,因为光标后面有本机资源(例如数据库的文件句柄)。编辑给其他读者:OP找到了答案并将其发布在他的问题中。以下内容仍然成立:
我从未使用过
deactivate()
(没有deactive()
),也许其他人可以解释这一点。如果您想要真正轻松的重新查询/更新,请查看LoaderManager
框架 - 它不仅适用于 Honeycomb:使用 compat 库,您可以使用LoaderManager
(和Fragments
)低至 Android 1.6。它不仅减少了您需要编写的代码,而且将这些事情完全卸载到 Android,比startManagingCursor()
更重要。EDIT2:关于
LoaderManager
的一些注释第一次像那里的大多数教程一样。我还必须进行大量挖掘,迄今为止我发现的最好的一站式服务是 http://mobile.tutsplus.com/tutorials/android/android-sdk_loading-data_cursorloader/ (加上所有 javadocs 和 compat lib 源,您可以find) ---
LoaderManager
的工作方式与(现在也已弃用,由DialogFragment
取代)托管对话框及其onCreateDialog
非常相似,onPrepareDialog
方法,您只需告诉 Android“显示对话框 #123”,然后 Android 使用该 ID 调用您的代码;对于加载器也是如此:“load loader #123”,Android 调用onCreateLoader()
。唯一明显的缺点是最初,
LoaderManager
严重依赖ContentProvider
框架,有些人似乎真的不喜欢这一点。当然,这是额外的学习和代码,但是一旦您为自己的数据拥有了ContentProvider
(即使仅在您的应用程序中私下使用),所有数据到视图的绑定都会变得轻而易举>光标加载器。恕我直言,滚动您自己的“内容提供程序”和实际实现ContentProvider
之间几乎没有什么区别 - 但这只是我备受争议的观点:)一旦您调用
startManagingCursor()
,Cursor
就不再是您的问题。当您的Activity
被破坏(用户离开、方向改变等)时,Android 将负责关闭光标。无需将对startManagingCursor()
的调用与对stopManagingCursor()
的调用相匹配 - 您通常不想承担管理的负担一旦你摆脱它,再次>光标
。Edit: Updated answer to reflect updated question 1:
Yes, you should definitely either tell Android to
startManagingCursor()
, useLoaderManager
/CursorLoader
orclose()
it yourself. Not doing so will leak memory, the GC won't help with that as there's native resources behind theCursor
(e.g. file handles to the database).EDIT to other readers: The OP found an answer and posted it in his question. The following still holds:
I've never used
deactivate()
(there's nodeactive()
), maybe someone else can explain this. If you want really painless requery/updates, do check out theLoaderManager
framework -- it's not only for Honeycomb: using the compat library you can useLoaderManager
(andFragments
) down to Android 1.6. Not only is it less code for you to write, but it completely offloads these things to Android, much more so thanstartManagingCursor()
.EDIT2: Some notes on
LoaderManager
There are
LoaderManager
tutorials on developer.android.com but these are quite... complex and hard to understand the first time like most of the tutorials there. I also had to dig a lot, the best all-in-one stop I found so far is http://mobile.tutsplus.com/tutorials/android/android-sdk_loading-data_cursorloader/ (plus all the javadocs and compat lib source you can find) --- the wayLoaderManager
works is very similar to the (now also deprecated, replaced byDialogFragment
) managed dialogs with theironCreateDialog
,onPrepareDialog
methods where you just tell Android to "show dialog #123" and then Android calls your code with that ID; same for loaders: "load loader #123", Android calls ononCreateLoader()
.The only obvious drawback is initially, that
LoaderManager
relies heavily on theContentProvider
framework and some people seem to really dislike that. Sure, it's additional learning and code, but once you have aContentProvider
for your own data (even if only used privately in your app), all the data-to-view bindng is a breeze withCursorLoader
. IMHO, there's little difference between rolling your own "content provider" and actually implementing theContentProvider
-- but this is just my highly controversial opinion :)Once you call
startManagingCursor()
theCursor
is no longer your problem. Android will take care of closing the Cursor when yourActivity
gets destroyed (user navigates away, orientation change, ...). There's no need to match a call tostartManagingCursor()
with a call tostopManagingCursor()
-- you usually don't want to take on the burden of managing aCursor
again once you've gotten rid of it.