Cursor trong lập trình Android
Bài đăng này đã không được cập nhật trong 7 năm
Nếu bạn đã và đang lập trình ứng dụng Android, bạn chắc chắn đã sử dụng tính năng của SQLite để lưu trữ và truy vấn dữ liệu tại local.
Dưới đây là một số lựa chọn khi mà bạn sử dụng Cursor.
CursorJoiner
Nếu bạn muốn sử dụng dữ liệu từ 2 hoặc nhiều bảng dữ liệu trong database, cách nhanh nhất để làm việc đó là sử dụng query của SQL để joins các bảng lại. Tuy nhiên, thỉnh thoảng bạn đã có sẵn dữ liệu từ các queries khác nhau ví dụ như một CursorLoader dựa trên một ContentProvider, và bạn muốn sử dụng lại chúng mà không cần tạo một query mới tức là không cần sửa đổi lại ContentProvider.
Trong tình huống đó thì CursorJoiner sẽ hữu ích với bạn. Không giống những lựa chọn khác trong bài viết này, CursorJoiner không tạo ra một cursor mới, thay vào đó nó cung cấp một cơ chế để duyệt qua các cursor đã joined (Iterable).
Một điểm thú vị nữa mà tôi thấy khi sử dụng CursorJoiner đó là xác định cái gì đã bị thay đổi khi LoaderManager.LoaderCallbacks<Cursor>
được update trong onLoadFinished()
. Bạn có thể sử dụng CursorJoiner để join cursor cũ và cursor mới dựa trên primary key của chúng, và sau đó so sánh. Khi lặp qua CursorJoiner, bạn nhận được một enum CursorJoiner.Result xác định rằng liệu row hiện tại có trong cursor cũ hay cursor mới hay cả 2.
Dưới đây là sample code xác định dữ liệu đã được add hoặc delete khỏi ContentProvider
@Override
public void onLoadFinished(Loader<cursor> loader, Cursor updatedCursor) {
if(adapter.getCursor() != null) {
Cursor oldCursor = adapter.getCursor();
CursorJoiner joiner =
new CursorJoiner(oldCursor,
new String[] {Thing.ID},
updatedCursor,
new String[] {Thing.ID}
);
for(CursorJoiner.Result joinerResult : joiner) {
switch (joinerResult) {
case RIGHT:
int thingId = updatedCursor.getInt(
updatedCursor.getColumnIndex(Thing.ID)
);
String thingName = updatedCursor.getString(
updatedCursor.getColumnIndex(Thing.NAME)
);
Log.d(TAG, "new Thing added - id: " + thingId
+ ", name: " + thingName);
break;
case LEFT:
int thingId = updatedCursor.getInt(
oldCursor.getColumnIndex(Thing.ID)
);
String thingName = updatedCursor.getString(
oldCursor.getColumnIndex(Thing.NAME)
);
Log.d(TAG, "Thing deleted - id: "
+ thingId + ", name: " + thingName);
break;
case BOTH:
int thingId = updatedCursor.getInt(
oldCursor.getColumnIndex(Thing.ID)
);
String thingName = updatedCursor.getString(
oldCursor.getColumnIndex(Thing.NAME)
);
Log.d(TAG, "Thing unchanged - id: "
+ thingId + ", name: " + thingName);
break;
}
}
updatedCursor.moveToFirst();
adapter.swapCursor(updatedCursor);
}
MatrixCursor
MatrixCursor hữu dụng khi mà bạn có tập hợp dữ liệu không nằm trong database mà bạn muốn tạo một cursor cho nó. Đơn giản chỉ cần xây dựng nó với một mảng các Column Names và một số capacity tùy chọn. Sau đó bạn có thể thêm từng row vào.
String[] columnNames = {"Column1", "Column2"};
MatrixCursor matrixCursor = new MatrixCursor(columnNames);
matrixCursor.addRow(new String[]{"value1", "value2"});
adapter.swapCursor(matrixCursor);
MergeCursor
MergeCursor cho phép bạn gộp 2 hoặc nhiều cursors thành một cursor duy nhất. Bạn có thể làm điều tương tự như câu query UNION trong SQL. Tuy nhiên, MergeCursor cho phép bạn có các colums khác nhau trong các cursor và vẫn merge cuhngs. MergeCursor hữu dụng trong trường hợp bạn muốn một list có các items không đồng nhất.
CursorWrapper
Cuối cùng, CursorWrapper là một Wrapper cho Cursor nó sẽ chuyển toàn bộ các tương tác đến đối tương cursor thật. Ứng dụng chính của class này là extend một Cursor trong khi chỉ overriding một số method của nó. Một ví dụ cho CursorWrapper là khi bạn đã có một cursor nhưng chỉ muốn đưa ra một vài rows đầu tiên, override method getCount() và trả ra một số nhỏ hơn so với count của cursor thật. Và khi sử dụng bạn chỉ có thể thấy được kết quả đã giới hạn. Tương đương khi mà bạn sử dụng câu query LIMIT trong SQL.
Kết
Bài này chỉ mang tính chất giới thiệu để tìm hiểu sâu hơn nữa bạn nên đọc document của từng loại cursor để hiểu cơ chế làm việc của nó.
All rights reserved