2013-10-23 79 views
2

我在適配器的getView方法內部有位置變量這個奇怪的問題。 這6種不同視圖類型中的4種,在它們內部有一個按鈕。該按鈕向服務發送消息(在服務中引發一些異步的東西),並且在無限期的時間之後,該適配器獲得服務激發的notifyDataSetChanged()。BaseAdapter的getView獲取錯誤位置

問題顯示當我發送消息發送按鈕時。如果我發送垃圾郵件的速度夠快,錯誤的位置將被髮送到服務。我認爲問題在於,在垃圾郵件過程中,我會在notifyDataSetChanged()期間點擊按鈕,因爲如果我在該服務正在使用的方法上評論該調用,則不一致不會發生。

這是我第一次使用BaseAdapter,我跟着這個漂亮的教程: Base Adapter Tutorial

下面是我認爲可以是相關的確定問題的部分代碼。

即使世界6種不同視圖類型是由該適配器管理:

​​

而這裏是方法IM首要:

@Override 
    public int getViewTypeCount() { 
     return MAX_COUNT; 
    } 

    @Override 
    public int getCount() { 
     return data.size(); 
    } 

    @Override 
    public ListViewDataItem getItem(int position) { 
     return data.get(position); 
    } 

    @Override 
    public long getItemId(int position) { 
     return position; 
    } 

    @Override 
    public int getItemViewType(int position) { 
     return getItem(position).getType(); 
    } 

而繼承人的getView方法:

@Override 
    public View getView(final int position, View convertView, ViewGroup parent) { 
//  Thread.currentThread().setContextClassLoader(MyParcelableFile.class.getClassLoader()); 
     View row = convertView; 
     StandardFolderViewHolder standardFolderViewHolder = null; 
     StandardFileViewHolder standardFileViewHolder = null; 
     MusicFileStoppedViewHolder musicFileStoppedHolder = null; 
     MusicFilePlayingViewHolder musicFilePlayingHolder = null; 
     MusicFolderStoppedViewHolder musicFolderStoppedHolder = null; 
     MusicFolderPlayingViewHolder musicFolderPlayingHolder = null; 

     switch(getItemViewType(position)) { 
     case Constants.MEDIA_FILE.TYPE.STANDARD_DIRECTORY: 
      if(row == null) { 
       standardFolderViewHolder = new StandardFolderViewHolder(); 
       row = inflater.inflate(R.layout.listview_mixed_folder_row, parent, false); 
       standardFolderViewHolder.icon = (ImageView)row.findViewById(R.id.filetype_icon); 
       standardFolderViewHolder.tempTV = (TextView)row.findViewById(R.id.listview_mixed_folder_row_test_tv); 
       row.setTag(standardFolderViewHolder); 
      } 
      else { 
       standardFolderViewHolder = (StandardFolderViewHolder)row.getTag(); 
      } 
      standardFolderViewHolder.icon.setImageDrawable(getItem(position).getDrawable()); 
      standardFolderViewHolder.tempTV.setText(getItem(position).getName()); 
      standardFolderViewHolder.tempTV.setSelected(true); 
      break; 
     case Constants.MEDIA_FILE.TYPE.MUSIC_DIRECTORY: 
      if(getItemViewState(position) == Constants.MEDIA_FILE.TYPE.STATE.PLAYING) { 
       if(row == null || (row !=null && row.getTag() instanceof MusicFolderStoppedViewHolder)) { 
        musicFolderPlayingHolder = new MusicFolderPlayingViewHolder(); 
        row = inflater.inflate(R.layout.listview_music_folder_playing_row, parent, false); 
        musicFolderPlayingHolder.icon = (ImageView)row.findViewById(R.id.filetype_icon); 
        musicFolderPlayingHolder.songName = (TextView)row.findViewById(R.id.row_title_tv); 
        musicFolderPlayingHolder.playButton = (Button)row.findViewById(R.id.row_play_button); 
        musicFolderPlayingHolder.durationTV = (TextView)row.findViewById(R.id.row_duration_tv); 
        musicFolderPlayingHolder.progressBar = (ProgressBar)row.findViewById(R.id.folder_progress_bar); 
        row.setTag(musicFolderPlayingHolder); 
       } 
       else { 
        musicFolderPlayingHolder = (MusicFolderPlayingViewHolder)row.getTag(); 
       } 
       musicFolderPlayingHolder.icon.setImageDrawable(getItem(position).getDrawable()); 
       musicFolderPlayingHolder.songName.setText(getItem(position).getName()); 
       musicFolderPlayingHolder.songName.setSelected(true); 
       musicFolderPlayingHolder.durationTV.setText(mActivity.formattedMillis(getItem(position).getDuration())); 
       musicFolderPlayingHolder.progressBar.setMax(getItem(position).getDuration()); 
       musicFolderPlayingHolder.progressBar.setProgress(getItem(position).getProgress()); 
       musicFolderPlayingHolder.playButton.setOnClickListener(new OnClickListener() { 

        @Override 
        public void onClick(View arg0) { 
         Log.e("clicked", getItem(position).getName()); 
         Bundle bun = new Bundle(); 
         bun.putString(Constants.BUNDLE_KEYS.PLAY_FILES, getItem(position).getPath()); 
         Message message = Message.obtain(null, Constants.OP_CODE.PLAY_FILES); 
         message.setData(bun); 
         try { 
          mActivity.mService.send(message); 
         } 
         catch (RemoteException re) { 
          re.printStackTrace(); 
         } 
        } 

       }); 
      } 
      else if(getItemViewState(position) == Constants.MEDIA_FILE.TYPE.STATE.STOPPED) { 
       if(row == null || (row !=null && row.getTag() instanceof MusicFolderPlayingViewHolder)) { 
        musicFolderStoppedHolder = new MusicFolderStoppedViewHolder(); 
        row = inflater.inflate(R.layout.listview_music_folder_stopped_row, parent, false); 
        musicFolderStoppedHolder.icon = (ImageView)row.findViewById(R.id.filetype_icon); 
        musicFolderStoppedHolder.songName = (TextView)row.findViewById(R.id.row_title_tv); 
        musicFolderStoppedHolder.playButton = (Button)row.findViewById(R.id.row_play_button); 
        musicFolderStoppedHolder.durationTV = (TextView)row.findViewById(R.id.row_duration_tv); 
        row.setTag(musicFolderStoppedHolder); 
       } 
       else { 
        musicFolderStoppedHolder = (MusicFolderStoppedViewHolder)row.getTag(); 
       } 
       musicFolderStoppedHolder.icon.setImageDrawable(getItem(position).getDrawable()); 
       musicFolderStoppedHolder.songName.setText(getItem(position).getName()); 
       musicFolderStoppedHolder.songName.setSelected(true); 
       musicFolderStoppedHolder.durationTV.setText(mActivity.formattedMillis(getItem(position).getDuration())); 
       musicFolderStoppedHolder.playButton.setOnClickListener(new OnClickListener() { 

        @Override 
        public void onClick(View arg0) { 
         Log.e("clicked", getItem(position).getName()); 
         Bundle bun = new Bundle(); 
         bun.putString(Constants.BUNDLE_KEYS.PLAY_FILES, getItem(position).getPath()); 
         Message message = Message.obtain(null, Constants.OP_CODE.PLAY_FILES); 
         message.setData(bun); 
         try { 
          mActivity.mService.send(message); 
         } 
         catch (RemoteException re) { 
          re.printStackTrace(); 
         } 
        } 

       }); 
      } 
      break; 
     case Constants.MEDIA_FILE.TYPE.STANDARD_FILE: 
      if(row == null) { 
       standardFileViewHolder = new StandardFileViewHolder(); 
       row = inflater.inflate(R.layout.listview_mixed_folder_row, parent, false); 
       standardFileViewHolder.icon = (ImageView)row.findViewById(R.id.filetype_icon); 
       standardFileViewHolder.tempTV = (TextView)row.findViewById(R.id.listview_mixed_folder_row_test_tv); 
       row.setTag(standardFileViewHolder); 
      } 
      else { 
       standardFileViewHolder = (StandardFileViewHolder)row.getTag(); 
      } 
      standardFileViewHolder.icon.setImageDrawable(getItem(position).getDrawable()); 
      standardFileViewHolder.tempTV.setText(getItem(position).getName()); 
      standardFileViewHolder.tempTV.setSelected(true); 
      break; 
     case Constants.MEDIA_FILE.TYPE.MUSIC_FILE: 
      if(getItemViewState(position) == Constants.MEDIA_FILE.TYPE.STATE.PLAYING) { 
       if(row == null || (row !=null && row.getTag() instanceof MusicFileStoppedViewHolder)) { 
        musicFilePlayingHolder = new MusicFilePlayingViewHolder(); 
        row = inflater.inflate(R.layout.listview_music_file_playing_row, parent, false); 
        musicFilePlayingHolder.icon = (ImageView)row.findViewById(R.id.filetype_icon); 
        musicFilePlayingHolder.songName = (TextView)row.findViewById(R.id.row_title_tv); 
        musicFilePlayingHolder.playButton = (Button)row.findViewById(R.id.row_play_button); 
        musicFilePlayingHolder.durationTV = (TextView)row.findViewById(R.id.row_duration_tv); 
        musicFilePlayingHolder.progressBar = (ProgressBar)row.findViewById(R.id.folder_progress_bar); 
        row.setTag(musicFilePlayingHolder); 
       } 
       else { 
        musicFilePlayingHolder = (MusicFilePlayingViewHolder)row.getTag(); 
       } 
       musicFilePlayingHolder.icon.setImageDrawable(getItem(position).getDrawable()); 
       musicFilePlayingHolder.songName.setText(getItem(position).getName()); 
       musicFilePlayingHolder.songName.setSelected(true); 
       musicFilePlayingHolder.durationTV.setText(mActivity.formattedMillis(getItem(position).getDuration())); 
       musicFilePlayingHolder.progressBar.setMax(getItem(position).getDuration()); 
       musicFilePlayingHolder.progressBar.setProgress(getItem(position).getProgress()); 
       musicFilePlayingHolder.playButton.setOnClickListener(new OnClickListener() { 

        @Override 
        public void onClick(View arg0) { 
         Log.e("clicked", getItem(position).getName()); 
         Bundle bun = new Bundle(); 
         bun.putString(Constants.BUNDLE_KEYS.PLAY_FILES, getItem(position).getPath()); 
         Message message = Message.obtain(null, Constants.OP_CODE.PLAY_FILES); 
         message.setData(bun); 
         try { 
          mActivity.mService.send(message); 
         } 
         catch (RemoteException re) { 
          re.printStackTrace(); 
         } 
        } 

       }); 
      } 
      else if(getItemViewState(position) == Constants.MEDIA_FILE.TYPE.STATE.STOPPED) { 
       if(row == null || (row !=null && row.getTag() instanceof MusicFilePlayingViewHolder)) { 
        musicFileStoppedHolder = new MusicFileStoppedViewHolder(); 
        row = inflater.inflate(R.layout.listview_music_file_stopped_row, parent, false); 
        musicFileStoppedHolder.icon = (ImageView)row.findViewById(R.id.filetype_icon); 
        musicFileStoppedHolder.songName = (TextView)row.findViewById(R.id.row_title_tv); 
        musicFileStoppedHolder.playButton = (Button)row.findViewById(R.id.row_play_button); 
        musicFileStoppedHolder.durationTV = (TextView)row.findViewById(R.id.row_duration_tv); 

        row.setTag(musicFileStoppedHolder); 
       } 
       else { 
        musicFileStoppedHolder = (MusicFileStoppedViewHolder)row.getTag(); 
       } 
       musicFileStoppedHolder.icon.setImageDrawable(getItem(position).getDrawable()); 
       musicFileStoppedHolder.songName.setText(getItem(position).getName()); 
       musicFileStoppedHolder.songName.setSelected(true); 
       musicFileStoppedHolder.durationTV.setText(mActivity.formattedMillis(getItem(position).getDuration())); 
       musicFileStoppedHolder.playButton.setOnClickListener(new OnClickListener() { 

        @Override 
        public void onClick(View arg0) { 
         Log.e("clicked", getItem(position).getName()); 
         Bundle bun = new Bundle(); 
         bun.putString(Constants.BUNDLE_KEYS.PLAY_FILES, getItem(position).getPath()); 
         Message message = Message.obtain(null, Constants.OP_CODE.PLAY_FILES); 
         message.setData(bun); 
         try { 
          mActivity.mService.send(message); 
         } 
         catch (RemoteException re) { 
          re.printStackTrace(); 
         } 
        } 

       }); 
      } 
      break; 
     } 

     if(!getItem(position).wasAnimatedIn()) { 
      row.startAnimation(getItem(position).getGoingIn()); 
     } 
     else if (!getItem(position).wasAnimatedOut()) { 
      Animation outAnim = getItem(position).getGoingOut(); 
      outAnim.setAnimationListener(new AnimationListener() { 

       @Override 
       public void onAnimationEnd(Animation animation) { 
        data.remove(getItem(position)); 
       } 

       @Override 
       public void onAnimationRepeat(Animation animation) {} 

       @Override 
       public void onAnimationStart(Animation animation) {} 
      }); 
      row.startAnimation(outAnim); 
     } 
     return row; 
    } 

服務可能會調用此適配器上的其中一種方法:

public void activatePlayingState(int positionInPage) { 
     if(positionInPage < getCount()) { 
      ListViewDataItem lvDataItem = getItem(positionInPage); 
      lvDataItem.setState(Constants.MEDIA_FILE.TYPE.STATE.PLAYING); 
      notifyDataSetChanged(); 
     } 
    } 

回答

1

位置並不意味着以與ID相同的方式穩定。這方面的一個例子是選擇模式。如果您的ID不穩定,則列表中的任何更改(移動/添加/移除項目)都會打亂檢查的位置,因爲確實沒有辦法存儲所有項目以跟蹤每個項目的位置。順便說一句,雖然與你的問題沒有真正的關係,但如果你有穩定的ID並且物品移動超過20個物品左右,他們只需清除物品的檢查狀態。在寫代碼的時候,我會假設他們認爲遍歷〜20項來檢查位置v.id是所有可以以足夠有效的方式執行的。

就你而言,雖然你可能不會將物品移動到自己周圍,但從某種意義上說撥打notifyDataSetChanged()時,內部物品會四處移動。 AdapterView.AdapterDataSetObserver#onChanged顯示當您撥打notifyDataSetChanged()時發生的情況。

爲了解決問題,您可以使用stableIds而不是位置來解決問題。要實現這一點,請更改getItemId(int position)方法以返回該位置項目的唯一標識。然後,覆蓋hasStableIds()以返回true。這裏是hasStableIds()BaseAdapter#hasStableIds()的文檔。現在,您可以將ID傳遞給您的服務。你已經將一個捆綁包傳遞給你的服務,所以只需要在這個ID。另外請注意,您需要爲具有需要跟蹤的狀態的項目存儲ID。例如,像添加一個ArrayList一樣簡單。當你的服務執行任何操作時,它可以使用id調用你的activatePlayingState方法,而不是可能過時的位置(記住將該參數從int更改爲long)。在getView中,您可以使用getItemId(int position)將激活的ID與當前的getView項目進行比較,並按照預期設置該項目的視圖。

+0

你好,非常感謝你花時間閱讀我的問題。我讀了你的答案很多次,但我認爲它不能解決問題。順便說一下,在我閱讀你的答案的那一刻,我已將適配器更改爲ListAdapter實現(而不是BaseAdapter擴展),問題依然存在。我將在這裏發佈鏈接到更新的問題。我也沒有在這裏提出所有關於我的問題的事實,所以我會提高你的答案並將其標記爲正確的答案。 – jfv

+0

編輯時間結束:(底線是,在getView方法中,我們必須使用位置變量作爲我們所在視圖的標識符,並且即時使用一個保存每個視圖的數據的數組列表,這個索引是唯一的。 bundle已經發送一個唯一的id,文件絕對路徑,其唯一性由底層文件結構保證。Thx再次 – jfv

+0

在這裏發佈了一個關於這個問題的更新問題http://stackoverflow.com/questions/19564012/listadapter-getview-與-錯誤值換位置 – jfv

相關問題