BaseAdapter的getView得到错误的位置 [英] BaseAdapter's getView getting wrong position

查看:192
本文介绍了BaseAdapter的getView得到错误的位置的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我与适配器的getView方法中位置变量这个奇怪的问题。
这些6种不同视图类型的4,得到了在他们里面的按钮。该按钮将消息发送到一个服务(挑起上的服务的一些异步的东西),和时间后无限期量内,该适配器得到一个notifyDataSetChanged()由服务挑起。

I have this weird problem with position variable inside getView method of the adapter. 4 of those 6 different view types, got a button inside them. That button sends a message to a service (provoking some async stuff on the service), and within an indefinite amount of time after, this adapter gets a notifyDataSetChanged() provoked by the service.

问题显示了当我垃圾邮件的发送消息的按钮。如果我在垃圾邮件速度不够快,错误的位置将被发送到服务。我认为这个问题是垃圾邮件时,我会notifyDataSetChanged()过程中按下按钮,因为如果我发表评论,该服务使用方法这一号召,这种不一致不会发生。

The problem shows when i spam the button that sends the message. If i spam it fast enough, the wrong position will be sent to the service. I think the problem is that during the spam, i will hit the button during a notifyDataSetChanged(), because if i comment that call on the methods that the service is using, this inconsistency wont happen.

这是我第一次使用BaseAdapter,我跟着这个漂亮的教程:
底座适配器教程

This is the first time i use BaseAdapter, and i followed this nice tutorial: Base Adapter Tutorial

下面是我认为可以是相关的确定问题的code部分。

Below are the code parts that i think can be relevant to pinpoint the issue.

即使世界6种不同的视图类型由该适配器管理:

Theres 6 different view types being managed by this adapter:

private static final int MAX_COUNT = 6;

和这里的方法IM压倒一切的:

And here are the methods im overriding:

@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方法:

And heres the getView method:

@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;
    }

的方法之一,该适配器上,该服务可以调用

One of the methods, on this adapter, that the service may call:

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


推荐答案

位置并不意味着在相同的方式ID是稳定的。这样的一个例子是选择模式。如果你的IDS并不稳定,在列表中的任何变化(移动/添加/删除项目)将破坏检查位置因为实在没办法短期存储的所有项目跟踪每个去的。顺便说一句,虽然没有真正涉及到您的问题,如果你有稳定的ID和一个项目移动超过20个项目左右,他们只是清除的项目的选中状态。在code写的时候,我会假设,他们认为穿越〜20个项目,检查位置诉ID为所有可能以高效的方式足以进行。

Positions aren't meant to be stable in the same way ids are. An example of this is choice modes. If your ids aren't stable, any changes in the list (moving/adding/removing items) will upset checked positions since there is really no way short of storing all items to track where each goes. Incidentally though not really related to your issue, if you DO have stable ids and an item moves more than 20 items or so, they just clear the item's checked state. At the time the code was written, I would assume they thought traversing ~20 items to check position v. id was all that could be performed in an efficient enough way.

在你的情况,而你可能不动自己周围的物品,内部项目你什么时候打电话 notifyDataSetChanged()在一定意义上走动。 <一href=\"http://grep$c$c.com/file/repository.grep$c$c.com/java/ext/com.google.android/android/4.3_r2.1/android/widget/AdapterView.java#AdapterView.AdapterDataSetObserver.onChanged%28%29\"相对=nofollow> AdapterView.AdapterDataSetObserver#调用onChanged显示当你打电话时发生的事情 notifyDataSetChanged()

In your case, while you may not be moving items around yourself, internally items DO move around when you call notifyDataSetChanged() in a sense. AdapterView.AdapterDataSetObserver#onChanged shows exactly what happens when you call notifyDataSetChanged().

要切入正题,你可以通过使用stableIds,而不是位置解决您的问题。要实现的是,改变你的 getItemId(INT位置)方法在该位置返回一个唯一的ID的项目。然后,覆盖 hasStableIds()返回true。下面是 hasStableIds的文档() BaseAdapter#hasStableIds()。现在,你就可以上的标识,你的服务能够通过。您已经传递了一个包为您服务,所以只是把ID在。另外请注意,你需要存储的ID与您需要跟踪状态的项目。这是因为添加到IDS例如一个ArrayList一样简单。当你的服务做什么这样做,可以使用ID而不是一个可能是陈旧的位置,然后打电话给你的 activatePlayingState 办法(记住该参数改变从int长)。在 getView ,然后你可以比较使用 getItemId(INT位置)当前getView项目和设置激活ID如预期的观点该项目。

To get to the point, you can fix your issue by using stableIds instead of positions. To implement that, change your getItemId(int position) method to return a unique id for the item at that position. Then, override hasStableIds() to return true. Here's the docs for hasStableIds() BaseAdapter#hasStableIds(). Now, you'll be able pass on the id to your service. You're already passing a bundle to your service, so just put the id in that. Also note that you'll need to store the ids for the items with a state you need to track. That's as simple as adding the ids to an ArrayList for example. When your service does whatever it does, it can then call your activatePlayingState method using the id instead of a possibly stale position (remember to change that parameter from int to long). In getView, you can then compare the activated id with the current getView item using getItemId(int position) and setting the views for that item as expected.

这篇关于BaseAdapter的getView得到错误的位置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆