【问题标题】:IndexOutOfBoundsException in RecyclerAdapter with two view types具有两种视图类型的 RecyclerAdapter 中的 IndexOutOfBoundsException
【发布时间】:2016-11-07 02:37:14
【问题描述】:

您会注意到,在下面的 feedItems.adAll(adItems) 行下方,我已经注释掉了几行代码。每当出现这个异常时,我都可以证明 feedItems 列表是空的。

这是我的 RecyclerAdapter:

public class FeedRecyclerAdapter extends LoadingRowRecyclerAdapter {

    private static final int VIEW_TYPE_FEED = 1;
    private static final int VIEW_TYPE_AD = 2;

    private final Context context;
    private final List<Feed> feedItems;
    private final ImageLoader feedItemImageLoader;
    private FeedItemClickListener feedItemClickListener;
    private boolean isLongPressed = false;

    public FeedRecyclerAdapter(Context context, List<Feed> feedItems, ImageLoader feedItemImageLoader, List<Feed> adItems) {
        this.context = context;
        this.feedItems = feedItems;
        this.feedItemImageLoader = feedItemImageLoader;
        feedItems.addAll(adItems);
//        if (adItems.isEmpty()) {
//            Log.d(getClass().toString(), "IndexOutOfBoundsException!");
//        }
    }

    // Differentiate between feedItem views and nativeAds
    @Override
    public int getItemViewType(int position) {
        int viewType = 1;
        if ((position % 9 == 0) && position != 1) viewType = 2;
        return viewType;
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        switch (viewType) {
            case VIEW_TYPE_FEED:
                return new FeedViewHolder(new FeedItemView(context));
            case VIEW_TYPE_AD:
                return new AdViewHolder(new AdItemView(context));
        }
        return super.onCreateViewHolder(parent, viewType);
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
        if (getItemViewType(position) == VIEW_TYPE_FEED) {
            bindFeedItemView((FeedViewHolder) viewHolder, position);
        } else {
            bindAdItemView((AdViewHolder) viewHolder);
        }
    }

    @Override
    protected int getContentDataSize() {
        return feedItems.size();
    }

    @Override
    protected int getViewType(int position) {
        if (position == 1) {
            return VIEW_TYPE_FEED;
        } else {
            return VIEW_TYPE_AD;
        }
    }

    class FeedViewHolder extends RecyclerView.ViewHolder {

        FeedItemView feedItemView;

        public FeedViewHolder(FeedItemView view) {
            super(view);
            this.feedItemView = view;
        }

    }

    class AdViewHolder extends RecyclerView.ViewHolder {

        AdItemView adItemView;

        public AdViewHolder(AdItemView view) {
            super(view);
            this.adItemView = view;
        }

    }

    private NativeAd nativeAd;
    private AdChoicesView adChoicesView;

    private void showNativeAd(AdViewHolder viewHolder){
        AdSettings.addTestDevice("STRING");
        nativeAd = new NativeAd(context, "STRING");
        nativeAd.setAdListener(new AdListener() {

            @Override
            public void onError(Ad ad, AdError adError) {

            }

            @Override
            public void onAdLoaded(Ad ad) {

                final AdItemView adItemView = viewHolder.adItemView;

                // Setting the Text
                adItemView.nativeAdSocialContext.setText(nativeAd.getAdSocialContext());
                adItemView.nativeAdCallToAction.setText(nativeAd.getAdCallToAction());
                adItemView.nativeAdTitle.setText(nativeAd.getAdTitle());
                adItemView.nativeAdBody.setText(nativeAd.getAdBody());

                // Downloading and setting the ad icon
                NativeAd.Image adIcon = nativeAd.getAdIcon();
                NativeAd.downloadAndDisplayImage(adIcon, adItemView.nativeAdIcon);

                // Download and setting the cover image
                /*NativeAd.Image adCoverImage = nativeAd.getAdCoverImage();*/
                adItemView.nativeAdMedia.setNativeAd(nativeAd);

                // Add adChoices icon
                if (adChoicesView == null) {
                    adChoicesView = new AdChoicesView(context, nativeAd, true);
                    adItemView.addView(adChoicesView, 0);
                }

                nativeAd.registerViewForInteraction(adItemView);

            }

            @Override
            public void onAdClicked(Ad ad) {

            }
        });

        nativeAd.loadAd();
    }

    // For Ad Objects
    private void bindAdItemView(AdViewHolder viewHolder) {

        showNativeAd(viewHolder);

    }

    // For Feed Objects
    private void bindFeedItemView(FeedViewHolder viewHolder, int position) {
        final FeedItemView feedItemView = viewHolder.feedItemView;
        final Feed feedDesign = feedItems.get(position);

        // TODO we can probably conditionally show or hide these based on the type of feed item, same as in FeedActivitySingle
        feedItemView.showOrHideEditButton(true);
        feedItemView.showOrHideBuyButton(false);
        feedItemView.showOrHideFlipButton(false);
        feedItemView.showOrHidePriceText(false);

        // Set the results into TextViews
        feedItemView.setProductPriceText(String.valueOf(feedDesign.getDesign().getPrice()));
        feedItemView.setDownloadsText(String.valueOf(feedDesign.getDesign().getDownloadCount()));
        feedItemView.setLikesText(String.valueOf(feedDesign.getDesign().getLikesCount()));
        feedItemView.setUsernameText(feedDesign.getDesign().getAuthor().getUsername());
        feedItemView.setTimestampText(feedDesign.getTimestampText());
        feedItemView.getSaveImage().setImageResource(feedDesign.isInPersonalGallery() ? R.drawable.ic_action_saved : R.drawable.ic_not_saved);
        feedItemView.getLikeImage().setImageResource(feedDesign.isLiked() ? R.drawable.ic_action_like_feed_full : R.drawable.ic_action_like_feed);

        feedItemView.getTrashImage().setVisibility(ParseHelper.isCurrentUser(feedDesign.getDesign().getAuthor().getObjectId()) ? View.VISIBLE : View.GONE);
        feedItemView.getFeedSocialShareImage().setVisibility(View.VISIBLE);

        feedItemImageLoader.DisplayImage(feedDesign.getDesign().getCompressedImage().getUrl(), feedItemView.getImage(), feedItemView.getProgressBar());

        if(feedDesign.getDesign().getAuthor().getProfilePicture() != null) {
            feedItemImageLoader.DisplayImage(feedDesign.getDesign().getAuthor().getProfilePicture().getUrl(), feedItemView.getProfilePicture(), null); // TODO should this use profilePictureFileCache?
        } else {
            viewHolder.feedItemView.getProfilePicture().setImageResource(R.drawable.ic_anonymous);
        }

        SetCommentViews(feedItemView, feedDesign.getComments());
        SetClickListeners(feedItemView, feedDesign);
    }

这是什么原因造成的?每当您向下滚动提要时,VM 会关闭并导致以下异常:

07-05 11:51:30.179 22178-22178/com.elgami.customizer E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.elgami.customizer, PID: 22178
java.lang.IndexOutOfBoundsException: Invalid index 5, size is 5
at java.util.ArrayList.throwIndexOutOfBoundsException(ArrayList.java:255)
at java.util.ArrayList.get(ArrayList.java:308)
at com.elgami.feed.FeedRecyclerAdapter.bindFeedItemView(FeedRecyclerAdapter.java:180)
at com.elgami.feed.FeedRecyclerAdapter.onBindViewHolder(FeedRecyclerAdapter.java:77)
at android.support.v7.widget.RecyclerView$Adapter.onBindViewHolder(RecyclerView.java:5768)
at android.support.v7.widget.RecyclerView$Adapter.bindViewHolder(RecyclerView.java:5801)
at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5037)
at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:4913)
at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2029)
at android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1414)
at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1377)
at android.support.v7.widget.LinearLayoutManager.scrollBy(LinearLayoutManager.java:1193)
at android.support.v7.widget.LinearLayoutManager.scrollVerticallyBy(LinearLayoutManager.java:1043)
at android.support.v7.widget.RecyclerView$ViewFlinger.run(RecyclerView.java:4357)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:858)
at android.view.Choreographer.doCallbacks(Choreographer.java:670)
at android.view.Choreographer.doFrame(Choreographer.java:603)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:844)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)

编辑

当项目的位置是 5,而不是 10 或 15,或者我尝试过的任何其他数字时,异常停止发生:

// Differentiate between feedItem views and nativeAds
@Override
public int getItemViewType(int position) {
    int viewType = 1;
    if ((position % 5 == 0) && position != 1) viewType = 2;
    return viewType;
}

我不明白为什么会这样。

【问题讨论】:

    标签: java android arraylist android-recyclerview indexoutofboundsexception


    【解决方案1】:

    java.lang.IndexOutOfBoundsException:索引 5 无效,大小为 5

    例如,您有一个包含 5 项的数组,并且您要求第 6 项,它会崩溃并抛出“IndexOutOfBoundsException”错误,因为数组小于您要求的。

    ->Understand Arraylist IndexOutOfBoundsException in Android

    【讨论】:

    • 有道理,我只是想知道如何在我的上下文中解决这个问题。
    • 我不能完全理解你的代码,但想想它崩溃的时间,那一刻发生了什么,你问什么,它做了什么......我不知道这有多大帮助 - 在哪一行崩溃了?
    • 当 adItems.isEmpty() 为 true 时会崩溃,这意味着数组中本应处于加载过程中时没有对象。
    • 不妨试试这个: if (!adItems.isEmpty()) { feedItems.addAll(adItems); }
    • 仍然会产生与java.lang.IndexOutOfBoundsException: Invalid index 5, size is 5 相同的崩溃。如果我在我的 getItemViewType 方法中设置if ((position % 5 == 0) &amp;&amp; position != 1) viewType = 2;,那么我永远不会奇怪地崩溃。
    猜你喜欢
    • 2016-11-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多