Recycleview при прокрутке вызывает java.lang.Исключение IndexOutOfBoundsException в последней позиции элемента

#java #android #android-recyclerview #admob

#java #Android #android-recyclerview #admob

Вопрос:

У меня есть список массивов, в котором содержится 15 элементов, и я использую нативную рекламу admob в recycleview в своем приложении, и у меня есть две проблемы, с которыми я не могу понять, как справиться. Первая проблема заключается в том, что я хочу показывать первые объявления после, скажем, 7-го элемента, но первое объявление отображается на 0-й позиции. И вторая проблема заключается в том, когда я дохожу до конца списка, который я получаю java.lang.IndexOutOfBoundsException: . Может ли кто-нибудь здесь, пожалуйста, помочь мне выяснить, что я делаю не так, любая помощь была бы очень признательна. Вот мой код:

 class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static final int TYPE_AD= 0;
private static final int TYPE_NORMAL= 1;
public static final int ITEMS_PER_AD = 7;
Context context;
List<UnifiedNativeAd> mNativeAds = new ArrayList<>();
List<Quote> mQuotes;

private static final int NUMBER_OF_ADS = 5;
private AdLoader adLoader;
private String ADMOB_NATIVE_AD_UNIIT = "ca-app-pub-3940256099942544/2247696110";

public RecyclerViewAdapter(Context context, List<Quote> quotes) {
    this.context = context;
    this.mQuotes = quotes;
    notifyDataSetChanged();
}

@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType)
{
    if(viewType == TYPE_AD)
    {
        View view = LayoutInflater.from(this.context).inflate(R.layout.ad_unified,parent,false);
        return new UnifiedNativeAdViewHolder(view);
    }
    View view = LayoutInflater.from(this.context).inflate(R.layout.quotes_list_item,parent,false);
    return new QuoteViewHolder(view);
}

@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position)
{
    int viewType = getItemViewType(position);

    switch (viewType) {
        case TYPE_NORMAL :
            QuoteViewHolder vh = (QuoteViewHolder) holder;

            Quote current = (Quote) mQuotes.get(position);
            vh.txtName.setText(current.getQuote());
            vh.txtEmail.setText(current.getCategoryId());
            break;
        case TYPE_AD:
            //fall through
        default:
            UnifiedNativeAdViewHolder adViewHolder = (UnifiedNativeAdViewHolder) holder;
            AdLoader.Builder builder = new AdLoader.Builder(context, ADMOB_NATIVE_AD_UNIIT);
            adLoader = builder.forUnifiedNativeAd(unifiedNativeAd -> {
                mNativeAds.add(unifiedNativeAd);
                if (!adLoader.isLoading()) {
                    UnifiedNativeAd nativeAd = (UnifiedNativeAd) mNativeAds.get(position);
                    populateNativeAdView( nativeAd, (adViewHolder.getAdView()));
                    notifyDataSetChanged();
                }
            }).withAdListener(new AdListener(){
                @Override
                public void onAdFailedToLoad(LoadAdError loadAdError) {
                    super.onAdFailedToLoad(loadAdError);
                }
            })
                    .build();
            adLoader.loadAd(new AdRequest.Builder().build());
    }

}

@Override
public int getItemCount() {
    if (mNativeAds != null) return mQuotes.size()   mNativeAds.size();
    else return mQuotes.size();
}

@Override
public int getItemViewType(int position)
{
    return (position % ITEMS_PER_AD == 0) ? TYPE_AD: TYPE_NORMAL;
}
 

и вот мой logcat

 2020-11-22 19:50:51.372 589-589/com.example.test E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.test, PID: 589
java.lang.IndexOutOfBoundsException: Index: 14, Size: 3
    at java.util.ArrayList.get(ArrayList.java:437)
    at com.example.test.RecyclerViewAdapter.lambda$onBindViewHolder$0$RecyclerViewAdapter(RecyclerViewAdapter.java:79)
    at com.example.test.-$Lambda$RecyclerViewAdapter$rjtX5KhLYVLI7Av-VFSBy8gWizI.onUnifiedNativeAdLoaded(Unknown Source:6)
    at com.google.android.gms.internal.ads.zzagx.zza(com.google.android.gms:play-services-ads-lite@@19.5.0:6)
    at com.google.android.gms.internal.ads.zzagb.zza(com.google.android.gms:play-services-ads-lite@@19.5.0:18)
    at com.google.android.gms.internal.ads.zzgw.onTransact(com.google.android.gms:play-services-ads-base@@19.5.0:13)
    at android.os.Binder.transact(Binder.java:630)
    at ge.b(:com.google.android.gms.policy_ads_fdr_dynamite@204102000@204102000000.334548305.334548305:2)
    at com.google.android.gms.ads.internal.formats.client.au.a(:com.google.android.gms.policy_ads_fdr_dynamite@204102000@204102000000.334548305.334548305:0)
    at com.google.android.gms.ads.nonagon.ad.nativead.ad.run(Unknown Source:0)
    at android.os.Handler.handleCallback(Handler.java:794)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at qj.a(:com.google.android.gms.policy_ads_fdr_dynamite@204102000@204102000000.334548305.334548305:0)
    at com.google.android.gms.ads.internal.util.f.a(:com.google.android.gms.policy_ads_fdr_dynamite@204102000@204102000000.334548305.334548305:1)
    at qj.dispatchMessage(:com.google.android.gms.policy_ads_fdr_dynamite@204102000@204102000000.334548305.334548305:0)
    at android.os.Looper.loop(Looper.java:176)
    at android.app.ActivityThread.main(ActivityThread.java:6651)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:547)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:824)
 

вот где я получаю ошибку

 UnifiedNativeAd nativeAd = (UnifiedNativeAd) mNativeAds.get(position);
 

Ответ №1:

Эта проблема связана с тем, что размер mNativeAds меньше размера суммирования двух списков, при прокрутке вверх вы вызываете индекс, такой как 15, который, конечно, не найден в списке mNativeAds размером 7.

Вместо того, чтобы использовать старую позицию списка mNativeAds :

 UnifiedNativeAd nativeAd = (UnifiedNativeAd) mNativeAds.get(position);
 

используйте новую позицию на основе суммирования

 UnifiedNativeAd nativeAd = (UnifiedNativeAd) mNativeAds.get(newPosition);
 

Ответ №2:

в getItemCount вы возвращаете сумму размеров кавычек и mNativeAds, которая больше размера mNativeAds. Таким образом, mNativeAds выдает некоторое исключение в более высокой позиции.

Вы должны использовать один список для обоих (mQuotes и mNativeAds) и соответствующим образом адаптировать свою логику.

»’

     @Override
    public int getItemCount() {

//Reason of your problem.

        if (mNativeAds != null) return mQuotes.size()   mNativeAds.size();
        else return mQuotes.size();
    }
 

»’

Ответ №3:

Попробуйте следующие 3 изменения кода:

  1. Quote current = (Quote) mQuotes.get(position); изменить на Quote current = (Quote) mQuotes.get(position - position / ITEMS_PER_AD);
  2. UnifiedNativeAd nativeAd = (UnifiedNativeAd) mNativeAds.get(position); изменить на UnifiedNativeAd nativeAd = (UnifiedNativeAd) mNativeAds.get((position / ITEMS_PER_AD - 1) / mNativeAds.size());
  3. return (position % ITEMS_PER_AD == 0) ? TYPE_AD: TYPE_NORMAL; изменить на return (position != 0 amp;amp; (position % ITEMS_PER_AD == 0)) ? TYPE_AD : TYPE_NORMAL;