Android開發經驗分享-GridView、ListView內容錯亂

jia635發表於2014-07-22

在使用GridView、ListView的過程中遇到內容錯亂的問題,費了較長時間才找到問題的根源,特地總結一下。

1、在自定義adapter中沒有給每一項都設定內容導致內容錯亂:

@Override
public View getView(final int position, View convertView, ViewGroup parent) {
    if( null == convertView ){
        mGridHolder = new GridHolder( );
         
    convertView = mLayoutInflater.inflate( R.layout.view_log_word_item_layout, null );
     
    mGridHolder.mBackTopLayout = (LinearLayout)convertView.findViewById( R.id.logItemTopLayoutId);
    mGridHolder.mBackBottomLayout = ( RelativeLayout )convertView.findViewById( R.id.logItemBottomLayoutId );
    mGridHolder.mRightWordTxt = ( TextView )convertView.findViewById( R.id.rightWordTxtId );
    mGridHolder.mUserWriteImg = ( ImageView )convertView.findViewById( R.id.userWordImgId );
    mGridHolder.mWriteResultImg = ( ImageView )convertView.findViewById( R.id.writeResultImgId );
    mGridHolder.mReasonTxt = ( TextView )convertView.findViewById( R.id.reasonTxtId );
    mGridHolder.mRightWordTxt.setTypeface( mTypeface );
     
      convertView.setTag( mGridHolder );
  }else{
    mGridHolder = ( GridHolder )convertView.getTag( );
  }
     
  showContent( mDictationInfoList.get( position ) );
     
  return convertView;
}
 
@SuppressWarnings("deprecation")
private void showContent( DictationInfo dictationInfo ){
    mGridHolder.mRightWordTxt.setText( dictationInfo.getmWord( ) );
    if( null != dictationInfo.getmDrawable( ) ){
        mGridHolder.mUserWriteImg.setBackgroundDrawable( dictationInfo.getmDrawable( ) );
         
        if( !TextUtils.isEmpty( dictationInfo.getDetailReason( ) ) ){
            mGridHolder.mReasonTxt.setText( dictationInfo.getDetailReason( ) );
        }else{
            mGridHolder.mReasonTxt.setText( "" );
        }
         
      setWriteResult( dictationInfo.getmWriteResult( ) );
    }else{
        // 沒有為內容項為空的項設定內容
    }
}

上面是一個自定義adapter中的一段程式碼,在getView中為每一項設定內容時只處理了有內容的項,沒有內容的項沒有賦值,導致在滑動內容時內容錯亂,分析發現這是由於使用了adapter的快取機制導致的,正確的處理方式是需要為內容為空的項也要賦值,修改後的程式碼如下:

@Override
public View getView(final int position, View convertView, ViewGroup parent) {
    if( null == convertView ){
        mGridHolder = new GridHolder( );
         
    convertView = mLayoutInflater.inflate( R.layout.view_log_word_item_layout, null );
     
    mGridHolder.mBackTopLayout = (LinearLayout)convertView.findViewById( R.id.logItemTopLayoutId);
    mGridHolder.mBackBottomLayout = ( RelativeLayout )convertView.findViewById( R.id.logItemBottomLayoutId );
    mGridHolder.mRightWordTxt = ( TextView )convertView.findViewById( R.id.rightWordTxtId );
    mGridHolder.mUserWriteImg = ( ImageView )convertView.findViewById( R.id.userWordImgId );
    mGridHolder.mWriteResultImg = ( ImageView )convertView.findViewById( R.id.writeResultImgId );
    mGridHolder.mReasonTxt = ( TextView )convertView.findViewById( R.id.reasonTxtId );
    mGridHolder.mRightWordTxt.setTypeface( mTypeface );
     
      convertView.setTag( mGridHolder );
  }else{
    mGridHolder = ( GridHolder )convertView.getTag( );
  }
     
  showContent( mDictationInfoList.get( position ) );
     
  return convertView;
}
 
@SuppressWarnings("deprecation")
private void showContent( DictationInfo dictationInfo ){
    mGridHolder.mRightWordTxt.setText( dictationInfo.getmWord( ) );
    if( null != dictationInfo.getmDrawable( ) ){
        mGridHolder.mUserWriteImg.setBackgroundDrawable( dictationInfo.getmDrawable( ) );
         
        if( !TextUtils.isEmpty( dictationInfo.getDetailReason( ) ) ){
            mGridHolder.mReasonTxt.setText( dictationInfo.getDetailReason( ) );
        }else{
            mGridHolder.mReasonTxt.setText( "" );
        }
         
      setWriteResult( dictationInfo.getmWriteResult( ) );
    }else{
        mGridHolder.mUserWriteImg.setBackgroundResource( Color.TRANSPARENT );
        mGridHolder.mReasonTxt.setText( "" );
        mGridHolder.mWriteResultImg.setBackgroundResource( R.drawable.log_unknown );
        mGridHolder.mBackTopLayout.setBackgroundResource( R.drawable.log_item_wrong_top_background );
        mGridHolder.mBackBottomLayout.setBackgroundResource( R.drawable.log_item_wrong_bottom_background );
    }
}

2、在自定義adapter的getview方法中,每一項的內容載入時間過長導致內容錯亂。

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    mViewHolder = new ViewHolder( );
 
    convertView = mLayoutInflater.inflate( R.layout.adapter_score_list_layout, null );
    mViewHolder.mScoreLayout = ( RelativeLayout )convertView.findViewById( R.id.scoreLayoutId );
    mViewHolder.mScoreLayout.setClickable( false );
    mViewHolder.mPositionTxt = ( TextView )convertView.findViewById( R.id.positionTxtId );
    mViewHolder.mUserNameTxt = ( TextView )convertView.findViewById( R.id.userNameTxtId );
    mViewHolder.mUserNameTxt.setTypeface( mTypeface );
    mViewHolder.mUserIconImg = ( ImageView )convertView.findViewById( R.id.userIconImgId );
    mViewHolder.mUserScoreTxt = ( TextView )convertView.findViewById( R.id.userScoreTxtId );
     
    showContent( position, mUserInfoList.get( position ) );
    return convertView;
}
 
private void showContent( int index, UserScoreInfo userInfo ){
    // 從網路獲取頭像
    handleUserIcon( mImageLoader, userInfo, mUserId );
    mViewHolder.mPositionTxt.setVisibility(TextView.VISIBLE);
    mViewHolder.mPositionTxt.setText( "第" + userInfo.getScoreRank( ) + "名" );
     
    if( mUserId.equals( userInfo.getUserId( ) ) ){
        mMyPosition = index;
        mViewHolder.mScoreLayout.setBackgroundResource( R.drawable.chinese_dictation_score_list_select );
    }else{
        mViewHolder.mScoreLayout.setBackgroundResource( R.drawable.chinese_dictation_score_list_normal );
    }
     
    String userName = userInfo.getNickName( );
    if( !TextUtils.isEmpty( userName ) ){
        userName = ( userName.length( ) > 10 )?( userName.substring(0, 7) + "..." ):userName;
    }else{
        userName = "佚名";
    }
     
    if( mUserId.equals( userInfo.getUserId( ) ) ){
        String localUserName = PersonalInfo.getCurrentUserName( mContext );
        mMyPosition = index;
        mViewHolder.mScoreLayout.setBackgroundResource( R.drawable.chinese_dictation_score_list_select );
        if( TextUtils.isEmpty( userName ) || ( !localUserName.equals( userName ) ) ){
            mViewHolder.mUserNameTxt.setText( localUserName  );
        }else{
            mViewHolder.mUserNameTxt.setText( userName  );
        }
             
    }else{
        mViewHolder.mScoreLayout.setBackgroundResource( R.drawable.chinese_dictation_score_list_normal );
        mViewHolder.mUserNameTxt.setText( userName );
    }
     
    mViewHolder.mUserScoreTxt.setText( StringUtils.getSplitByComma( userInfo.getScore( ) + "" ) );
}

上面是一個獲取使用者排名列表所自定義adapter中的一段程式碼,handleUserIcon方法是從網路獲取使用者頭像,在滑動排名列表的時候發現使用者頭像會錯亂,最後跟蹤找到具體的原因是由於從網路獲取使用者頭像耗時,正確的做法應該是在獲取完成使用者頭像之後再通知adapter更新。


在使用gridview和listview的過程中,由於需要載入大量的內容,android建議我們採用viewholder的快取機制,這樣能夠提高列表載入的效率,但是在使用的過程中一定要注意上面這兩個問題,否則可能會讓你很頭疼。


相關文章