Android 基本适配器';s getView的位置错误
适配器的getView方法中的位置变量有一个奇怪的问题。 在这6种不同的视图类型中,有4种在其内部有一个按钮。该按钮向服务发送一条消息(引发服务上的一些异步内容),在此后的不确定时间内,该适配器将获得由该服务引发的notifyDataSetChanged() 当我向发送消息的按钮发送垃圾邮件时,问题就出现了。如果我发垃圾邮件的速度足够快,错误的位置将被发送到服务。我认为问题在于,在垃圾邮件期间,我会在notifyDataSetChanged()期间点击按钮,因为如果我对服务使用的方法的调用进行注释,这种不一致性就不会发生 这是我第一次使用BaseAdapter,我遵循了这本不错的教程: 下面是我认为与查明问题相关的代码部分 此适配器管理6种不同的视图类型:Android 基本适配器';s getView的位置错误,android,listview,android-listview,android-adapter,Android,Listview,Android Listview,Android Adapter,适配器的getView方法中的位置变量有一个奇怪的问题。 在这6种不同的视图类型中,有4种在其内部有一个按钮。该按钮向服务发送一条消息(引发服务上的一些异步内容),在此后的不确定时间内,该适配器将获得由该服务引发的notifyDataSetChanged() 当我向发送消息的按钮发送垃圾邮件时,问题就出现了。如果我发垃圾邮件的速度足够快,错误的位置将被发送到服务。我认为问题在于,在垃圾邮件期间,我会在notifyDataSetChanged()期间点击按钮,因为如果我对服务使用的方法的调用进行注
private static final int MAX_COUNT = 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();
}
}
public void activatePlayingState(内部位置页面){
if(positionInPage
位置不像ID那样稳定。选择模式就是一个例子。如果您的ID不稳定,那么列表中的任何更改(移动/添加/删除项目)都会打乱已检查的位置,因为要存储所有项目以跟踪每个项目的去向,实在是不可能的。顺便说一句,虽然与您的问题不太相关,但是如果您确实有稳定的ID,并且一个项目移动了20多个项目,那么它们只会清除项目的选中状态。在编写代码时,我假设他们想遍历~20个项目来检查位置v。id是所有能够以足够有效的方式执行的功能
在您的情况下,虽然您可能不会在自己周围移动项目,但在某种意义上,当您调用notifydatasetchange()
时,项目会在内部移动。显示调用notifyDataSetChanged()
时发生的确切情况
为了切中要害,您可以使用stableIds而不是positions来解决问题。要实现这一点,请更改
getItemId(int-position)
方法以返回该位置项的唯一id。然后,重写hasStableIds()以返回true。以下是hasStableIds()
的文档。现在,您可以将id传递给您的服务。您已经将一个包传递给您的服务,因此只需将id放入其中。还请注意,您需要存储具有需要跟踪的状态的项目的ID。这就像将ID添加到ArrayList中一样简单。当您的服务执行它所做的任何操作时,它可以使用id而不是可能的陈旧位置(记住将该参数从int更改为long)调用您的activatePlayingState
方法。然后,在getView
中,您可以使用getItemId(int位置)
将激活的id与当前getView项进行比较,并按预期设置该项的视图 您好,非常感谢您抽出时间阅读我的问题。我读了你的答案很多次,但我认为它并不能解决问题。顺便说一下,在阅读您的答案时,我已经将适配器更改为ListAdapter实现(而不是BaseAdapter扩展),问题仍然存在。我将在这里发布更新问题的链接。我也没有在这里给出我问题中的所有事实,因此我将投票并将您的答案标记为正确答案。编辑时间结束:(底线是,在getView方法中,我们必须使用位置变量作为我们所处视图的标识符,并且im使用一个arraylist来保存每个视图的数据,该数据由唯一的索引标识。此外,捆绑包已经发送了一个唯一的id,即文件绝对路径,其唯一性由底层文件结构保证。Thx再次在这里提出关于这个问题的最新问题