2013년 8월 6일 화요일

Android SQLite Cursor 관리, close 시점

이전 블로그에서 이전 함 (원본 글 2013/08/06 작성)

Android SQLite를 사용하다 Cursor의 close 시점이 궁금해서 찾아봄.

일단 Query 이후 전달되는 Cursor는 데이터를 다른 data structure에 저장을 하고 바로 close하는 게 바람직해 보이나
과도한 query로 인한 activity 사용성 문제와 activity의 state 변경으로 인한 cursor 처리를 위해 Loader를 구현해서 적절히 처리하는게 맞겠음.
만약 data를 소비하는 측이 다른 process에 존재한다면 ContentProvider를 구현해서 처리하는 게 맞음.

[startManagingCursor(), CursorLoader]

Cursor를 자동으로 관리해 주는 startManagingCursor() 는 deprecate 되었고
CursorLoader와 LoaderManager를 사용하라고 권고 하고 있음.


 public void startManagingCursor (Cursor c)
Added in API level 1

This method was deprecated in API level 11.
Use the new CursorLoader class with LoaderManager instead; this is also available on older platforms through the Android compatibility package.
This method allows the activity to take care of managing the given Cursor's lifecycle for you based on the activity's lifecycle. That is, when the activity is stopped it will automatically call deactivate() on the given Cursor, and when it is later restarted it will call requery() for you. When the activity is destroyed, all managed Cursors will be closed automatically. If you are targeting HONEYCOMB or later, consider instead using LoaderManager instead, available via getLoaderManager().
Warning: Do not call close() on cursor obtained from managedQuery(Uri, String[], String, String[], String), because the activity will do that for you at the appropriate time. However, if you call stopManagingCursor(Cursor) on a cursor from a managed query, the system will not automatically close the cursor and, in that case, you must call close().

= CursorLoader
public class

CursorLoader
 

extends AsyncTaskLoader<D> 
   ↳

   ↳


   ↳
android.content.CursorLoader

Class Overview


A loader that queries the ContentResolver and returns a Cursor. This class implements the Loader protocol in a standard way for querying cursors, building on AsyncTaskLoader to perform the cursor query on a background thread so that it does not block the application's UI. 


= LoaderManager
 : 링크에 simple cursor example 포함.
 public abstract class
LoaderManager
extends
 Object 
   ↳
android.app.LoaderManager

Class Overview


Interface associated with an Activity or Fragment for managing one or more Loader instances associated with it. This helps an application manage longer-running operations in conjunction with the Activity or Fragment lifecycle; the most common use of this is with a CursorLoader, however applications are free to write their own loaders for loading other types of data. While the LoaderManager API was introduced in HONEYCOMB, a version of the API at is also available for use on older platforms throughFragmentActivity. See the blog post Fragments For All for more details.


startManagingCursor()의 단점과 Loader, LoaderManager에 대한 설명은 다음 블로그에서 잘 정리하고 있음.


간단 요약
 - managedQuery() (startManagingCursor())은 사용자가 신경 쓸 필요 없이 activity에서 관리를 하게 하지만
    main UI thread 상에서 query를 실행하여 처리하다 보니 반응성 측면에서 문제가 될 수 있고
    activity의 상태 변경으로 인한 변화에 따라 cursor()를 적절히 처리하지 못함.
 - Loader를 통해서 application은 data loading을 별도의 thread에서 asynchronous 하게 처리할 수 있고 loading result 및 update 관련된 사항을 callback을 통해서 처리할 수 있음. 또한 Loader는 명시적인 states(started, stopped, reset 등)에 대해서 대응 할 수 있음.
* 자세한 내용은 읽어 보는 것을 추천...


[Cursor 관련 QnA]
: DB close는 provider가 처리, cursor은 사용이 끝난 시점에 close

: 항상은 아니지만 코딩상 실수로 이런 경우도 있을 것 같음. :)
 "close() was never explicitly called on database xxx" 라는 메세지가 나오는 경우 한번에? db를 여러번 열지 않았는지 확인 필요
 I resolved the exception. I was calling
db = eventsData.getReadableDatabase();
twice thats why the exception is thrown


[ContentProvider 구현]

나중에 자세히 봐야 할듯...

 : ContentProvider 설명
 : ContentProvider 만들기 


 : ContentProvider 관련 개념 설명 및 practice

댓글 없음:

댓글 쓰기