ListViewでCursorAdapterを使ってリストを表示していたらlogcatに、
W/CursorWindow(1111): Window is full: requested allocation 111 bytes, free space 11 bytes, window size 2097152 bytes
みたいなログが出てて、アプリの挙動がおかしくなることがあった。
原因は、ログのメッセージの通り、windows用のメモリが足りませんってことなんだけど、どうにかしてサイズを拡張したいので方法を調べてみた。
まずは、CursorWindow.javaのソースを眺めてみると、window sizeはsCursorWindowSizeで持っていて、
com.android.internal.R.integer.config_cursorWindowSize
から取得していた。しかし、この値はシステムで固定、しかも、privateだし、finalだし、外部から変更するためのメソッドが用意されていない。
ということで、リフレクションを使ってこの値を書き換えてみた。以下が、そのコードです。
static private void setCursorWindowSize(int size){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
try {
final Class cls = Class.forName("android.database.CursorWindow");
final Field fld = cls.getDeclaredField("sCursorWindowSize");
fld.setAccessible(true);
int before = fld.getInt(null); // default=2048*1024
fld.setInt(null, size * 1024); // extend to
int after = fld.getInt(null);
Log.d(TAG, "sCursorWindowSize:" + before + "/" + after);
} catch (Exception e) {
Log.e(TAG, e);
}
}
}
自分は、ApplicationクラスのonCreate内で、
setCursorWindowSize(8192);
みたいな感じで呼び出しました。
これで、上記のログは出なくなりました。試しに、試しにものすごい小さい値に書き換えてみたら、ログ出まくりだったので、一応指定したサイズで機能しているようです。
ちなみに、window sizeが有効なのはICS以降のようです。
(Honeycombのソースは確認できなかったので、もしかしたらHoneycomb以降かもしれませんが。Ginger Breadのソースには無かったです)
今回は、アプリ側での対応方法でしたが、もし、システム全体で拡張するならXposed module作ってしまうと手っ取り早いかもしれない。
同じような現象にお悩みの方がいたら、解決の参考になれば幸いです。