3

Stackoverflow コミュニティの皆様、こんにちは。

現在、Android ListViewsections の機能をいじっていますが、Android 4.4 API に問題があるようです。SQLite データベースから項目を設定する CursorAdapter があります。アダプターが作成されると、項目がセクション化されます。ユーザーは、ListView アイテムの並べ替えを AZ から ZA に変更することができます。彼がこれを行うと、新しい CursorAdapter が作成されて設定され、もちろん、彼の項目のインデックスが再度作成されます。次のコードを使用して新しいアダプターを設定しました。これにより、Listview が強制的に getSections() を呼び出し、高速スクロール時にセクションが更新されたようです。

//A new instance of adapter is created here with the new cursor, see code at bottom

listView.setFastScrollEnabled(false);
listView.setAdapter(adapter);
listView.setFastScrollEnabled(true);

上記のコードは Android 4.3 までは問題なく動作しましたが、4.4 で動作しなくなりました。4.4 では、ListView は高速スクロール中に古いセクションを表示します。そのため、ユーザーが並べ替えを ZA に変更した場合でも、ListView は高速スクロール時にこのセクション オーバーレイを AZ の順序で表示します。私が何を意味するか知っていることを願っています。

これは既知のバグで、回避策はありますか?

どうもありがとうございました。

編集:これは私が使用するアダプターのコードです。基本的に2つのカーソルに基づいています。最初のものは表示するデータを保持し、2 つ目はインデックスを保持します。

public class SectionCheckableCursorAdapter extends CursorAdapter implements SectionIndexer {

private LayoutInflater mInflater;
private Map<Integer, Object> mSectionIndices = new TreeMap<Integer, Object>();
private Object[] mSections;
private Integer[] mSectionPositions;

public SectionCheckableCursorAdapter(Context context, Cursor c, Cursor indexCursor) {
    super(context, c, false);
    mInflater = LayoutInflater.from(context);   
    buildIndex(indexCursor);
}

private void buildIndex(Cursor indexCursor) {
    //init
    mSectionIndices = new TreeMap<Integer, Object>();
    List<Integer> sectionPositionsList = new ArrayList<Integer>();

    //get column indices from cursor
    int indexFirstLetter = indexCursor.getColumnIndex("firstLetter");
    int indexCount = indexCursor.getColumnIndex("count");

    //build sections
    int currentCount = 0;
    while (indexCursor.moveToNext()) {
        final int count = indexCursor.getInt(indexCount);
        String firstChar = indexCursor.getString(indexFirstLetter);

        if (firstChar == null || firstChar.isEmpty()) {
            firstChar = " ";
        }

        if (StringUtils.isNumber(firstChar)) {
            firstChar = "#";
        }

        if (!mSectionIndices.containsValue(firstChar)) {
            mSectionIndices.put(currentCount, firstChar);
            sectionPositionsList.add(currentCount);
        }

        currentCount += count;
    }

    mSectionPositions = new Integer[sectionPositionsList.size()];
    sectionPositionsList.toArray(mSectionPositions);

    Collection<Object> sections_collection = mSectionIndices.values();
    mSections = new Object[sections_collection.size()];
    sections_collection.toArray(mSections);
}

@Override
public int getPositionForSection(int section) {
    if (section > mSectionPositions.length - 1) {
        if (getCursor() != null)
            return getCursor().getCount() - 1;
        return 0;
    } else {
        return mSectionPositions[section];
    }
}

@Override
public int getSectionForPosition(int position) {
    for (int i = 0; i < mSectionPositions.length-1; i++) {
        if (position >= mSectionPositions[i] && position < mSectionPositions[i+1]) {
            return i;
        }
    }
    return mSectionPositions.length-1;
}

@Override
public Object[] getSections() {
    return mSections;
}

}

これは、上部のコードのようにアダプタが設定される前に、カーソルとアダプタが作成される方法です。

//Query for "real" data and the indices. The indices are created with a query because
//this is much faster than iterating through all entries in the "data" cursor
mCursor = mDatabase.rawQuery(query, null);
mIndexCursor = mDatabase.rawQuery(indexQuery, null);
if (mCursor != null) {
    adapter = new SectionCheckableCursorAdapter(getSherlockActivity(), mCursor, mIndexCursor);
}
4

1 に答える 1

1

これまでに見つけた唯一の「回避策」は、古い ListView を完全に削除し、新しい ListView をレイアウトに追加することです。したがって、最初の投稿のようにアダプターを設定する前に、ユーザーが KitKat を実行しているかどうかを確認してから、新しい ListView をレイアウトに追加できます。

listView.setFastScrollEnabled(false);
if (android.os.Build.VERSION.SDK_INT == android.os.Build.VERSION_CODES.KITKAT) {
    swapListView();
}
listView.setAdapter(adapter);
listView.setFastScrollEnabled(true);

swapListView() メソッドは単純です。

private void swapListView() {
    //save layout params
    ViewGroup.LayoutParams listViewParams = null;
    if (listView != null) {
        listViewParams = listView.getLayoutParams();
    } else {
        listViewParams = new ViewGroup.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
    }

    //frame is a FrameLayout around the ListView
    frame.removeView(listView);

    listView = new ListView(this);
    listView.setLayoutParams(listViewParams);
    //other ListView initialization code like divider settings

    frame.addView(listView);
}

これにより、アダプターの設定後にインデックス/セクションが強制的に更新されますが、私には汚いコードのように見え、良い解決策とは思えません。

于 2013-12-26T17:20:48.723 に答える