这个问题从根本上解决了与旧版本 重写相同的问题,因为代码更具可读性,并且我将适配器从 BaseAdapter 扩展更改为 ListAdapter 接口实现(这毫无意义)。
我对适配器的 getView 方法中的位置变量有这个奇怪的问题。这 6 种不同视图类型中的 4 种,在其中有一个按钮。该按钮向服务发送消息(在服务上引发一些异步内容),并且在无限时间之后,此适配器会收到由服务引发的 notifyDataSetChanged()。
当我向发送消息的按钮发送垃圾邮件时,问题就出现了。如果我垃圾邮件的速度足够快,错误的数据将被发送到服务。我认为问题在于,在垃圾邮件期间,我将在 notifyDataSetChanged() 期间点击按钮,因为如果我对服务正在使用的方法的调用进行评论,则不会发生这种不一致。此外,如果我不向按钮发送垃圾邮件(例如点击之间的 1 秒延迟),它将正常工作。
奇怪的是,在 getView 方法中,getItem(position) 调用将返回不同的项目。它将返回正确的项目来构建视图本身,但可能会将错误的项目返回到视图中按钮的 onClickListener。
这是完整的适配器类:
public class ListViewFolderAdapter implements ListAdapter{
private static final int MAX_COUNT = 6;
private MainActivity mActivity;
private ArrayList<ListViewDataItem> data = null;
private String[] selected;
private MainPagerAdapter mainPagerAdapter;
private int listPosition;
private String dirName;
private final DataSetObservable mDataSetObservable;
private LayoutInflater inflater;
public ListViewFolderAdapter(MainActivity mActivity, MainPagerAdapter mainPagerAdapter, int listPosition,
String dirName, ArrayList<ListViewDataItem> data) {
this.mActivity=mActivity;
this.mainPagerAdapter = mainPagerAdapter;
this.listPosition = listPosition;
this.data = data;
this.dirName=dirName;
this.inflater = mActivity.getLayoutInflater();
this.mDataSetObservable = new DataSetObservable();
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
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_standard_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.STANDARD_FILE:
if(row == null) {
standardFileViewHolder = new StandardFileViewHolder();
row = inflater.inflate(R.layout.listview_standard_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_DIRECTORY_PLAYING_STATE:
if(row == null) {
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.setTag(getItem(position));
musicFolderPlayingHolder.playButton.setOnClickListener(new MyOnClickListener());
break;
case Constants.MEDIA_FILE.TYPE.MUSIC_DIRECTORY_STOPPED_STATE:
if(row == null) {
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.setTag(getItem(position));
musicFolderStoppedHolder.playButton.setOnClickListener(new MyOnClickListener());
break;
case Constants.MEDIA_FILE.TYPE.MUSIC_FILE_PLAYING_STATE:
if(row == null) {
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.music_file_playing_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.setTag(getItem(position));
musicFilePlayingHolder.playButton.setOnClickListener(new MyOnClickListener());
break;
case Constants.MEDIA_FILE.TYPE.MUSIC_FILE_STOPPED_STATE:
if(row == null) {
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.music_file_stopped_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.setTag(getItem(position));
musicFileStoppedHolder.playButton.setOnClickListener(new MyOnClickListener());
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);
}
Log.e("getView" + getItem(position).getName(), "pos: " + position);
return row;
}
public void insert(ListViewDataItem object, int index) {
data.set(index, object);
object.setAnimatedInFalse();
}
public void removeWithAnimation(String fileName) {
for(int i = 0 ; i < data.size(); i++) {
if(data.get(i).getName().compareToIgnoreCase(fileName) == 0) {
getItem(i).setAnimatedOutFalse();
notifyDataSetChanged();
selectItem(i);
return;
}
}
}
private void selectItem(int itemPosition) {
mainPagerAdapter.setSelectedItemInList(listPosition, itemPosition);
}
static class StandardFolderViewHolder {
ImageView icon;
TextView tempTV;
TextView tempTV2;
}
static class StandardFileViewHolder {
ImageView icon;
TextView tempTV;
TextView tempTV2;
}
static class MusicFileStoppedViewHolder {
ImageView icon;
TextView songName;
Button playButton;
TextView durationTV;
}
static class MusicFilePlayingViewHolder {
ImageView icon;
TextView songName;
Button playButton;
TextView durationTV;
ProgressBar progressBar;
}
static class MusicFolderStoppedViewHolder {
ImageView icon;
TextView songName;
Button playButton;
TextView durationTV;
}
static class MusicFolderPlayingViewHolder {
ImageView icon;
TextView songName;
Button playButton;
TextView durationTV;
ProgressBar progressBar;
}
void setSelectedPosition(String[] selection) {
this.selected=selection;
notifyDataSetChanged();
}
public String[] getSelectedPosition() {
return this.selected;
}
public String getDirName() {
return this.dirName;
}
@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;
}
/**
* must return 0 <= int < getCount()
*/
@Override
public int getItemViewType(int position) {
return getItem(position).getType();
}
public void notifyDataSetChanged() {
mDataSetObservable.notifyChanged();
}
@Override
public boolean hasStableIds() {
return true;
}
@Override
public boolean isEmpty() {
return getCount() == 0;
}
@Override
public void registerDataSetObserver(DataSetObserver observer) {
mDataSetObservable.registerObserver(observer);
}
@Override
public void unregisterDataSetObserver(DataSetObserver observer) {
mDataSetObservable.unregisterObserver(observer);
}
@Override
public boolean areAllItemsEnabled() {
return true;
}
@Override
public boolean isEnabled(int position) {
return true;
}
public void updateTypeAndDuration(int position, int type, int duration) {
ListViewDataItem lvDataItem = getItem(position);
lvDataItem.setType(type);
lvDataItem.setDuration(duration);
notifyDataSetChanged();
}
public void updateProgressInFile(int positionInPage, int maxProgress, int progress) {
if(positionInPage < getCount()) {
ListViewDataItem lvDataItem = getItem(positionInPage);
lvDataItem.setDuration(maxProgress);
lvDataItem.setProgress(progress);
notifyDataSetChanged();
}
}
public void activatePlayingState(int positionInPage) {
if(positionInPage < getCount()) {
ListViewDataItem lvDataItem = getItem(positionInPage);
if(lvDataItem.getType() == Constants.MEDIA_FILE.TYPE.MUSIC_DIRECTORY_STOPPED_STATE) {
lvDataItem.setType(Constants.MEDIA_FILE.TYPE.MUSIC_DIRECTORY_PLAYING_STATE);
notifyDataSetChanged();
}
else if(lvDataItem.getType() == Constants.MEDIA_FILE.TYPE.MUSIC_FILE_STOPPED_STATE) {
lvDataItem.setType(Constants.MEDIA_FILE.TYPE.MUSIC_FILE_PLAYING_STATE);
notifyDataSetChanged();
}
}
}
public void clearPlayState() {
boolean stateChanged = false;
for(ListViewDataItem lvDataItem : data) {
if(lvDataItem.getType() == Constants.MEDIA_FILE.TYPE.MUSIC_DIRECTORY_PLAYING_STATE) {
lvDataItem.setType(Constants.MEDIA_FILE.TYPE.MUSIC_DIRECTORY_STOPPED_STATE);
stateChanged = true;
}
else if(lvDataItem.getType() == Constants.MEDIA_FILE.TYPE.MUSIC_FILE_PLAYING_STATE) {
lvDataItem.setType(Constants.MEDIA_FILE.TYPE.MUSIC_FILE_STOPPED_STATE);
stateChanged = true;
}
}
if(stateChanged) {
notifyDataSetChanged();
}
}
private class MyOnClickListener implements OnClickListener {
@Override
public void onClick(View v) {
Log.e("Clicked", (String)((ListViewDataItem)v.getTag()).getName());
Bundle bun = new Bundle();
bun.putString(Constants.BUNDLE_KEYS.PLAY_FILES, (String)((ListViewDataItem)v.getTag()).getPath());
Message message = Message.obtain(null, Constants.OP_CODE.PLAY_FILES);
message.setData(bun);
try {
mActivity.mService.send(message);
}
catch (RemoteException re) {
re.printStackTrace();
}
}
}
}
这是我在位置 1 向视图内的按钮发送垃圾邮件的 LogCat 转储,文件名是 02 Maniac.flac
10-24 11:39:06.929: E/Clicked(21489): 02 Maniac.flac
10-24 11:39:06.949: E/TRYING TO PLAY(21489): /mnt/sdcard/Music/Caravan Palace/Caravan Palace - Panic (2012) FLAC/02 Maniac.flac
10-24 11:39:06.949: E/getView 01 Queens.flac(21489): pos: 0
10-24 11:39:07.049: E/getView 02 Maniac.flac(21489): pos: 1
10-24 11:39:07.069: E/getView 03 The dirty side of the street.flac(21489): pos: 2
10-24 11:39:07.069: E/getView 04 12 June 3049.flac(21489): pos: 3
10-24 11:39:07.069: E/getView 05 Rock it for me.flac(21489): pos: 4
10-24 11:39:07.069: E/getView 06 Clash.flac(21489): pos: 5
10-24 11:39:07.169: E/getView 01 Queens.flac(21489): pos: 0
10-24 11:39:07.169: E/getView 02 Maniac.flac(21489): pos: 1
10-24 11:39:07.169: E/getView 03 The dirty side of the street.flac(21489): pos: 2
10-24 11:39:07.179: E/getView 04 12 June 3049.flac(21489): pos: 3
10-24 11:39:07.179: E/getView 05 Rock it for me.flac(21489): pos: 4
10-24 11:39:07.179: E/getView 06 Clash.flac(21489): pos: 5
10-24 11:39:07.239: E/Clicked(21489): 02 Maniac.flac
10-24 11:39:07.259: E/Clicked(21489): 02 Maniac.flac
10-24 11:39:07.269: E/getView 01 Queens.flac(21489): pos: 0
10-24 11:39:07.269: E/TRYING TO PLAY(21489): /mnt/sdcard/Music/Caravan Palace/Caravan Palace - Panic (2012) FLAC/02 Maniac.flac
10-24 11:39:07.289: E/getView 02 Maniac.flac(21489): pos: 1
10-24 11:39:07.299: E/getView 03 The dirty side of the street.flac(21489): pos: 2
10-24 11:39:07.329: E/getView 04 12 June 3049.flac(21489): pos: 3
10-24 11:39:07.339: E/getView 05 Rock it for me.flac(21489): pos: 4
10-24 11:39:07.339: E/getView 06 Clash.flac(21489): pos: 5
10-24 11:39:07.409: W/MediaPlayer(21489): mediaplayer went away with unhandled events
10-24 11:39:07.419: E/TRYING TO PLAY(21489): /mnt/sdcard/Music/Caravan Palace/Caravan Palace - Panic (2012) FLAC/02 Maniac.flac
10-24 11:39:07.489: E/getView 01 Queens.flac(21489): pos: 0
10-24 11:39:07.499: E/getView 02 Maniac.flac(21489): pos: 1
10-24 11:39:07.499: E/getView 03 The dirty side of the street.flac(21489): pos: 2
10-24 11:39:07.519: E/getView 04 12 June 3049.flac(21489): pos: 3
10-24 11:39:07.519: E/getView 05 Rock it for me.flac(21489): pos: 4
10-24 11:39:07.539: E/getView 06 Clash.flac(21489): pos: 5
10-24 11:39:07.599: E/Clicked(21489): 05 Rock it for me.flac
10-24 11:39:07.619: E/getView 01 Queens.flac(21489): pos: 0
10-24 11:39:07.629: E/getView 02 Maniac.flac(21489): pos: 1
10-24 11:39:07.629: E/getView 03 The dirty side of the street.flac(21489): pos: 2
10-24 11:39:07.639: E/getView 04 12 June 3049.flac(21489): pos: 3
10-24 11:39:07.639: E/getView 05 Rock it for me.flac(21489): pos: 4
10-24 11:39:07.639: E/getView 06 Clash.flac(21489): pos: 5
10-24 11:39:07.699: E/Clicked(21489): 06 Clash.flac
10-24 11:39:07.709: E/Clicked(21489): 02 Maniac.flac
10-24 11:39:07.789: E/getView 01 Queens.flac(21489): pos: 0
10-24 11:39:07.799: E/getView 02 Maniac.flac(21489): pos: 1
10-24 11:39:07.809: E/getView 03 The dirty side of the street.flac(21489): pos: 2
10-24 11:39:07.809: E/TRYING TO PLAY(21489): /mnt/sdcard/Music/Caravan Palace/Caravan Palace - Panic (2012) FLAC/05 Rock it for me.flac
10-24 11:39:07.829: E/getView 04 12 June 3049.flac(21489): pos: 3
10-24 11:39:07.859: E/getView 05 Rock it for me.flac(21489): pos: 4
10-24 11:39:07.869: E/getView 06 Clash.flac(21489): pos: 5
10-24 11:39:08.039: D/dalvikvm(21489): GC_CONCURRENT freed 185K, 45% free 3396K/6087K, external 327K/839K, paused 5ms+6ms
10-24 11:39:08.049: E/getView 01 Queens.flac(21489): pos: 0
10-24 11:39:08.049: E/getView 02 Maniac.flac(21489): pos: 1
10-24 11:39:08.059: E/getView 03 The dirty side of the street.flac(21489): pos: 2
10-24 11:39:08.059: E/getView 04 12 June 3049.flac(21489): pos: 3
10-24 11:39:08.069: E/getView 05 Rock it for me.flac(21489): pos: 4
10-24 11:39:08.069: E/getView 06 Clash.flac(21489): pos: 5
10-24 11:39:08.129: E/Clicked(21489): 06 Clash.flac
10-24 11:39:08.129: E/Clicked(21489): 06 Clash.flac
10-24 11:39:08.159: E/Clicked(21489): 02 Maniac.flac
10-24 11:39:08.239: E/getView 01 Queens.flac(21489): pos: 0
10-24 11:39:08.249: E/getView 02 Maniac.flac(21489): pos: 1
10-24 11:39:08.259: E/TRYING TO PLAY(21489): /mnt/sdcard/Music/Caravan Palace/Caravan Palace - Panic (2012) FLAC/06 Clash.flac
10-24 11:39:08.259: E/getView 03 The dirty side of the street.flac(21489): pos: 2
10-24 11:39:08.259: E/getView 04 12 June 3049.flac(21489): pos: 3
10-24 11:39:08.289: E/getView 05 Rock it for me.flac(21489): pos: 4
10-24 11:39:08.319: E/getView 06 Clash.flac(21489): pos: 5
10-24 11:39:08.409: E/getView 01 Queens.flac(21489): pos: 0
10-24 11:39:08.419: E/getView 02 Maniac.flac(21489): pos: 1
10-24 11:39:08.419: E/getView 03 The dirty side of the street.flac(21489): pos: 2
10-24 11:39:08.419: E/getView 04 12 June 3049.flac(21489): pos: 3
10-24 11:39:08.429: E/getView 05 Rock it for me.flac(21489): pos: 4
10-24 11:39:08.429: E/getView 06 Clash.flac(21489): pos: 5
您可以看到 getView 方法被正确调用,每个项目的位置都正确:
10-24 11:39:06.949: E/getView 01 Queens.flac(21489): pos: 0
10-24 11:39:07.049: E/getView 02 Maniac.flac(21489): pos: 1
10-24 11:39:07.069: E/getView 03 The dirty side of the street.flac(21489): pos: 2
10-24 11:39:07.069: E/getView 04 12 June 3049.flac(21489): pos: 3
10-24 11:39:07.069: E/getView 05 Rock it for me.flac(21489): pos: 4
10-24 11:39:07.069: E/getView 06 Clash.flac(21489): pos: 5
但是在单击按钮时,getItem 方法有时会返回错误的项目(回想一下我的垃圾邮件 02 Maniac.flac)
10-24 11:39:07.699: E/Clicked(21489): 06 Clash.flac
10-24 11:39:07.709: E/Clicked(21489): 02 Maniac.flac
--
10-24 11:39:07.599: E/Clicked(21489): 05 Rock it for me.flac
--
10-24 11:39:08.129: E/Clicked(21489): 06 Clash.flac
10-24 11:39:08.129: E/Clicked(21489): 06 Clash.flac
10-24 11:39:08.159: E/Clicked(21489): 02 Maniac.flac