keeper

public abstract class CursorAdapter<VH extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<VH>  implements
    Filterable,
    CursorFilter.CursorFilterClient {

  /**
   * Call when bind view with the cursor
   * @param holder
   * @param cursor
   */
  public abstract void onBindViewHolder(VH holder, Cursor cursor);

  /**
   * This field should be made private, so it is hidden from the SDK.
   * {@hide}
   */
  protected boolean mDataValid;

  /**
   * The current cursor
   */
  protected Cursor mCursor;

  /**
   * This field should be made private, so it is hidden from the SDK.
   * {@hide}
   */
  protected Context mContext;

  /**
   * The row id column
   */
  protected int mRowIDColumn;

  /**
   * This field should be made private, so it is hidden from the SDK.
   * {@hide}
   */
  protected ChangeObserver mChangeObserver;
  /**
   * This field should be made private, so it is hidden from the SDK.
   * {@hide}
   */
  protected DataSetObserver mDataSetObserver;

  /**
   * This field should be made private, so it is hidden from the SDK.
   * {@hide}
   */
  protected CursorFilter mCursorFilter;

  /**
   * This field should be made private, so it is hidden from the SDK.
   * {@hide}
   */
  protected FilterQueryProvider mFilterQueryProvider;

  /**
   * If set the adapter will register a content observer on the cursor and will call
   * {@link #onContentChanged()} when a notification comes in.  Be careful when
   * using this flag: you will need to unset the current Cursor from the adapter
   * to avoid leaks due to its registered observers.  This flag is not needed
   * when using a CursorAdapter with a
   * {@link android.content.CursorLoader}.
   */
  public static final int FLAG_REGISTER_CONTENT_OBSERVER = 0x02;

  /**
   * Recommended constructor.
   *
   * @param c The cursor from which to get the data.
   * @param context The context
   * @param flags Flags used to determine the behavior of the adapter;
   *              Currently it accept {@link #FLAG_REGISTER_CONTENT_OBSERVER}.
   */
  public CursorAdapter(Context context, Cursor c, int flags) {
    init(context, c, flags);
  }

  void init(Context context, Cursor c, int flags) {

    boolean cursorPresent = c != null;
    mCursor = c;
    mDataValid = cursorPresent;
    mContext = context;
    mRowIDColumn = cursorPresent ? c.getColumnIndexOrThrow("_id") : -1;
    if ((flags & FLAG_REGISTER_CONTENT_OBSERVER) == FLAG_REGISTER_CONTENT_OBSERVER) {
      mChangeObserver = new ChangeObserver();
      mDataSetObserver = new MyDataSetObserver();
    } else {
      mChangeObserver = null;
      mDataSetObserver = null;
    }

    if (cursorPresent) {
      if (mChangeObserver != null) c.registerContentObserver(mChangeObserver);
      if (mDataSetObserver != null) c.registerDataSetObserver(mDataSetObserver);
    }
    setHasStableIds(true);
  }

  /**
   * Returns the cursor.
   * @return the cursor.
   */
  @Override
  public Cursor getCursor() {
    return mCursor;
  }

  /**
   * @see android.support.v7.widget.RecyclerView.Adapter#getItemCount()
   */
  @Override
  public int getItemCount() {
    if (mDataValid && mCursor != null) {
      return mCursor.getCount();
    } else {
      return 0;
    }
  }

  /**
   * @see android.support.v7.widget.RecyclerView.Adapter#getItemId(int)
   *
   * @param position Adapter position to query
   * @return
   */
  @Override
  public long getItemId(int position) {
    if (mDataValid && mCursor != null) {
      if (mCursor.moveToPosition(position)) {
        return mCursor.getLong(mRowIDColumn);
      } else {
        return 0;
      }
    } else {
      return 0;
    }
  }

  @Override
  public void onBindViewHolder(VH holder, int position) {
    if (!mDataValid) {
      throw new IllegalStateException("this should only be called when the cursor is valid");
    }
    if (!mCursor.moveToPosition(position)) {
      throw new IllegalStateException("couldn't move cursor to position " + position);
    }
    onBindViewHolder(holder, mCursor);
  }

  /**
   * Change the underlying cursor to a new cursor. If there is an existing cursor it will be
   * closed.
   *
   * @param cursor The new cursor to be used
   */
  public void changeCursor(Cursor cursor) {
    Cursor old = swapCursor(cursor);
    if (old != null) {
      old.close();
    }
  }

  /**
   * Swap in a new Cursor, returning the old Cursor.  Unlike
   * {@link #changeCursor(Cursor)}, the returned old Cursor is <em>not</em>
   * closed.
   *
   * @param newCursor The new cursor to be used.
   * @return Returns the previously set Cursor, or null if there wasa not one.
   * If the given new Cursor is the same instance is the previously set
   * Cursor, null is also returned.
   */
  public Cursor swapCursor(Cursor newCursor) {
    if (newCursor == mCursor) {
      return null;
    }
    Cursor oldCursor = mCursor;
    if (oldCursor != null) {
      if (mChangeObserver != null) oldCursor.unregisterContentObserver(mChangeObserver);
      if (mDataSetObserver != null) oldCursor.unregisterDataSetObserver(mDataSetObserver);
    }
    mCursor = newCursor;
    if (newCursor != null) {
      if (mChangeObserver != null) newCursor.registerContentObserver(mChangeObserver);
      if (mDataSetObserver != null) newCursor.registerDataSetObserver(mDataSetObserver);
      mRowIDColumn = newCursor.getColumnIndexOrThrow("_id");
      mDataValid = true;
      // notify the observers about the new cursor
      notifyDataSetChanged();
    } else {
      mRowIDColumn = -1;
      mDataValid = false;
      // notify the observers about the lack of a data set
      notifyDataSetChanged();
      //            notifyDataSetInvalidated();
    }
    return oldCursor;
  }

  /**
   * <p>Converts the cursor into a CharSequence. Subclasses should override this
   * method to convert their results. The default implementation returns an
   * empty String for null values or the default String representation of
   * the value.</p>
   *
   * @param cursor the cursor to convert to a CharSequence
   * @return a CharSequence representing the value
   */
  public CharSequence convertToString(Cursor cursor) {
    return cursor == null ? "" : cursor.toString();
  }

  /**
   * Runs a query with the specified constraint. This query is requested
   * by the filter attached to this adapter.
   *
   * The query is provided by a
   * {@link android.widget.FilterQueryProvider}.
   * If no provider is specified, the current cursor is not filtered and returned.
   *
   * After this method returns the resulting cursor is passed to {@link #changeCursor(Cursor)}
   * and the previous cursor is closed.
   *
   * This method is always executed on a background thread, not on the
   * application's main thread (or UI thread.)
   *
   * Contract: when constraint is null or empty, the original results,
   * prior to any filtering, must be returned.
   *
   * @param constraint the constraint with which the query must be filtered
   *
   * @return a Cursor representing the results of the new query
   *
   * @see #getFilter()
   * @see #getFilterQueryProvider()
   * @see #setFilterQueryProvider(android.widget.FilterQueryProvider)
   */
  public Cursor runQueryOnBackgroundThread(CharSequence constraint) {
    if (mFilterQueryProvider != null) {
      return mFilterQueryProvider.runQuery(constraint);
    }

    return mCursor;
  }

  public android.widget.Filter getFilter() {
    if (mCursorFilter == null) {
      mCursorFilter = new CursorFilter(this);
    }
    return mCursorFilter;
  }

  /**
   * Returns the query filter provider used for filtering. When the
   * provider is null, no filtering occurs.
   *
   * @return the current filter query provider or null if it does not exist
   *
   * @see #setFilterQueryProvider(android.widget.FilterQueryProvider)
   * @see #runQueryOnBackgroundThread(CharSequence)
   */
  public FilterQueryProvider getFilterQueryProvider() {
    return mFilterQueryProvider;
  }

  /**
   * Sets the query filter provider used to filter the current Cursor.
   * The provider's
   * {@link android.widget.FilterQueryProvider#runQuery(CharSequence)}
   * method is invoked when filtering is requested by a client of
   * this adapter.
   *
   * @param filterQueryProvider the filter query provider or null to remove it
   *
   * @see #getFilterQueryProvider()
   * @see #runQueryOnBackgroundThread(CharSequence)
   */
  public void setFilterQueryProvider(FilterQueryProvider filterQueryProvider) {
    mFilterQueryProvider = filterQueryProvider;
  }

  /**
   * Called when the {@link ContentObserver} on the cursor receives a change notification.
   * The default implementation provides the auto-requery logic, but may be overridden by
   * sub classes.
   *
   * @see ContentObserver#onChange(boolean)
   */
  protected abstract void onContentChanged();

  private class ChangeObserver extends ContentObserver {
    public ChangeObserver() {
      super(new Handler());
    }

    @Override
    public boolean deliverSelfNotifications() {
      return true;
    }

    @Override
    public void onChange(boolean selfChange) {
      onContentChanged();
    }
  }

  private class MyDataSetObserver extends DataSetObserver {
    @Override
    public void onChanged() {
      mDataValid = true;
      notifyDataSetChanged();
    }

    @Override
    public void onInvalidated() {
      mDataValid = false;
      notifyDataSetChanged();
      //            notifyDataSetInvalidated();
    }
  }
}



public class CursorFilter extends Filter {
  CursorFilterClient mClient;

  interface CursorFilterClient {
    CharSequence convertToString(Cursor cursor);
    Cursor runQueryOnBackgroundThread(CharSequence constraint);
    Cursor getCursor();
    void changeCursor(Cursor cursor);
  }

  CursorFilter(CursorFilterClient client) {
    mClient = client;
  }

  @Override
  public CharSequence convertResultToString(Object resultValue) {
    return mClient.convertToString((Cursor) resultValue);
  }

  @Override
  protected FilterResults performFiltering(CharSequence constraint) {
    Cursor cursor = mClient.runQueryOnBackgroundThread(constraint);

    FilterResults results = new FilterResults();
    if (cursor != null) {
      results.count = cursor.getCount();
      results.values = cursor;
    } else {
      results.count = 0;
      results.values = null;
    }
    return results;
  }

  @Override
  protected void publishResults(CharSequence constraint, FilterResults results) {
    Cursor oldCursor = mClient.getCursor();

    if (results.values != null && results.values != oldCursor) {
      mClient.changeCursor((Cursor) results.values);
    }
  }
}


public class DividerItemDecoration extends RecyclerView.ItemDecoration {
  private static final int[] ATTRS = new int[] {
      android.R.attr.listDivider
  };

  public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL;

  public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL;

  private Drawable mDivider;

  private int mOrientation;

  public DividerItemDecoration(int orientation, Drawable divider) {
    mDivider = divider;
    setOrientation(orientation);
  }

  public void setOrientation(int orientation) {
    if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) {
      throw new IllegalArgumentException("invalid orientation");
    }
    mOrientation = orientation;
  }

  @Override
  public void onDraw(Canvas c, RecyclerView parent) {
    if (mOrientation == VERTICAL_LIST) {
      drawVertical(c, parent);
    } else {
      drawHorizontal(c, parent);
    }
  }

  public void drawVertical(Canvas c, RecyclerView parent) {
    final int left = parent.getPaddingLeft();
    final int right = parent.getWidth() - parent.getPaddingRight();

    final int childCount = parent.getChildCount();
    for (int i = 0; i < childCount; i++) {
      final View child = parent.getChildAt(i);
      final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
      final int top = child.getBottom() + params.bottomMargin;
      final int bottom = top + mDivider.getIntrinsicHeight();
      mDivider.setBounds(left, top, right, bottom);
      mDivider.draw(c);
    }
  }

  public void drawHorizontal(Canvas c, RecyclerView parent) {
    final int top = parent.getPaddingTop();
    final int bottom = parent.getHeight() - parent.getPaddingBottom();

    final int childCount = parent.getChildCount();
    for (int i = 0; i < childCount; i++) {
      final View child = parent.getChildAt(i);
      final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
      final int left = child.getRight() + params.rightMargin;
      final int right = left + mDivider.getIntrinsicHeight();
      mDivider.setBounds(left, top, right, bottom);
      mDivider.draw(c);
    }
  }

  @Override
  public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) {
    if (mOrientation == VERTICAL_LIST) {
      outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
    } else {
      outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
    }
  }
}


SuperRecyclerView



你可能感兴趣的:(keeper)