Search code examples
androidandroid-recyclerviewadapterfacebook-audience-networknative-ads

Facebook Native in feed ads are overlapping to each other in RecyclerView


I have an app which has Recyclerview and I want to put some facebook Native ads in between list items, like every 5 list items 1 native ad will be shown. everything is working perfectly but main problem is when I scroll down adChoice icon is being doubled and on scrolling up also adChoice icons are getting doubled. It seems that ads are overlapping to the previous one.

SCREENSHOT

Any suggestion will help me a lot. Here is the all source code and the official facebook audience network native ad code sample.

dependency

implementation 'com.android.support:cardview-v7:27.1.1'
implementation 'com.android.support:recyclerview-v7:27.1.1'
implementation 'com.android.volley:volley:1.1.0'
implementation 'com.facebook.android:audience-network-sdk:4.+'

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recycler_view_id"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</RelativeLayout>

content_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <android.support.v7.widget.CardView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="10dp">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:padding="10dp" >

            <TextView
                android:id="@+id/textViewHead"
                android:text="Heading"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:textAppearance="@style/Base.TextAppearance.AppCompat.Large"/>

            <TextView
                android:id="@+id/textViewDesc"
                android:text="Description"
                android:layout_width="match_parent"
                android:layout_height="wrap_content" />

        </LinearLayout>
    </android.support.v7.widget.CardView>
</LinearLayout>

ads_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="center_vertical"
    android:layout_marginBottom="5dp"
    android:layout_marginTop="5dp"
    android:orientation="vertical">

    <LinearLayout
        android:id="@+id/adChoicesContainer"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="top|right"
        android:orientation="vertical"/>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="80dp"
        android:layout_gravity="center_vertical"
        android:layout_marginBottom="5dp"
        android:layout_marginRight="10dp"
        android:orientation="horizontal">

        <com.facebook.ads.AdIconView
            android:id="@+id/adIconView"
            android:layout_width="70dp"
            android:layout_height="70dp"
            android:layout_gravity="center_vertical"
            android:layout_marginLeft="10dp"
            android:layout_marginRight="10dp"
            tools:src="@mipmap/ic_launcher"/>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">

            <TextView
                android:id="@+id/tvAdTitle"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:gravity="center_vertical"
                android:maxLines="1"
                android:textColor="@android:color/white"
                tools:text="Ad Title"/>

            <TextView
                android:id="@+id/tvAdBody"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:ellipsize="end"
                android:gravity="center_vertical"
                android:lines="3"
                android:textColor="@android:color/darker_gray"
                tools:text="This is an ad description."/>
        </LinearLayout>
    </LinearLayout>

    <com.facebook.ads.MediaView
        android:id="@+id/mediaView"
        android:layout_width="wrap_content"
        android:layout_height="200dp"
        android:layout_marginLeft="10dp"
        android:layout_marginRight="10dp"/>

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="10dp"
        android:layout_marginRight="10dp"
        >

        <TextView
            android:id="@+id/sponsored_label"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:ellipsize="end"
            android:lines="1"
            android:textColor="@android:color/darker_gray"
            android:textSize="10sp"/>

        <Button
            android:id="@+id/btnCTA"
            style="?android:attr/borderlessButtonStyle"
            android:layout_width="130dp"
            android:layout_height="40dp"
            android:layout_alignParentEnd="true"
            android:layout_centerVertical="true"
            android:layout_gravity="right"
            android:layout_marginTop="20dp"
            android:background="@android:color/darker_gray"
            android:gravity="center"
            android:paddingLeft="3dp"
            android:paddingRight="3dp"
            android:text="Install Now"
            android:textColor="@android:color/white"
            android:textSize="14sp"/>
    </RelativeLayout>
</LinearLayout>

ContentModel.java

package com.example.my_demo_app.fb_in-feed_ad;

public class ContentModel {

    String head, des;

    public ContentModel(String head, String des) {
        this.head = head;
        this.des = des;
    }

    public String getHead() {
        return head;
    }

    public String getDes() {
        return des;
    }
}

MyAdapter.java

package com.example.my_demo_app.fb_in-feed_ad;

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.facebook.ads.Ad;
import com.facebook.ads.AdChoicesView;
import com.facebook.ads.AdIconView;
import com.facebook.ads.MediaView;
import com.facebook.ads.NativeAd;

import java.util.ArrayList;
import java.util.List;

public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    public static final int MENU_ITEM_VIEW_TYPE = 0;
    public static final int AD_ITEM_VIEW_TYPE = 1;

    private final List<Object> mRecyclerViewItems;
    private final Context context;

    public MyAdapter(List<Object> recyclerViewItems, Context context) {
        this.mRecyclerViewItems = recyclerViewItems;
        this.context = context;
    }

    //--------------------getItemViewType

    @Override
    public int getItemViewType(int position) {
        Object recyclerViewItem = mRecyclerViewItems.get(position);
        if (recyclerViewItem instanceof ContentModel) {
            return MENU_ITEM_VIEW_TYPE;
        } else if (recyclerViewItem instanceof Ad) {
            return AD_ITEM_VIEW_TYPE;
        } else {
            return -1;
        }
    }


    //--------------------getItemCount

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

    //--------------------onCreateViewHolder

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        Context context = parent.getContext();
        LayoutInflater inflater = LayoutInflater.from(context);

        if (viewType==MENU_ITEM_VIEW_TYPE){
            View menuItemView = inflater.inflate(R.layout.content_layout, parent, false);
            return new MenuItemHolder(menuItemView);
        }else if (viewType==AD_ITEM_VIEW_TYPE){
            View adItemView = inflater.inflate(R.layout.ads_layout, parent, false);
            return new AdHolder(adItemView);
        }
        return null;
    }

    //--------------------onBindViewHolder

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

        if (itemType==MENU_ITEM_VIEW_TYPE){
            MenuItemHolder menuItemHolder = (MenuItemHolder) holder;
            ContentModel contentModel = (ContentModel) mRecyclerViewItems.get(position);
            menuItemHolder.txtH.setText(contentModel.getHead());
            menuItemHolder.txtD.setText(contentModel.getDes());
        }else if (itemType==AD_ITEM_VIEW_TYPE){

            AdHolder nativeAdViewHolder = (AdHolder) holder;
            NativeAd nativeAd = (NativeAd) mRecyclerViewItems.get(position);

            AdIconView adIconView = nativeAdViewHolder.adIconView;
            TextView tvAdTitle = nativeAdViewHolder.tvAdTitle;
            TextView tvAdBody = nativeAdViewHolder.tvAdBody;
            Button btnCTA = nativeAdViewHolder.btnCTA;
            LinearLayout adChoicesContainer = nativeAdViewHolder.adChoicesContainer;
            MediaView mediaView = nativeAdViewHolder.mediaView;
            TextView sponsorLabel = nativeAdViewHolder.sponsorLabel;

            tvAdTitle.setText(nativeAd.getAdvertiserName());
            tvAdBody.setText(nativeAd.getAdBodyText());
            btnCTA.setText(nativeAd.getAdCallToAction());
            sponsorLabel.setText(nativeAd.getSponsoredTranslation());

            AdChoicesView adChoicesView = new AdChoicesView(context, nativeAd, true);
            adChoicesContainer.addView(adChoicesView);

            List<View> clickableViews = new ArrayList<>();
            clickableViews.add(btnCTA);
            clickableViews.add(mediaView);
            nativeAd.registerViewForInteraction(nativeAdViewHolder.container, mediaView, adIconView, clickableViews);

        }
    }

    //--------------------MenuItemHolder

    public class MenuItemHolder extends RecyclerView.ViewHolder{

        public TextView txtH, txtD;

        public MenuItemHolder(View itemView) {
            super(itemView);

            txtH = (TextView) itemView.findViewById(R.id.textViewHead);
            txtD = (TextView) itemView.findViewById(R.id.textViewDesc);
        }
    }

    //--------------------AdHolder

    public class AdHolder extends RecyclerView.ViewHolder{
        AdIconView adIconView;
        TextView tvAdTitle;
        TextView tvAdBody;
        Button btnCTA;
        View container;
        TextView sponsorLabel;
        LinearLayout adChoicesContainer;
        MediaView mediaView;

        AdHolder(View itemView) {
            super(itemView);
            this.container = itemView;
            adIconView = (AdIconView) itemView.findViewById(R.id.adIconView);
            tvAdTitle = (TextView) itemView.findViewById(R.id.tvAdTitle);
            tvAdBody = (TextView) itemView.findViewById(R.id.tvAdBody);
            btnCTA = (Button) itemView.findViewById(R.id.btnCTA);
            adChoicesContainer = (LinearLayout) itemView.findViewById(R.id.adChoicesContainer);
            mediaView = (MediaView) itemView.findViewById(R.id.mediaView);
            sponsorLabel = (TextView) itemView.findViewById(R.id.sponsored_label);
        }
    }
}

MainActivity.java

package com.example.my_demo_app.fb_in-feed_ad;

import android.app.ProgressDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.widget.Toast;

import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.StringRequest;
import com.android.volley.toolbox.Volley;
import com.facebook.ads.Ad;
import com.facebook.ads.AdError;
import com.facebook.ads.NativeAd;
import com.facebook.ads.NativeAdListener;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {

    private static final String URL_DATA = "https://res.cloudinary.com/ravi40/raw/upload/v1532239134/my_json/heroes_list.json";
    private RecyclerView recyclerView;
    private List<Object> mRecyclerViewItems;
    MyAdapter adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        recyclerView = (RecyclerView) findViewById(R.id.recycler_view_id);
        recyclerView.setHasFixedSize(true);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        mRecyclerViewItems = new ArrayList<>();

        //--------------------Native Ad

        NativeAd nativeAd = new NativeAd(getApplicationContext(), "IMG_16_9_LINK#YOUR_FACEBOOK_NATIVE_AD_PLACEMENT_ID_WILL_GOES_HERE");  // IMG_16_9_LINK# denote only testing purpose
        nativeAd.setAdListener(new NativeAdListener() {
            @Override
            public void onMediaDownloaded(Ad ad) {

            }

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

            }

            @Override
            public void onAdLoaded(Ad ad) {

                for (int i=4; i<mRecyclerViewItems.size()+4; i+=5)
                mRecyclerViewItems.add(i, ad);
                adapter.notifyDataSetChanged();

            }

            @Override
            public void onAdClicked(Ad ad) {

            }

            @Override
            public void onLoggingImpression(Ad ad) {

            }
        });

        nativeAd.loadAd();

        loadRecyclerViewData();
    }

    private void loadRecyclerViewData(){
        final ProgressDialog progressDialog = new ProgressDialog(this);
        progressDialog.setMessage("Loading Data...");
        progressDialog.show();

        StringRequest stringRequest = new StringRequest(Request.Method.GET,
                URL_DATA,
                new Response.Listener<String>() {
                    @Override
                    public void onResponse(String s) {
                        progressDialog.dismiss();
                        try {
                            JSONObject jsonObject = new JSONObject(s);
                            JSONArray array = jsonObject.getJSONArray("heroes");
                            for (int i = 0; i<array.length(); i++){
                                JSONObject o = array.getJSONObject(i);
                                ContentModel item = new ContentModel(
                                        o.getString("name"),
                                        o.getString("about")
                                );
                                mRecyclerViewItems.add(item);
                            }

                            adapter = new MyAdapter(mRecyclerViewItems, getApplicationContext());
                            recyclerView.setAdapter(adapter);

                        } catch (JSONException e) {
                            e.printStackTrace();
                        }
                    }
                },
                new Response.ErrorListener() {
                    @Override
                    public void onErrorResponse(VolleyError error) {
                        progressDialog.dismiss();
                        Toast.makeText(getApplicationContext(), error.getMessage(), Toast.LENGTH_LONG).show();
                    }
                });
        RequestQueue requestQueue = Volley.newRequestQueue(this);
        requestQueue.add(stringRequest);
    }

}

Solution

  • Ad are getting overlapped when adding in the container. The solution is to clear the container before adding the ads again.

    For example:

    AdChoicesView adChoicesView = new AdChoicesView(context, nativeAd, true);
    
    // Clear the container.
    adChoicesContainer.removeAllViews()
    
    adChoicesContainer.addView(adChoicesView);