android.view.ViewGroup.addViewInner (ViewGroup.java:5034)
android.view.ViewGroup.addView (ViewGroup.java:4865)
android.view.ViewGroup.addView (ViewGroup.java:4805)
android.view.ViewGroup.addView (ViewGroup.java:4778)
com.google.android.gms.ads.internal.formats.ah.a (ah.java:44)
com.google.android.gms.ads.internal.formats.client.k.a (k.java:25)
fa.onTransact (fa.java:4)
android.os.Binder.transact (Binder.java:667)
com.google.android.gms.internal.ads.zzgc.zza (zzgc.java:21)
com.google.android.gms.internal.ads.zzacx.zza (zzacx.java:16)
com.google.android.gms.ads.formats.UnifiedNativeAdView.setNativeAd (UnifiedNativeAdView.java:52)
com.ihad.ptt.model.handler.AdMobHelper$BannerItemHolder.setNativeAd (AdMobHelper.java:911)
com.ihad.ptt.model.handler.AdMobBannerAdHelper.bind (AdMobBannerAdHelper.java:156)
com.ihad.ptt.ArticleContentRecyclerAdapter$SponsorAdMobItemHolder.updateAd (ArticleContentRecyclerAdapter.java:3871)
com.ihad.ptt.ArticleContentRecyclerAdapter.onBindViewHolder (ArticleContentRecyclerAdapter.java:1624)
com.ihad.ptt.ArticleContentRecyclerAdapter.onBindViewHolder (ArticleContentRecyclerAdapter.java:58)
androidx.recyclerview.widget.RecyclerView$Adapter.onBindViewHolder (RecyclerView.java:7065)
androidx.recyclerview.widget.RecyclerView$Adapter.bindViewHolder (RecyclerView.java:7107)
androidx.recyclerview.widget.RecyclerView$Recycler.tryBindViewHolderByDeadline (RecyclerView.java:6012)
androidx.recyclerview.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline (RecyclerView.java:6279)
androidx.recyclerview.widget.GapWorker.prefetchPositionWithDeadline (GapWorker.java:288)
androidx.recyclerview.widget.GapWorker.flushTaskWithDeadline (GapWorker.java:345)
androidx.recyclerview.widget.GapWorker.flushTasksWithDeadline (GapWorker.java:361)
androidx.recyclerview.widget.GapWorker.prefetch (GapWorker.java:368)
androidx.recyclerview.widget.GapWorker.run (GapWorker.java:399)
android.os.Handler.handleCallback (Handler.java:873)
android.os.Handler.dispatchMessage (Handler.java:99)
android.os.Looper.loop (Looper.java:280)
android.app.ActivityThread.main (ActivityThread.java:6706)
java.lang.reflect.Method.invoke (Method.java)
com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:493)
com.android.internal.os.ZygoteInit.main (ZygoteInit.java:858)
Hi there,
Thank you for reaching out to us.
I'm afraid that using native ads in a RecyclerView is a bit more involved than just adding and removing views to and from a view parent. You may check out our example code for further details on this.
Regards,
Ziv Yves Sanchez
Mobile Ads SDK Team
protected BannerItemHolder inflateBanner(){
Activity activity = getActivity();
if( activity == null ) return null;
UnifiedNativeAdView view = (UnifiedNativeAdView) LayoutInflater.from(activity).inflate(R.layout.admob_native_banner_body_item, null);
return new BannerItemHolder(view);
}
protected CardItemHolder inflateCard(){
Activity activity = getActivity();
if( activity == null ) return null;
UnifiedNativeAdView view = (UnifiedNativeAdView) LayoutInflater.from(activity).inflate(R.layout.admob_native_card_item, null);
return new CardItemHolder(view);
}
public static class BannerItemHolder implements NativeItemHolder {
UnifiedNativeAdView adView;
@BindView(R.id.icon)
ImageView icon;
@BindView(R.id.headline)
NativeAdHeaderView headline;
@Nullable
@BindView(R.id.advertiser)
NativeAdAdvertiserView advertiser;
@Nullable
@BindView(R.id.body)
NativeAdBodyView body;
@Nullable
@BindView(R.id.socialContext)
TextView socialContext;
@BindView(R.id.callToAction)
Button callToAction;
public BannerItemHolder(UnifiedNativeAdView adView) {
ButterKnife.bind(this, adView);
this.adView = adView;
}
public void setHeadline(String headline){
this.headline.setText(headline);
this.headline.setTextSize(SingletonProperty.getInstance().getListItemTextSize());
adView.setHeadlineView(this.headline);
}
public void setBody(String body){
if( this.body == null ) return;
this.body.setText(body);
this.body.setTextSize(SingletonProperty.getInstance().getListItemTextSize() - 3);
adView.setBodyView(this.body);
}
public void setAdvertiser(String advertiser){
this.advertiser.setText(advertiser);
this.advertiser.setTextSize(SingletonProperty.getInstance().getListItemTextSize() - 4);
adView.setAdvertiserView(this.headline);
}
public void setSocialContext(String socialContext){
if( this.socialContext == null ) return;
if( socialContext == null || socialContext.isEmpty() ){
this.socialContext.setVisibility(View.GONE);
}
else {
this.socialContext.setText(socialContext);
this.socialContext.setVisibility(View.VISIBLE);
this.socialContext.setTextSize(SingletonProperty.getInstance().getListItemTextSize() - 5);
}
}
public void setIcon(NativeAd.Image icon){
if( icon == null ) {
this.icon.setVisibility(View.GONE);
return;
}
else {
this.icon.setVisibility(View.VISIBLE);
}
this.icon.setImageDrawable(icon.getDrawable());
adView.setIconView(this.icon);
}
public void setCallToAction(String callToAction){
this.callToAction.setText(callToAction);
this.callToAction.setTextSize(SingletonProperty.getInstance().getListItemTextSize() - 5);
adView.setCallToActionView(this.callToAction);
}
public void setNativeAd(UnifiedNativeAd ad){
this.adView.setNativeAd(ad);
}
@Override
public void destroy() {
if( this.adView == null ) return;
this.adView.destroy();
}
}
public static class CardItemHolder implements NativeItemHolder {
UnifiedNativeAdView adView;
@BindView(R.id.media)
MediaView media;
@BindView(R.id.icon)
ImageView icon;
@BindView(R.id.headline)
NativeAdHeaderView headline;
@Nullable
@BindView(R.id.advertiser)
NativeAdAdvertiserView advertiser;
@Nullable
@BindView(R.id.socialContext)
TextView socialContext;
@Nullable
@BindView(R.id.body)
NativeAdBodyView body;
@BindView(R.id.callToAction)
Button callToAction;
public CardItemHolder(UnifiedNativeAdView adView) {
ButterKnife.bind(this, adView);
this.adView = adView;
this.media.setImageScaleType(ImageView.ScaleType.FIT_CENTER);
this.media.setOnHierarchyChangeListener(new ViewGroup.OnHierarchyChangeListener() {
@Override
public void onChildViewAdded(View parent, View child) {
if (child instanceof ImageView) {
ImageView imageView = (ImageView) child;
imageView.setAdjustViewBounds(true);
Resources resources = imageView.getResources();
if( resources == null ) return;
int maxHeight = (int) TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP, 400, imageView.getResources().getDisplayMetrics() );
imageView.setMaxHeight(maxHeight);
}
}
@Override
public void onChildViewRemoved(View parent, View child) {}
});
}
public void setHeadline(String headline){
this.headline.setText(headline);
this.headline.setTextSize(SingletonProperty.getInstance().getListItemTextSize());
adView.setHeadlineView(this.headline);
}
public void setBody(String body){
if( this.body == null ) return;
this.body.setText(body);
this.body.setTextSize(SingletonProperty.getInstance().getListItemTextSize() - 3);
adView.setBodyView(this.body);
}
public void setAdvertiser(String advertiser){
if( this.advertiser == null ) {
this.headline.setText(advertiser);
this.headline.setTextSize(SingletonProperty.getInstance().getListItemTextSize());
adView.setAdvertiserView(this.headline);
}
else {
this.advertiser.setText(advertiser);
this.advertiser.setTextSize(SingletonProperty.getInstance().getListItemTextSize() - 4);
adView.setAdvertiserView(this.headline);
}
}
public void setSocialContext(String socialContext){
if( this.socialContext == null ) return;
if( socialContext == null || socialContext.isEmpty() ){
this.socialContext.setVisibility(View.GONE);
}
else {
this.socialContext.setText(socialContext);
this.socialContext.setVisibility(View.VISIBLE);
this.socialContext.setTextSize(SingletonProperty.getInstance().getListItemTextSize() - 5);
}
}
public void setMedia(MediaContent media){
this.media.setMediaContent(media);
adView.setMediaView(this.media);
}
public void setIcon(NativeAd.Image icon){
if( icon == null ) {
this.icon.setVisibility(View.GONE);
return;
}
else {
this.icon.setVisibility(View.VISIBLE);
}
this.icon.setImageDrawable(icon.getDrawable());
adView.setIconView(this.icon);
}
public void setCallToAction(String callToAction){
this.callToAction.setText(callToAction);
this.callToAction.setTextSize(SingletonProperty.getInstance().getListItemTextSize() - 5);
adView.setCallToActionView(this.callToAction);
}
public void setNativeAd(UnifiedNativeAd ad){
this.adView.setNativeAd(ad);
}
@Override
public void destroy() {
if( this.adView == null ) return;
this.adView.destroy();
}
}
public void bind(ViewGroup parent){
if( remoteConfigHelper.isLimitedEdition() ) return;
if( property.isSubscriptionNoAds() ) return;
if( !property.isUseNativeAd() ) return;
if( parent == null ) return;
AdMobHelper.AdHolder adHolder = AdMobHelper.getInstance().getAd(AdMobHelper.Type.card);
if( adHolder == null ) return;
if( referencedAd != null && referencedAd.equals(adHolder) ) return;
if( AdMobHelper.getInstance().isNativeBannerOnly() ){
bindBanner(parent, adHolder);
}
else {
bindCard(parent, adHolder);
}
}
private void bindBanner(ViewGroup parent, AdMobHelper.AdHolder adHolder) {
AdMobHelper.BannerItemHolder itemHolder = AdMobHelper.getInstance().inflateBanner();
if( itemHolder == null ) return;
unbind(parent);
UnifiedNativeAd ad = adHolder.ad;
itemHolder.setHeadline(ad.getHeadline());
itemHolder.setAdvertiser(ad.getAdvertiser());
itemHolder.setBody(ad.getBody());
itemHolder.setIcon(ad.getIcon());
itemHolder.setCallToAction(ad.getCallToAction());
itemHolder.setNativeAd(ad);
parent.addView(itemHolder.adView);
this.referencedAd = adHolder;
adHolder.setImpression(true);
}
private void bindCard(ViewGroup parent, AdMobHelper.AdHolder adHolder) {
AdMobHelper.CardItemHolder itemHolder = AdMobHelper.getInstance().inflateCard();
if( itemHolder == null ) return;
unbind(parent);
UnifiedNativeAd ad = adHolder.ad;
itemHolder.setMedia(ad.getMediaContent());
itemHolder.setIcon(ad.getIcon());
itemHolder.setHeadline(ad.getHeadline());
itemHolder.setAdvertiser(ad.getAdvertiser());
Bundle extras = ad.getExtras();
if (extras != null && extras.containsKey(FacebookAdapter.KEY_SOCIAL_CONTEXT_ASSET)) {
String socialContext = extras.getString(FacebookAdapter.KEY_SOCIAL_CONTEXT_ASSET);
itemHolder.setSocialContext(socialContext);
}
else {
itemHolder.setSocialContext(null);
}
itemHolder.setBody(ad.getBody());
itemHolder.setCallToAction(ad.getCallToAction());
itemHolder.setNativeAd(ad);
parent.addView(itemHolder.adView);
this.referencedAd = adHolder;
this.referenceItemHolder = new WeakReference<>(itemHolder);
adHolder.setImpression(true);
}
@Override
public ItemHolder onCreateViewHolder(ViewGroup parent, int viewType) {
switch ( viewType ){case SPONSOR_ADMOB:{
// create a new view
View itemLayoutView = LayoutInflater.from(parent.getContext()).inflate(R.layout.admob_recycler_item, parent, false);
// create ViewHolder
return new SponsorAdMobItemHolder(itemLayoutView);
}
// ...
}
}
public static class SponsorAdMobItemHolder extends ItemHolder {
AdMobBannerAdHelper adMobBannerAdHelper = new AdMobBannerAdHelper();
ViewGroup view;
public SponsorAdMobItemHolder(View itemView){
super(itemView, null, null);
ButterKnife.bind(this, itemView);
this.view = (ViewGroup) itemView;
}
@Override
void updateAd(Context context){
adMobBannerAdHelper.bind(view);
}
@Override
void detach() {
super.detach();
adMobBannerAdHelper.unbind(view);
}
}
Hi there,
Thank you for updating us on your concern.
There doesn't seem to be any glaring issues with your code at first glance. That said, since it is proving to be quite a challenge just tracing code and theorizing code state, could you kindly provide the details below (via Reply privately to author) so that we can further investigate this issue?
Regards,
- Copy of a sample project (replicating the issue)
- Steps to replicate the issue
Also from what it looks like, you were trying to get the same ad to appear in each spot of the RecyclerView but have not been able to get that to happen?
Where is the recursive part of the code that allows for the different ads to be placed in?
protected AdHolder getAd(@Type String type){
if( !initialized ) return null;
switch (type) {
case Type.banner: {
int size = bannerGarage.size();
if (size == 0) return null;
return bannerGarage.get(size - 1);
}
case Type.card: {
int size = cardGarage.size();
if (size == 0) return null;
return cardGarage.get(size - 1);
}
default:
return null;
}
}
Hi there,
Thank you for providing additional details on your concern.
I'm afraid that we would be needing a sample project with a consistently replicable set of steps in order to continue with the investigation. Kindly send one via Reply privately to author whenever you are able to.
As for your post regarding the AdChoices overlay: we can formalize this into a feature request if you would kindly expand on this, particularly on why you wish for this feature to be implemented.
Regards,
Ziv Yves Sanchez
