ExpandableListView с использованием SimpleCursorTreeAdapter прокручивается вверх при обновлении

Я создал ExpandableListAdapter, расширив SimpleCursorTreeAdapter. Курсоры управляются загрузчиками. Когда список отображается для пользователя, я запускаю фоновый сервис для получения последних данных с сервера. Если сервер возвращает новые данные, я добавляю их в БД и уведомляю дочерние курсоры. Курсоры запрашиваются, а список обновляется. На этом этапе, если пользователь прокрутил список вниз, список прокручивается вверх. Это очень раздражает. Я прошел весь API для *TreeAdapters и не вижу никакого способа, чтобы предотвратить это. Это должно быть очень распространенной проблемой. Как я могу это исправить?

1 ответ

Попробуйте этот код:

public class GroupsAdapter extends SimpleCursorTreeAdapter {

    private final String TAG = getClass().getSimpleName().toString();

    private final FragmentActivity mActivity;
    private final ContactsFragment mFragment;

    private static final String[] CONTACTS_PROJECTION = new String[] {
                    ContactsContract.Users._ID, ContactsContract.Users.USER_ID,
                    ContactsContract.Users.NAME, ContactsContract.Users.STATUS_TYPE,
                    ContactsContract.Users.STATUS_MESSAGE,
                    ContactsContract.Users.HAS_ALERT };

    // Note that the constructor does not take a Cursor. This is done to avoid
    // querying the database on the main thread.
    public GroupsAdapter(final Context context, final ContactsFragment glf,
                    final int groupLayout, final int childLayout,
                    final String[] groupFrom, final int[] groupTo,
                    final String[] childrenFrom, final int[] childrenTo) {

            super(context, null, groupLayout, groupFrom, groupTo, childLayout,
                            childrenFrom, childrenTo);
            mActivity = (FragmentActivity) context;
            mFragment = glf;
    }

    @Override
    protected Cursor getChildrenCursor(final Cursor groupCursor) {
            final String id = groupCursor.getString(groupCursor
                            .getColumnIndex(ContactsContract.Groups.GROUP_ID));
            final CursorLoader cursorLoader = new CursorLoader(mActivity,
                            ContactsContract.Users.CONTENT_URI, CONTACTS_PROJECTION, "("
                                            + ContactsContract.UserGroupColumns.GROUP_ID + "=?)",
                            new String[] { id }, null);

            Cursor childCursor = null;

            try {
                    childCursor = cursorLoader.loadInBackground();
                    childCursor.moveToFirst();
            } catch (final Exception e) {
                    Log.e(TAG, e.getMessage());
            }

            return childCursor;

    }

}

и фрагмент:

public class ContactsFragment extends Fragment implements
            LoaderCallbacks<Cursor> {

    private static final String[] GROUPS_PROJECTION = new String[] {
                    ContactsContract.Groups._ID, ContactsContract.Groups.NAME,
                    ContactsContract.Groups.GROUP_ID,
                    ContactsContract.Groups.USERS_COUNT };
    private static final String TAG = "ContactsFragment";

    ExpandableListView listView;
    GroupsAdapter mAdapter;

    public ContactsFragment() {
            // Required empty public constructor
    }

    @Override
    public void onCreate(final Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setHasOptionsMenu(true);
    }

    @Override
    public View onCreateView(final LayoutInflater inflater,
                    final ViewGroup container, final Bundle savedInstanceState) {
            // Inflate the layout for this fragment
            return inflater.inflate(R.layout.fragment_contacts, container, false);
    }

    @Override
    public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) {
            inflater.inflate(R.menu.contacts_menu, menu);
            super.onCreateOptionsMenu(menu, inflater);
    }

    @Override
    public void onActivityCreated(final Bundle savedInstanceState) {

            super.onActivityCreated(savedInstanceState);

            listView = (ExpandableListView) getView().findViewById(
                            android.R.id.list);
            // listView.setEmptyView();
            // Set up our adapter
            mAdapter = new GroupsAdapter(getActivity(), R.layout.group,
                            R.layout.user, new String[] { ContactsContract.Groups.NAME,
                                            ContactsContract.Groups.USERS_COUNT }, // Name
                            // for group layouts
                            new int[] { R.id.group, R.id.count }, new String[] {
                                            ContactsContract.Users.NAME,
                                            ContactsContract.Users.STATUS_MESSAGE }, // Name
                            // for child layouts
                            new int[] { R.id.user_name, R.id.status_message });

            listView.setAdapter(mAdapter);

            // Prepare the loader. Either re-connect with an existing one,
            // or start a new one.
            final Loader<Cursor> loader = getLoaderManager().getLoader(-1);
            if (loader != null && !loader.isReset()) {
                    getLoaderManager().restartLoader(-1, null, this);
            } else {
                    getLoaderManager().initLoader(-1, null, this);
            }
            getActivity().getContentResolver().registerContentObserver(
                            ContactsContract.Users.CONTENT_URI, false,
                            new ContentObserver(null) {
                                    @Override
                                    public void onChange(final boolean selfChange) {
                                            Log.w(TAG, "Change");
                                    }
                            });
    }

    @Override
    public Loader<Cursor> onCreateLoader(final int id, final Bundle args) {
            // This is called when a new Loader needs to be created.
            // group cursor
            final CursorLoader cl = new CursorLoader(getActivity(),
                            ContactsContract.Groups.CONTENT_URI, GROUPS_PROJECTION, null,
                            null, null);

            return cl;
    }

    @Override
    public void onLoadFinished(final Loader<Cursor> loader, final Cursor cursor) {

            // Swap the new cursor in.
            final int id = loader.getId();

            if (id == -1) {

                    mAdapter.setGroupCursor(cursor);

            }

    }

    @Override
    public void onLoaderReset(final Loader<Cursor> loader) {
            // This is called when the last Cursor provided to onLoadFinished()
            // is about to be closed.
            final int id = loader.getId();
            if (id != -1) {
                    // child cursor
                    try {
                            mAdapter.setChildrenCursor(id, null);
                    } catch (final NullPointerException e) {
                            Log.w("TAG", "Adapter expired, try again on the next query: "
                                            + e.getMessage());
                    }
            } else {
                    mAdapter.setGroupCursor(null);
            }
    }

}
Другие вопросы по тегам