Code example for Adapter

Methods: getCountisEmptyregisterDataSetObserver

0
		} 
 
	} 
	protected void checkFocus () { 
		final T adapter = getAdapter();
		final boolean focusable = !(adapter == null || adapter.getCount() == 0);
		// The order in which we set focusable in touch mode/focusable may matter 
		// for the client, see View.setFocusableInTouchMode() comments for more 
		// details 
		super.setFocusableInTouchMode( focusable && mDesiredFocusableInTouchModeState );
		super.setFocusable( focusable && mDesiredFocusableState );
		if (getEmptyView() != null) { 
			updateEmptyStatus( (adapter == null) || adapter.isEmpty() );
		} 
	} 
 
	@Override 
	protected void onLayout (boolean changed, int l, int t, int r, int b) {
 
		mLayoutHeight = getHeight();
 
		super.onLayout( changed, l, t, r, b );
 
		// Remember that we are in layout to prevent more layout request from being generated. 
		mInLayout = true;
		layoutChildren( 0, false, changed );
		mInLayout = false;
	} 
 
 
	protected abstract void layoutChildren (int delta, boolean animate, boolean changed);
 
	/** 
	 * Override to prevent spamming ourselves with layout requests 
	 * as we place views 
	 * 
	 * @see android.view.View#requestLayout() 
	 */ 
	@Override 
	public void requestLayout () { 
		if (!mBlockLayoutRequests) {
			super.requestLayout(); 
		} 
	} 
 
	/** 
	 * Controls whether the selection highlight drawable should be drawn on top of the item or 
	 * behind it. 
	 * 
	 * @param onTop If true, the selector will be drawn on the item it is highlighting. The default 
	 *              is false. 
	 * @attr ref android.R.styleable#AbsListView_drawSelectorOnTop 
	 */ 
	public void setDrawSelectorOnTop (boolean onTop) {
		mDrawSelectorOnTop = onTop;
	} 
 
	/** 
	 * Set a Drawable that should be used to highlight the currently selected item. 
	 * 
	 * @param resID A Drawable resource to use as the selection highlight. 
	 * @attr ref android.R.styleable#AbsListView_listSelector 
	 */ 
	public void setSelector (int resID) {
		setSelector( getResources().getDrawable( resID ) );
	} 
 
	public void setSelector (Drawable sel) {
 
		if (mSelector != null) {
			mSelector.setCallback(null);
			unscheduleDrawable(mSelector);
		} 
 
		mSelector = sel;
		Rect padding = new Rect();
		sel.getPadding(padding);
		mSelectionLeftPadding = padding.left;
		mSelectionTopPadding = padding.top;
		mSelectionRightPadding = padding.right;
		mSelectionBottomPadding = padding.bottom;
		sel.setCallback(this);
		updateSelectorState(); 
	} 
 
	/** 
	 * Indicates whether this view is in a state where the selector should be drawn. This will 
	 * happen if we have focus but are not in touch mode, or we are in the middle of displaying 
	 * the pressed state for an item. 
	 * 
	 * @return True if the selector should be shown 
	 */ 
	protected boolean shouldShowSelector () { 
		return (hasFocus() && !isInTouchMode()) || isPressed();
	} 
 
	/** 
	 * Overridden to draw the selector image. 
	 * 
	 * @param canvas Canvas object 
	 */ 
	@Override 
	protected void dispatchDraw (Canvas canvas) {
 
		if (mSelectorRect.isEmpty()) {
			super.dispatchDraw( canvas );
			return; 
		} 
 
		//final boolean clipToPadding = (mGroupFlags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK; 
		//if (clipToPadding) { 
		int saveCount = canvas.save();
		final int scrollX = getScrollX();
		final int scrollY = getScrollY();
		canvas.clipRect( scrollX + getPaddingLeft(), scrollY + getPaddingTop(),
				scrollX + getRight() - getLeft() - getPaddingRight(),
				scrollY + getBottom() - getTop() - getPaddingBottom() );
		//mGroupFlags &= ~CLIP_TO_PADDING_MASK; 
		//} 
 
		final boolean drawSelectorOnTop = mDrawSelectorOnTop;
		if (!drawSelectorOnTop) {
			drawSelector( canvas );
		} 
 
		super.dispatchDraw( canvas );
 
		if (drawSelectorOnTop) {
			drawSelector( canvas );
		} 
 
		//if (clipToPadding) { 
		canvas.restoreToCount( saveCount );
		//mGroupFlags |= CLIP_TO_PADDING_MASK; 
		//} 
	} 
 
	/** 
	 * Override this method if you need to draw a custom selector. 
	 * 
	 * @param canvas Canvas instance. 
	 */ 
	protected void drawSelector (Canvas canvas) {
		if (mSelector != null && !mSelectorRect.isEmpty()) {
			final Drawable selector = mSelector;
			selector.setBounds( mSelectorRect );
			selector.draw( canvas );
		} 
	} 
 
	protected void updateSelector () { 
		if (!isInTouchMode() && mSelectedPosition != INVALID_POSITION)
			positionSelector(mSelectedPosition, getSelectedView());
		else if (mSelectorPosition != INVALID_POSITION)
			positionSelector(INVALID_POSITION, getSelectedView());
		else 
			mSelectorRect.setEmpty();
	} 
 
	private static final int[] STATE_NOTHING = new int[]{0};
 
	private void updateSelectorState () { 
		if (mSelector != null) {
			if (shouldShowSelector()) 
				mSelector.setState( getDrawableState() );
			else 
				mSelector.setState( STATE_NOTHING );
		} 
	} 
 
	private void positionSelector (int position, View sel) {
 
		if (position != INVALID_POSITION) {
			mSelectorPosition = position;
		} 
 
		if (sel == null) return;
 
		final Rect selectorRect = mSelectorRect;
		selectorRect.set( sel.getLeft(), sel.getTop(), sel.getRight(), sel.getBottom() );
		positionSelector( selectorRect.left, selectorRect.top, selectorRect.right, selectorRect.bottom );
 
		final boolean isChildViewEnabled = mIsChildViewEnabled;
		if (sel.isEnabled() != isChildViewEnabled) {
			mIsChildViewEnabled = !isChildViewEnabled;
			if (getSelectedItemPosition() != INVALID_POSITION) {
				refreshDrawableState();
			} 
		} 
	} 
 
	private void positionSelector (int l, int t, int r, int b) {
		mSelectorRect.set( l - mSelectionLeftPadding, t - mSelectionTopPadding, r + mSelectionRightPadding, b + mSelectionBottomPadding );
	} 
 
	protected void updateSelectedItemMetadata () { 
 
		updateSelector(); 
 
		View oldSelectedChild = mSelectedChild;
 
		View child = mSelectedChild = getChildAt( mSelectedPosition - mFirstPosition );
		if (child == null) {
			return; 
		} 
 
		child.setSelected( true );
		child.setFocusable( true );
 
		if (hasFocus()) {
			child.requestFocus();
		} 
 
		// We unfocus the old child down here so the above hasFocus check 
		// returns true 
		if (oldSelectedChild != null && oldSelectedChild != child) {
 
			// Make sure its drawable state doesn't contain 'selected' 
			oldSelectedChild.setSelected( false );
 
			// Make sure it is not focusable anymore, since otherwise arrow keys 
			// can make this one be focused 
			oldSelectedChild.setFocusable( false );
		} 
	} 
 
	@Override 
	protected void drawableStateChanged () { 
		super.drawableStateChanged(); 
		updateSelectorState(); 
	} 
 
	@Override 
	protected int[] onCreateDrawableState (int extraSpace) {
		// If the child view is enabled then do the default behavior. 
		if (mIsChildViewEnabled) {
			// Common case 
			return super.onCreateDrawableState( extraSpace );
		} 
 
		// The selector uses this View's drawable state. The selected child view 
		// is disabled, so we need to remove the enabled state from the drawable 
		// states. 
		final int enabledState = ENABLED_STATE_SET[0];
 
		// If we don't have any extra space, it will return one of the static state arrays, 
		// and clearing the enabled state on those arrays is a bad thing!  If we specify 
		// we need extra space, it will create+copy into a new array that safely mutable. 
		int[] state = super.onCreateDrawableState( extraSpace + 1 );
		int enabledPos = -1;
		for (int i = state.length - 1; i >= 0; i--) {
			if (state[i] == enabledState) {
				enabledPos = i;
				break; 
			} 
		} 
 
		// Remove the enabled state 
		if (enabledPos >= 0)
			System.arraycopy( state, enabledPos + 1, state, enabledPos, state.length - enabledPos - 1 );
 
		return state;
	} 
 
	@Override 
	public boolean verifyDrawable (Drawable dr) {
		return mSelector == dr || super.verifyDrawable( dr );
	} 
 
	/** 
	 * Update the status of the list based on the empty parameter.  If empty is true and 
	 * we have an empty view, display it.  In all the other cases, make sure that the listview 
	 * is VISIBLE and that the empty view is GONE (if it's not null). 
	 */ 
	private void updateEmptyStatus (boolean empty) {
		if (empty) {
			View mEmptyView = getEmptyView();
			if (mEmptyView != null) {
				mEmptyView.setVisibility( View.VISIBLE );
				setVisibility( View.GONE );
			} 
			else { 
				// If the caller just removed our empty view, make sure the list view is visible 
				setVisibility( View.VISIBLE );
			} 
 
			// We are now GONE, so pending layouts will not be dispatched. 
			// Force one here to make sure that the state of the list matches 
			// the state of the adapter. 
			if (mDataChanged) {
				onLayout( false, getLeft(), getTop(), getRight(), getBottom() );
			} 
		} 
		else { 
			View mEmptyView = getEmptyView();
			if (mEmptyView != null) mEmptyView.setVisibility( View.GONE );
			setVisibility( View.VISIBLE );
		} 
	} 
 
	/** 
	 * Gets the data associated with the specified position in the list. 
	 * 
	 * @param position Which data to get 
	 * @return The data associated with the specified position in the list 
	 */ 
	public Object getItemAtPosition (int position) {
		return (mAdapter == null || position < 0) ? null : mAdapter.getItem( position );
	} 
 
	public long getItemIdAtPosition (int position) {
		return (mAdapter == null || position < 0) ? INVALID_ROW_ID : mAdapter.getItemId( position );
	} 
 
	@Override 
	public void setOnClickListener (OnClickListener l) {
		throw new RuntimeException( "Don't call setOnClickListener for an AdapterView. "
				+ "You probably want setOnItemClickListener instead" ); 
	} 
 
	/** 
	 * Clear out all children from the list 
	 */ 
	protected void resetList () { 
		mDataChanged = false;
		mNeedSync = false;
 
		removeAllViewsInLayout();
		mOldSelectedPosition = INVALID_POSITION;
		mOldSelectedRowId = INVALID_ROW_ID;
 
		mSelectorPosition = INVALID_POSITION;
		mSelectorRect.setEmpty();
 
		setSelectedPositionInt( INVALID_POSITION );
		setNextSelectedPositionInt( INVALID_POSITION );
		invalidate();
	} 
 
	protected void recycleAllViews () { 
		final int childCount = getChildCount();
		final RecycleBin recycleBin = mRecycler;
		final int position = mFirstPosition;
 
		// All views go in recycler 
		for (int i = 0; i < childCount; i++) {
			View v = getChildAt( i );
			int index = position + i;
			recycleBin.put( index, v );
		} 
	} 
 
	/** 
	 * Override to prevent freezing of any views created by the adapter. 
	 */ 
	@Override 
	protected void dispatchSaveInstanceState (SparseArray<Parcelable> container) {
		dispatchFreezeSelfOnly( container );
	} 
 
	/** 
	 * Override to prevent thawing of any views created by the adapter. 
	 */ 
	@Override 
	protected void dispatchRestoreInstanceState (SparseArray<Parcelable> container) {
		dispatchThawSelfOnly( container );
	} 
 
	protected DataSetObserver createDataSetObserver () {
		return new AdapterDataSetObserver(); 
	} 
 
	protected class AdapterDataSetObserver extends DataSetObserver {
 
		private Parcelable mInstanceState = null;
 
		@Override 
		public void onChanged () { 
			mDataChanged = true;
			mOldItemCount = mItemCount;
			mItemCount = mAdapter.getCount();
 
			// Detect the case where a cursor that was previously invalidated has 
			// been repopulated with new data. 
			if (mAdapter.hasStableIds() && mInstanceState != null && mOldItemCount == 0 && mItemCount > 0) {
				onRestoreInstanceState( mInstanceState );
				mInstanceState = null;
			} 
			else { 
				rememberSyncState(); 
			} 
			checkFocus(); 
			requestLayout(); 
		} 
 
		@Override 
		public void onInvalidated () { 
			mDataChanged = true;
 
			if (mAdapter.hasStableIds()) {
				// Remember the current state for the case where our hosting activity is being 
				// stopped and later restarted 
				mInstanceState = onSaveInstanceState();
			} 
 
			// Data is invalid so we should reset our state 
			mOldItemCount = mItemCount;
			mItemCount = 0;
			mSelectedPosition = INVALID_POSITION;
			mSelectedRowId = INVALID_ROW_ID;
			mNextSelectedPosition = INVALID_POSITION;
			mNextSelectedRowId = INVALID_ROW_ID;
			mNeedSync = false;
 
			checkFocus(); 
			requestLayout(); 
		} 
 
		public void clearSavedState () { 
			mInstanceState = null;
		} 
	} 
 
	@Override 
	protected void onDetachedFromWindow () { 
		super.onDetachedFromWindow(); 
		removeCallbacks( mSelectionNotifier );
	} 
 
	private class SelectionNotifier implements Runnable {
 
		public void run () { 
			if (mDataChanged) {
				// Data has changed between when this SelectionNotifier 
				// was posted and now. We need to wait until the AdapterView 
				// has been synched to the new data. 
				if (getAdapter() != null) { 
					post( this );
				} 
			} 
			else { 
				fireOnSelected(); 
			} 
		} 
	} 
 
	protected void selectionChanged () { 
 
		updateSelector(); 
 
		if (getOnItemSelectedListener() != null) { 
			if (mInLayout || mBlockLayoutRequests) {
				// If we are in a layout traversal, defer notification 
				// by posting. This ensures that the view tree is 
				// in a consistent state and is able to accomodate 
				// new layout or invalidate requests. 
				if (mSelectionNotifier == null) {
					mSelectionNotifier = new SelectionNotifier();
				} 
				post( mSelectionNotifier );
			} 
			else { 
				fireOnSelected(); 
			} 
		} 
 
		// we fire selection events here not in View 
		if (mSelectedPosition != ListView.INVALID_POSITION && isShown() && !isInTouchMode()) {
			sendAccessibilityEvent( AccessibilityEvent.TYPE_VIEW_SELECTED );
		} 
	} 
 
	private void fireOnSelected () { 
		if (getOnItemSelectedListener() == null) 
			return; 
 
		int selection = this.getSelectedItemPosition();
		if (selection >= 0) {
			View v = getSelectedView();
			getOnItemSelectedListener().onItemSelected( this, v, selection, getAdapter().getItemId( selection ) );
		} 
		else { 
			getOnItemSelectedListener().onNothingSelected( this );
		} 
	} 
 
	@Override 
	public boolean dispatchPopulateAccessibilityEvent (AccessibilityEvent event) {
		View selectedView = getSelectedView();
		return selectedView != null && selectedView.getVisibility() == VISIBLE && selectedView.dispatchPopulateAccessibilityEvent( event );
	} 
 
//	@Override 
//	public boolean onRequestSendAccessibilityEvent (View child, AccessibilityEvent event) { 
//		if (super.onRequestSendAccessibilityEvent( child, event )) { 
//			// Add a record for ourselves as well. 
//			AccessibilityEvent record = AccessibilityEvent.obtain(); 
//			onInitializeAccessibilityEvent( record ); 
//			// Populate with the text of the requesting child. 
//			child.dispatchPopulateAccessibilityEvent( record ); 
//			event.appendRecord( record ); 
//			return true; 
//		} 
//		return false; 
//	} 
// 
//	@Override 
//	public void onInitializeAccessibilityNodeInfo (AccessibilityNodeInfo info) { 
//		super.onInitializeAccessibilityNodeInfo( info ); 
//		info.setScrollable( isScrollableForAccessibility() ); 
//		View selectedView = getSelectedView(); 
//		if (selectedView != null) { 
//			info.setEnabled( selectedView.isEnabled() ); 
//		} 
//	} 
// 
//	@Override 
//	public void onInitializeAccessibilityEvent (AccessibilityEvent event) { 
//		super.onInitializeAccessibilityEvent( event ); 
//		event.setScrollable( isScrollableForAccessibility() ); 
//		View selectedView = getSelectedView(); 
//		if (selectedView != null) { 
//			event.setEnabled( selectedView.isEnabled() ); 
//		} 
//		event.setCurrentItemIndex( getSelectedItemPosition() ); 
//		event.setFromIndex( getFirstVisiblePosition() ); 
//		event.setToIndex( getLastVisiblePosition() ); 
//		event.setItemCount( getCount() ); 
//	} 
 
	private boolean isScrollableForAccessibility () { 
		T adapter = getAdapter();
		if (adapter != null) {
			final int itemCount = adapter.getCount();
			return itemCount > 0
					&& (getFirstVisiblePosition() > 0 || getLastVisiblePosition() < itemCount - 1);
		} 
		return false; 
	} 
 
	@Override 
	protected boolean canAnimate () { 
		return getLayoutAnimation() != null && mItemCount > 0;
	} 
 
	protected void handleDataChanged () { 
		final int count = mItemCount;
		boolean found = false;
 
		if (count > 0) {
 
			int newPos;
 
			// Find the row we are supposed to sync to 
			if (mNeedSync) {
				// Update this first, since setNextSelectedPositionInt inspects 
				// it 
				mNeedSync = false;
 
				// See if we can find a position in the new data with the same 
				// id as the old selection 
				newPos = findSyncPosition();
				if (newPos >= 0) {
					// Verify that new selection is selectable 
					int selectablePos = lookForSelectablePosition( newPos, true );
					if (selectablePos == newPos) {
						// Same row id is selected 
						setNextSelectedPositionInt( newPos );
						found = true;
					} 
				} 
			} 
			if (!found) {
				// Try to use the same position if we can't find matching data 
				newPos = getSelectedItemPosition();
 
				// Pin position to the available range 
				if (newPos >= count) {
					newPos = count - 1;
				} 
				if (newPos < 0) {
					newPos = 0;
				} 
 
				// Make sure we select something selectable -- first look down 
				int selectablePos = lookForSelectablePosition( newPos, true );
				if (selectablePos < 0) {
					// Looking down didn't work -- try looking up 
					selectablePos = lookForSelectablePosition( newPos, false );
				} 
				if (selectablePos >= 0) {
					setNextSelectedPositionInt( selectablePos );
					checkSelectionChanged(); 
					found = true;
				} 
			} 
		} 
		if (!found) {
			// Nothing is selected 
			mSelectedPosition = INVALID_POSITION;
			mSelectedRowId = INVALID_ROW_ID;
			mNextSelectedPosition = INVALID_POSITION;
			mNextSelectedRowId = INVALID_ROW_ID;
			mNeedSync = false;
			checkSelectionChanged(); 
		} 
	} 
 
	@Override 
	public T getAdapter () { 
		return mAdapter;
	} 
 
	/** 
	 * The Adapter is used to provide the data which backs this Spinner. 
	 * It also provides methods to transform spinner items based on their position 
	 * relative to the selected item. 
	 * 
	 * @param adapter The SpinnerAdapter to use for this Spinner 
	 */ 
	@Override 
	public void setAdapter (T adapter) {
		if (null != mAdapter) {
			mAdapter.unregisterDataSetObserver( mDataSetObserver );
			resetList(); 
		} 
 
		mAdapter = adapter;
 
		mOldSelectedPosition = INVALID_POSITION;
		mOldSelectedRowId = INVALID_ROW_ID;
 
		if (mAdapter != null) {
			mOldItemCount = mItemCount;
			mItemCount = mAdapter.getCount();
			checkFocus(); 
 
			mDataSetObserver = createDataSetObserver();
			mAdapter.registerDataSetObserver( mDataSetObserver );
 
			int position = mItemCount > 0 ? 0 : INVALID_POSITION;
 
			setSelectedPositionInt( position );
			setNextSelectedPositionInt( position );