Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BannerRecyclerViewExample low ad impression rate! #646

Open
theoyuncu8 opened this issue Feb 5, 2024 · 4 comments
Open

BannerRecyclerViewExample low ad impression rate! #646

theoyuncu8 opened this issue Feb 5, 2024 · 4 comments

Comments

@theoyuncu8
Copy link

theoyuncu8 commented Feb 5, 2024

I have a RecyclerView, and I aim to insert a banner ad after every 10 items within it. However, following the approach outlined in the official documentation leads to a decrease in ad display rate when pre-loading ads. Specifically, I experience a significantly low display rate, approximately 20-30%.

Another approach involves loading the ad-containing holder either in onCreateViewHolder or its constructor. However, this method only loads one ad at a time.

Alternatively, I attempted to load ads in onBindViewHolder, as demonstrated in my example. However, this approach isn't optimal because the onLoading event occurs when the creative exits the screen during scrolling and re-enters it, triggering the bind operation again. I believe this could also violate policies.

In summary, none of these solutions prove effective. I seek a different and correct method that doesn't burden the RecyclerView with repeated loading during scrolling.

The current method of pre-loading ads is outdated and not entirely correct. If users don't scroll to the end of the list, they won't generate any views. Despite an 80-90% match rate, the display rate remains at 20%, which is inaccurate. I am in need of a solution to address this issue.

BannerRecyclerViewExample:
https://github.com/googleads/googleads-mobile-android-examples/blob/master/java/advanced/BannerRecyclerViewExample/app/src/main/java/com/google/android/gms/example/bannerrecyclerviewexample/MainActivity.java

InlineAdaptiveBannerExample:
https://github.com/googleads/googleads-mobile-android-examples/blob/main/java/advanced/InlineAdaptiveBannerExample/app/src/main/java/com/google/android/gms/example/inlineadaptivebannerexample/MainActivity.java

My example: (My approach is flawed because the banner ad gets removed and then reloaded when the RecyclerView screen exits.)

The official example is also incorrect. As I mentioned, although the ads are pre-loaded, they are not always displayed. Ideally, the RecyclerView should pause the bind/banner ad where there are no impressions and then resume, but I'm unsure how to implement this.

TestActivity

public class TestActivity extends AppCompatActivity {
    RecyclerView recyclerView;
    TestAdapter testAdapter;
    List<String> itemList = new ArrayList<>();

    @SuppressLint("SetTextI18n")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.test_activity);

        for (int i = 0; i < 200; i++) {
            itemList.add("Item " + i);
            if (i % 10 == 0) {
                itemList.add(null);
            }
        }

        recyclerView = findViewById(R.id.recyclerView);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));

        testAdapter = new TestAdapter(itemList);
        recyclerView.setAdapter(testAdapter);
    }
}

TestAdapter

public class TestAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    List<String> itemList;
    static final int CONTENT_TYPE = 0;
    static final int AD_TYPE = 1;

    public TestAdapter(List<String> itemList) {
        this.itemList = itemList;
    }

    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        if (viewType == CONTENT_TYPE) {
            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.test_item, parent, false);
            return new ViewHolder(view);
        } else {
            View adView = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_ad, parent, false);
            return new AdRecyclerHolder(adView);
        }
    }

    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
        if (holder instanceof ViewHolder viewHolder) {
            viewHolder.idText.setText(String.valueOf(position));
            viewHolder.title.setText(itemList.get(position));
        } else if (holder instanceof AdRecyclerHolder adHolder) {
            AdRequest adRequest = new AdRequest.Builder().build();
            adHolder.mAdView.loadAd(adRequest);
            adHolder.mAdView.setAdListener(new AdListener() {
                @Override
                public void onAdFailedToLoad(@NonNull LoadAdError loadAdError) {
                    Log.e("TAG_AD", "onAdFailedToLoad");
                    super.onAdFailedToLoad(loadAdError);
                }

                @Override
                public void onAdLoaded() {
                    Log.e("TAG_AD", "onAdLoaded");
                }
            });
        }
    }

    @Override
    public int getItemCount() {
        return itemList.size();
    }

    @Override
    public int getItemViewType(int position) {
        if (itemList.get(position) == null) {
            return AD_TYPE;
        } else {
            return CONTENT_TYPE;
        }
    }

    public static class ViewHolder extends RecyclerView.ViewHolder {
        TextView idText, title;

        public ViewHolder(@NonNull View itemView) {
            super(itemView);
            idText = itemView.findViewById(R.id.id_text);
            title = itemView.findViewById(R.id.title);
        }
    }

    public static class AdRecyclerHolder extends RecyclerView.ViewHolder {
        AdView mAdView;
        public AdRecyclerHolder(@NonNull View itemView) {
            super(itemView);
            mAdView = itemView.findViewById(R.id.adView);
        }
    }
}
@NVentimiglia
Copy link
Member

Thanks,

I will take a look.

@NVentimiglia
Copy link
Member

NVentimiglia commented Mar 22, 2024

Chain #641

@NVentimiglia
Copy link
Member

@theoyuncu8

  1. The reduced show rate is expected because we are loading ads which are not rendered.

  2. In this comment are you talking about a video ad?

The official example is also incorrect. As I mentioned, although the ads are pre-loaded, they are not always displayed. Ideally, the RecyclerView should pause the bind/banner ad where there are no impressions and then resume, but I'm unsure how to implement this.

@DeveloperMobilePersonal
  1. Banner has a new auto-loading feature
  2. The fact that you load many ads in onCreateViewHolder is a big problem. Recyclerview is optimized according to the recycle view
  3. Performance is not good

How to fix these problems is as follows:

  1. You should not create and load many ads, instead you should have a mechanism to limit and cache AdView. For example, create a hashMap((1,AdView1),(2,AdView2),(3,AdView3)). I example:
    After item 10, take out AdView1
    After item 20, take out AdView2
    After item 30, take out AdView3
    After item 40, take out AdView1
    ...
    You should remember that when you swipe to item 40, item 10 has been recycled. We can reuse AdViews. But you will need to handle more complex logic including removeFromParent, removeAllView, check banner loaded....

  2. AdView supports onPause, onResume, onDestroy, attached and detached listening to optimize performance

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants