簡體   English   中英

如何實現無盡的CursorAdapter?

[英]How to implement an endless CursorAdapter?

在我們公司,我們正在開發一個顯示時間表的應用程序。 我們願意讓用戶無限期地(幾乎)滾動它。

現在要考慮兩個事實:

  • 加載大的游標可能會對性能產生不良影響(對於舊設備尤其如此)
  • 游標大小限制似乎為 1MB

在當前的實現中,默認情況下我們加載40個項目,然后當用戶滾動到某個閾值以上時,我們通過將限制增加到40 + 20個項目來重復查詢,依此類推。

但是,這種方法似乎很弱,因為它與前面提到的兩個原則相沖突:查詢最終將變得相當大,並且在某個時刻游標可能會達到1MB的內存限制(我們加載了很多字符串)。

現在,我們正在考慮利用MergeCursor並按以下步驟進行:

  1. 第一次加載40個項目的游標
  2. 當用戶滾動到某個級別以外時,我們將加載另一個包含下40個項目的游標,並在游標適配器中設置一個MergeCursor ,它將新游標連接到上一個游標。
  3. 繼續使用此方法,直到最多X步(取決於測試),以避免遇到一些OOM異常。 最后,時間軸光標將是X光標的串聯。

您如何看待這種方法? 有什么弱點(除了開銷,應該很小)?

如果您能指出/描述更好的解決方案?

提前致謝

在評論中,pskink建議使用AbstractWindowedCursor

我對這門課不熟悉,對此進行了一些調查。 事實證明, SQLiteCursor已經SQLiteCursor擴展。 該文檔指出:

光標擁有它使用的光標窗口。 當光標關閉時,其窗口也將關閉。 同樣,當更改光標使用的窗口時,其舊窗口也將關閉。 嚴格的所有權政策可確保不會泄漏游標窗口。

這意味着在任何給定時刻,從數據庫查詢的數據中只有一小部分實際上保留在內存中。 這是SQLiteCursor代碼中有趣的部分:

@Override
public boolean onMove(int oldPosition, int newPosition) {
    // Make sure the row at newPosition is present in the window
    if (mWindow == null || newPosition < mWindow.getStartPosition() ||
            newPosition >= (mWindow.getStartPosition() + mWindow.getNumRows())) {
        fillWindow(newPosition);
    }

    return true;
}

@Override
public int getCount() {
    if (mCount == NO_COUNT) {
        fillWindow(0);
    }
    return mCount;
}

private void fillWindow(int requiredPos) {
    clearOrCreateWindow(getDatabase().getPath());

    try {
        if (mCount == NO_COUNT) {
            int startPos = DatabaseUtils.cursorPickFillWindowStartPosition(requiredPos, 0);
            mCount = mQuery.fillWindow(mWindow, startPos, requiredPos, true);
            mCursorWindowCapacity = mWindow.getNumRows();
            if (Log.isLoggable(TAG, Log.DEBUG)) {
                Log.d(TAG, "received count(*) from native_fill_window: " + mCount);
            }
        } else {
            int startPos = DatabaseUtils.cursorPickFillWindowStartPosition(requiredPos,
                    mCursorWindowCapacity);
            mQuery.fillWindow(mWindow, startPos, requiredPos, false);
        }
    } catch (RuntimeException ex) {
        // Close the cursor window if the query failed and therefore will
        // not produce any results.  This helps to avoid accidentally leaking
        // the cursor window if the client does not correctly handle exceptions
        // and fails to close the cursor.
        closeWindow();
        throw ex;
    }
}

這意味着兩件事:

  1. 加載整個數據集應該是安全的,因為它不會完全保留在內存中。 它的一部分( CursorWindow )隨時都在內存中。 1MB大小限制(可能是)是一個神話,或者它引用了CursorWindow對象,在這種情況下,它是一個安全的大小
  2. 同樣,性能也不是問題,因為游標總是在固定數量的數據上工作。 初始查詢(計算存儲在mCount變量中的數據集的總大小)可能會對感知性能產生一些影響。 我需要進一步測試。

總之,很可能不需要使用MergeCursor技巧或過多地擔心OOM。

我本可以對源代碼進行更好的研究,但是我對網上閱讀的內容感到有些困惑。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM