使用SimpleCursorTreeAdapter的ExpandableListView在更新时滚动到顶部

时间:2014-04-11 03:19:44

标签: android expandablelistview simplecursortreeadapter

我通过扩展SimpleCursorTreeAdapter创建了一个ExpandableListAdapter。游标由加载器管理。当列表显示给用户时,我启动后台服务以从服务器获取最新数据。如果服务器返回新数据,我将其添加到DB并通知子游标。游标被重新获取并且列表更新。此时,如果用户在列表中向下滚动,则列表向上滚动到顶部。这非常烦人。我已经浏览了* TreeAdapters的整个API,但没有看到任何方法来阻止它。这一定是一个非常普遍的问题。我该如何解决?

1 个答案:

答案 0 :(得分:2)

试试这段代码:

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);
            }
    }

}