Как сохранить флажок в адаптере курсора при переключении курсора?

У меня есть ListView, который ям с информацией из медиа магазина. У меня есть флажки в каждой строке, чтобы позволить пользователю выбрать несколько строк. В меню параметров есть пункты меню, которые запускают новые запросы к хранилищу мультимедиа, и с помощью CursorLoader я меняю курсор в адаптере, когда курсор загружен.

В моем адаптере яm используя ArrayList, который отслеживает отмеченные элементы и отслеживает все элементы в списке. Список, который отслеживает все элементы, должен быть повторно отсортирован / перестроен при изменении курсора, чтобы метод getView () мог проверить правильные флажки.Мне не удалось найти способ обновить мой список, чтобы он соответствовал порядку элементов в курсоре.

мы попытались переопределить swapCursor, changeCursor и notifyDataSetChanged. При каждой попытке вызвать метод super до и после я прибегаю к списку, как это делается в конструкторе адаптера.

Мы рассмотрели эти вопросы здесь, на SO, которые, кажется, связаны, но яне удалось создать решение:Проблемы с адаптером Listview

Пользовательские состояния CursorAdapter и CheckBox

Курсор неправильно связывает текст с помощью специального адаптера

Это мой код активности:

/**
 * This activity displays a list of the available media on the device. It allows
 * selecting several items from the list and by selecting the "done" icon in the
 * options menu, the activity will return the results to the calling activity.
 * 
 * The list can be sorted via the options menu. The available sorting columns
 * are artist, title and album. By default the list is sorted by artist name.
 * 
 * The selection from the database consists of the _ID, ARTIST, ALBUM, TITLE,
 * DATA, DISPLAY_NAME and DURATION columns and is also limited to contain only
 * files that are markes as IS_MUSIC.
 * 
 * @author Daniel Kvist
 * 
 */
public class MediaSelectorActivity extends Activity implements LoaderCallbacks
{
    private static final int LOADER_ID_ARTIST = 2;
    private static final int LOADER_ID_ALBUM = 4;
    private static final int LOADER_ID_TITLE = 8;

    public static final String EXTRA_SELECTED_ITEMS = "selected_media";
    public static final int REQUEST_MEDIA = 0;

    private MediaSelectorAdapter adapter;
    private ListView listView;
    private LoaderManager loaderManager;

    private String selection = MediaStore.Audio.Media.IS_MUSIC + " != 0";
    private String[] projection = { MediaStore.Audio.Media._ID, MediaStore.Audio.Media.ARTIST, MediaStore.Audio.Media.ALBUM,
            MediaStore.Audio.Media.TITLE, MediaStore.Audio.Media.DATA, MediaStore.Audio.Media.DISPLAY_NAME, MediaStore.Audio.Media.DURATION };
    private ArrayList selectedItems;

    /**
     * The onCreate method loads the xml layout which contains the listview. It
     * also gets the loader manager and initiates a first load of available
     * media and sorts it by artist name.
     */
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_media_selector);
        loaderManager = getLoaderManager();
        loaderManager.initLoader(LOADER_ID_ARTIST, null, this);
        listView = (ListView) findViewById(R.id.list);
        selectedItems = new ArrayList();
    }

    /**
     * This method simply inflates the xml file which contains the menu options.
     */
    @Override
    public boolean onCreateOptionsMenu(Menu menu)
    {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.media_selector_menu, menu);
        return true;
    }

    /**
     * This is called when an option item has been selected. Depending on the
     * user selection either the selected tracks are passed back to the calling
     * activity or a new query is made to the media store to sort on either
     * artist, album or title.
     */
    @Override
    public boolean onOptionsItemSelected(MenuItem item)
    {
        selectedItems = adapter.getSelectedItems();
        switch (item.getItemId())
        {
            case R.id.done:
                Intent intent = new Intent();
                intent.putParcelableArrayListExtra(EXTRA_SELECTED_ITEMS, selectedItems);
                setResult(RESULT_OK, intent);
                finish();
                return true;
            case R.id.artist:
                loaderManager.initLoader(LOADER_ID_ARTIST, null, this);
                return true;
            case R.id.album:
                loaderManager.initLoader(LOADER_ID_ALBUM, null, this);
                return true;
            case R.id.track:
                loaderManager.initLoader(LOADER_ID_TITLE, null, this);
                return true;
            default:
                return super.onOptionsItemSelected(item);
        }
    }

    /**
     * Called when the cursor loader is first created. It decides which URI to
     * query and which sorting order should be returned. The query also contains
     * information about which columns we are interested in which selection we
     * want.
     */
    public Loader onCreateLoader(int i, Bundle bundle)
    {
        CursorLoader cursorLoader = null;
        switch (i)
        {
            case LOADER_ID_ARTIST:
                cursorLoader = new CursorLoader(this, MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, projection, selection, null,
                        MediaStore.Audio.Media.ARTIST);
                break;
            case LOADER_ID_ALBUM:
                cursorLoader = new CursorLoader(this, MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, projection, selection, null,
                        MediaStore.Audio.Media.ALBUM);
                break;
            case LOADER_ID_TITLE:
                cursorLoader = new CursorLoader(this, MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, projection, selection, null,
                        MediaStore.Audio.Media.TITLE);
                break;
        }
        return cursorLoader;
    }

    /**
     * When the load has finished we create a new adapter of the cursor we
     * receive from the media store content provider. The adapter is then set to
     * the listvew. The adapter uses ARIST, ALBUM and TITLE to be displayed to the
     * user.
     */
    public void onLoadFinished(Loader cursorLoader, Cursor cursor)
    {
        if(adapter == null) 
        {
            adapter = new MediaSelectorAdapter(getApplicationContext(), R.layout.activity_media_selector, cursor, new String[] {
                MediaStore.Audio.Media.ARTIST, MediaStore.Audio.Media.ALBUM, MediaStore.Audio.Media.TITLE }, new int[] { R.id.text_1,
                R.id.text_2, R.id.text_3 }, Adapter.NO_SELECTION, selectedItems);
            listView.setAdapter(adapter);
        }
        else
        {
            adapter.swapCursor(cursor);
        }
    }

    /**
     * WHen the loader is reset we just pass in null as the cursor to the
     * adapter.
     */
    public void onLoaderReset(Loader cursorLoader)
    {
        adapter.swapCursor(null);
    }
}

Это мой код адаптера:

/**
 * This adapter is used by the media selector activity to display the list rows.
 * It is needed to keep track of which checkboxes have been checked and which
 * has not. The system is aggressive in trying to re-use views that are not
 * currently being displayed which leads to strange behaviour with the
 * checkboxes where they keep their "checked" state although they have not been
 * checked for a specific item.
 * 
 * The class is extending SimpleCursorAdapter for easy use of the cursor that
 * can be obtained from a database or content resolver.
 * 
 * @author Daniel Kvist
 * 
 */
public class MediaSelectorAdapter extends SimpleCursorAdapter
{
    private Context context;
    private ArrayList listItems;
    private ArrayList selectedItems;

    /**
     * The constructor takes the same parameters as an ordinary simple cursor
     * adapter and passes them up to the super class. It then loops through the
     * cursor and initiates an array which contains references to all the list
     * rows and if they have been checked or not.
     * 
     * @param context
     *            the context which to be displayed in
     * @param layout
     *            the layout file for the list view
     * @param cursor
     *            the cursor that points to the data
     * @param from
     *            the fields that are to be displayed
     * @param to
     *            the views to display the fields in
     * @param flags
     *            any special flags that can be used to determine the behaviour
     *            of the super class adapter
     * @param selectedItems2 
     */
    public MediaSelectorAdapter(Context context, int layout, Cursor cursor, String[] from, int[] to, int flags, ArrayList selectedItems)
    {
        super(context, layout, cursor, from, to, flags);
        this.context = context;
        this.selectedItems = selectedItems;
        listItems = new ArrayList();

        while (cursor.moveToNext())
        {
            Track track = new Track(cursor.getString(0), cursor.getString(1), cursor.getString(2), cursor.getString(3),
                    cursor.getString(4), cursor.getString(5), cursor.getString(6));
            listItems.add(track);
        }
    }

    /**
     * Overridden method that getView uses to keep track of how many items the
     * adapter has.
     */
    @Override
    public int getCount()
    {
        return listItems.size();
    }

    /**
     * Called by the system to get a specific item.
     */
    @Override
    public Track getItem(int position)
    {
        return listItems.get(position);
    }

    /**
     * Called by the system to get the id/position for an item.
     */
    @Override
    public long getItemId(int position)
    {
        return position;
    }

    /**
     * Reuses old views if they have not already been reset and inflates new
     * views for the rows in the list that needs a new one. It the adds a
     * listener to each checkbox that is used to store information about which
     * checkboxes have been checked or not. Finally we set the checked status of
     * the checkbox and let the super class do it's thing.
     */
    @Override
    public View getView(final int position, View convertView, ViewGroup parent)
    {
        if (convertView == null)
        {
            LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = inflater.inflate(R.layout.media_selector_item_layout, null);
        }
        final CheckBox checkBox = (CheckBox) convertView.findViewById(R.id.checkbox);
        checkBox.setOnClickListener(new OnClickListener()
        {
            public void onClick(View v)
            {
                CheckBox cb = (CheckBox) v.findViewById(R.id.checkbox);
                if (cb.isChecked())
                {
                    selectedItems.add(listItems.get(position));
                }
                else if (!cb.isChecked())
                {
                    selectedItems.remove(listItems.get(position));
                }
            }
        });
        // If the selected items contains the current item, set the checkbox to be checked
        checkBox.setChecked(selectedItems.contains(listItems.get(position)));

        return super.getView(position, convertView, parent);
    }

    /**
     * Returns an array list with all the selected items as Track objects.
     * 
     * @return the selected items
     */
    public ArrayList getSelectedItems()
    {
        return selectedItems;
    }
}

Любые советы, подсказки или другие материалы очень ценятся.

Спасибо

Ответы на вопрос(1)

Ваш ответ на вопрос