Native is a component-based ad format that gives publishers the freedom to customize how ad assets like headlines and calls to action are presented in their apps. By choosing fonts, colors, and other details for themselves, publishers are able to create natural, unobtrusive ad presentations that can add to a rich user experience.

This codelab will walk you through using Native Advanced ads within a RecyclerView, to show you how to monetize a feed-based app. You'll start with an app that displays a list of items (current sample uses dishes from a menu), but no ads. Over the course of the codelab, you'll add code to handle a new types of item (unified native ads), and display it correctly.

What you will build

You will build a feed-based app with ads injected at regular intervals. Your app will:

  • Request Native Ads Advanced using the Google Mobile Ads SDK
  • Present ads within your feed
  • Customize the look of the ads to match your content

What you'll learn

What you'll need

This codelab is focused on Native Advanced ads in the Google Mobile Ads SDK. Non-relevant concepts and code blocks are glossed over and are provided for you to simply copy and paste.

You will start with an app that imitates a restaurant menu. It has a RecyclerView showing a list of menu items.

Download the Code

Follow the steps listed below to download all the code for this codelab:
Click the following link to download all the code for this codelab:

  1. Download the source code from this link.
  2. Unpack the downloaded zip file.

This will unpack a root folder (admob-native-advanced-feed-master), which contains a directory specific to either Android or iOS. For this codelab you'll navigate to the Android directory. The Android directory contains the start state for this codelab, located in the work directory. The end state for this codelab is located in the final directory. Both work and final directories contain an Android project within a subdirectory named NativeRecyclerViewExample.

You'll do all of your coding in this codelab in Android project located within the work directory. If at any time you're having trouble, you can refer to the Android project located under the final directory.

Open the work project in Android Studio

  1. Open Android Studio and select Import Project.
  2. Navigate to the NativeRecyclerViewExample project under the work directory and select it.
  3. Click OK

You should now have the project open in Android Studio.

The first step to adding the Firebase SDK to your Android project is including a Firebase configuration file within your app. Normally, you would download a google-services.json file from the Firebase console and include it at the app/ directory of your app. For convenience, a sample google-services.json file has already been included in this project.

Once the google-services.json file is included in the project, import the Firebase Ads SDK by adding the following rule to your project-level build.gradle file to include the google-services plugin:

build.gradle -- NativeAdvancedRecyclerViewExample/

buildscript {
    ...
    dependencies {
        ...
        classpath 'com.google.gms:google-services:3.1.1'
    }
}

You will also add the two lines shown below to your app-level build.gradle file. Place the compile statement inside the dependencies section and the apply plugin statement at the bottom.

build.gradle -- NativeAdvancedRecyclerViewExample/app/

  ...
  dependencies {
      ...
      compile 'com.google.firebase:firebase-ads:15.0.0'
  }
  ...

  apply plugin: 'com.google.gms.google-services'
  1. If you see a warning message across the top of the Android Studio window indicating that Gradle needs to perform a sync, click Sync Now. Gradle refreshes your project's libraries to include the dependency you just added.
  2. If you see a message asking you to install the Google Repository, just agree to the install and have Android Studio take care of the download for you. The Google Repository contains code for Gradle to incorporate.
  3. Once your build.gradle files are modified and everything has synced, try rebuilding your project (Run app in the Run menu) to make sure it compiles correctly.

You won't see any changes, but including Firebase and the Mobile Ads SDK is the first step toward getting native advanced ads into your app.

Before loading ads, your app will need to initialize the Mobile Ads SDK by calling MobileAds.initialize() with your AdMob App ID. This only needs to be done once, ideally at app launch. You can find your app's App ID in the AdMob UI. For this codelab, you will use the test app ID value of ca-app-pub-3940256099942544~3347511713. Following Android best practices, this value should be mapped to the strings resource file located at NativeAdvancedRecyclerExample/app/src/main/res/values/strings.xml of your project. Add an new entry to this file for the AdMob App ID, as shown below.

strings.xml

<resources>
   ...
   <string name="admob_app_id">ca-app-pub-3940256099942544~3347511713</string>
   ...
</resources>

Add the call to initialize(), shown below, to the onCreate() method of the MainActivity class to perform Google Mobile Ads SDK initialization.

MainActivity.java

import com.google.android.gms.ads.MobileAds;
...
public class MainActivity extends Activity {
    private RewardedVideoAd mAd;

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

        // Initialize the Google Mobile Ads SDK
        MobileAds.initialize(this,
                getString(R.string.admob_app_id));
        ...
    }

    ...
}

Currently, the the RecyclerView in the sample app is displaying one type of view, views corresponding to menu items. To integrate native ads, you'll need to define a new view type.

Add the code shown below, to define a new view type constant in the RecyclerViewAdapter class.

RecyclerViewAdapter.java

class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    // A menu item view type.
    private static final int MENU_ITEM_VIEW_TYPE = 0;

    // The unified native ad view type.
    private static final int UNIFIED_NATIVE_AD_VIEW_TYPE = 1;

...

For the unified native ad format, there is a corresponding ad view class, UnifiedNativeAdView. This is a ViewGroup object that you should use as the roots for ads of each format. A single UnifiedNativeAdView corresponds to a single UnifiedNativeAd. Each view used to display that ad's assets (the MediaView that displays the media asset, for instance) should be a child of the UnifiedNativeAdView object.

We must also include an Ad attribution view as per AdMob's policy guidelines.

Now that you have a new view type for unified native ads, you'll need to describe how the individual views for the components of the ads should be laid out within the UnifiedNativeAdView class. For this codelab, you'll use an layout XML resource file to define the visual structure of the ads. To make this task easier, the XML has been created for you.

To define the unified native ad layout, create a file named ad_unified.xml in the res/layout/ directory of your Android project, and include the XML content listed below in the file.

ad_unified.xml

<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginBottom="10dp"
    android:orientation="vertical"
    card_view:cardCornerRadius="@dimen/cardview_default_radius"
    card_view:cardElevation="@dimen/cardview_default_elevation">

    <com.google.android.gms.ads.formats.UnifiedNativeAdView xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/ad_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:background="#FFFFFF"
            android:minHeight="50dp"
            android:orientation="vertical">

            <TextView
                android:id="@+id/ad_attribution"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="left"
                android:textColor="#FFFFFF"
                android:textSize="12sp"
                android:text="Ad"
                android:background="#FFCC66"
                android:width="15dp"
                android:height="15dp"/>

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="vertical"
                android:paddingLeft="20dp"
                android:paddingRight="20dp"
                android:paddingTop="3dp">

                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:orientation="horizontal">

                    <ImageView
                        android:id="@+id/ad_icon"
                        android:layout_width="40dp"
                        android:layout_height="40dp"
                        android:adjustViewBounds="true"
                        android:paddingBottom="5dp"
                        android:paddingRight="5dp"
                        android:paddingEnd="5dp"/>

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

                        <TextView
                            android:id="@+id/ad_headline"
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:textColor="#0000FF"
                            android:textSize="16sp"
                            android:textStyle="bold" />

                        <LinearLayout
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content">

                            <TextView
                                android:id="@+id/ad_advertiser"
                                android:layout_width="wrap_content"
                                android:layout_height="match_parent"
                                android:gravity="bottom"
                                android:textSize="14sp"
                                android:textStyle="bold"/>

                            <RatingBar
                                android:id="@+id/ad_stars"
                                style="?android:attr/ratingBarStyleSmall"
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:isIndicator="true"
                                android:numStars="5"
                                android:stepSize="0.5" />
                        </LinearLayout>

                    </LinearLayout>
                </LinearLayout>

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

                    <TextView
                        android:id="@+id/ad_body"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_marginRight="20dp"
                        android:layout_marginEnd="20dp"
                        android:textSize="12sp" />

                    <com.google.android.gms.ads.formats.MediaView
                        android:id="@+id/ad_media"
                        android:layout_gravity="center_horizontal"
                        android:layout_width="250dp"
                        android:layout_height="175dp"
                        android:layout_marginTop="5dp" />

                    <LinearLayout
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_gravity="end"
                        android:orientation="horizontal"
                        android:paddingBottom="10dp"
                        android:paddingTop="10dp">

                        <TextView
                            android:id="@+id/ad_price"
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:paddingLeft="5dp"
                            android:paddingStart="5dp"
                            android:paddingRight="5dp"
                            android:paddingEnd="5dp"
                            android:textSize="12sp" />

                        <TextView
                            android:id="@+id/ad_store"
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:paddingLeft="5dp"
                            android:paddingStart="5dp"
                            android:paddingRight="5dp"
                            android:paddingEnd="5dp"
                            android:textSize="12sp" />

                        <Button
                            android:id="@+id/ad_call_to_action"
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:gravity="center"
                            android:textSize="12sp" />
                    </LinearLayout>
                </LinearLayout>
            </LinearLayout>
        </LinearLayout>

    </com.google.android.gms.ads.formats.UnifiedNativeAdView>
</android.support.v7.widget.CardView>

Once you have defined the new view type and layout for unified native ads, you will need to create a corresponding ViewHolder object that will hold the native ads in a RecyclerView.

You will define a new ViewHolder classes to hold a UnifiedNativeAdView, which provides methods used to register the view used for each individual asset. Registering the views in this way allows the SDK to automatically handle tasks such as:

The code snippet included below is simply a demonstration of how to locate the view used to display the headline ad asset of the ad and register it with a UnifiedNativeAdView. Don't include this code in your project yet.

(not to be included in project)

TextView headlineView = (TextView) adView.findViewById(R.id.ad_headline);
adView.setHeadlineView(headlineView);

Create and add the UnifiedNativeAdViewHolder class, shown below, to the Android project. This class will be of type ViewHolder. It will hold an ad in a RecyclerView and register the view to be used for each individual asset. The process for locating each view used to display an ad asset and registering the view with the ad view object is performed as demonstrated in the the code snippet above.

UnifiedNativeAdViewHolder.java

package com.google.android.gms.example.nativeadvancedrecyclerviewexample;

import android.support.v7.widget.RecyclerView;
import android.view.View;

import com.google.android.gms.ads.formats.MediaView;
import com.google.android.gms.ads.formats.UnifiedNativeAdView;

public class UnifiedNativeAdViewHolder extends RecyclerView.ViewHolder {

    private UnifiedNativeAdView adView;

    public UnifiedNativeAdView getAdView() {
        return adView;
    }

    UnifiedNativeAdViewHolder(View view) {
        super(view);
        adView = (UnifiedNativeAdView) view.findViewById(R.id.ad_view);

        // The MediaView will display a video asset if one is present in the ad, and the
        // first image asset otherwise.
        adView.setMediaView((MediaView) adView.findViewById(R.id.ad_media));

        // Register the view used for each individual asset.
        adView.setHeadlineView(adView.findViewById(R.id.ad_headline));
        adView.setBodyView(adView.findViewById(R.id.ad_body));
        adView.setCallToActionView(adView.findViewById(R.id.ad_call_to_action));
        adView.setIconView(adView.findViewById(R.id.ad_icon));
        adView.setPriceView(adView.findViewById(R.id.ad_price));
        adView.setStarRatingView(adView.findViewById(R.id.ad_stars));
        adView.setStoreView(adView.findViewById(R.id.ad_store));
        adView.setAdvertiserView(adView.findViewById(R.id.ad_advertiser));
    }
}

As the RecyclerView in the sample app will be displaying multiple view types, the getItemViewType method of the RecyclerView.Adapter needs to be updated to return the view type of the item at each position. To determine what the ad view type should be, you'll need to check the instance of the item to be displayed at that position in the RecyclerView.

Replace the getItemViewType() method in your RecyclerViewAdapter class with the following implementation:

RecyclerViewAdapter.java

import com.google.android.gms.ads.formats.UnifiedNativeAd;
...
@Override
public int getItemViewType(int position) {

    Object recyclerViewItem = mRecyclerViewItems.get(position);
    if (recyclerViewItem instanceof UnifiedNativeAd) {
        return UNIFIED_NATIVE_AD_VIEW_TYPE;
    }
    return MENU_ITEM_VIEW_TYPE;
}

The onCreateViewHolder method of the RecyclerView adapter is called when RecyclerView needs a new RecyclerView.ViewHolder of the given view type to represent an item. This new ViewHolder should be constructed with a new View that can represent the items of that given type. To create the UnifiedNativeAdViewHolder, you'll inflate the XML layout file you created earlier.

Replace the onCreateViewHolder() method in your RecyclerViewAdapter class with the following implementation:

RecyclerViewAdapter.java

 @Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
    switch (viewType) {
        case UNIFIED_NATIVE_AD_VIEW_TYPE:
            View unifiedNativeLayoutView = LayoutInflater.from(
                viewGroup.getContext()).inflate(R.layout.ad_unified,
                viewGroup, false);
            return new UnifiedNativeAdViewHolder(unifiedNativeLayoutView);
        case MENU_ITEM_VIEW_TYPE:
            // Fall through.
        default:
            View menuItemLayoutView = LayoutInflater.from(viewGroup.getContext())
              .inflate(R.layout.menu_item_container, viewGroup, false);
            return new MenuItemViewHolder(menuItemLayoutView);
    }
}

For each native advanced ad asset to be displayed, you must populate the asset view with the asset value from the native ad object. This process of setting the corresponding ad asset value for each ad asset view must be repeated for each native ad asset that the app will display. The populateNativeAdView method shown below performs these tasks for each of the assets of a unified native ad.

Add this method to the RecyclerViewAdapter class.

RecyclerViewAdapter.java

import android.widget.Button;
import android.widget.RatingBar;
...
private void populateNativeAdView(UnifiedNativeAd nativeAd,
                                  UnifiedNativeAdView adView) {
    // Some assets are guaranteed to be in every UnifiedNativeAd.
    ((TextView) adView.getHeadlineView()).setText(nativeAd.getHeadline());
    ((TextView) adView.getBodyView()).setText(nativeAd.getBody());
    ((Button) adView.getCallToActionView()).setText(nativeAd.getCallToAction());

    // These assets aren't guaranteed to be in every UnifiedNativeAd, so it's important to
    // check before trying to display them.
    NativeAd.Image icon = nativeAd.getIcon();

    if (icon == null) {
        adView.getIconView().setVisibility(View.INVISIBLE);
    } else {
        ((ImageView) adView.getIconView()).setImageDrawable(icon.getDrawable());
        adView.getIconView().setVisibility(View.VISIBLE);
    }

    if (nativeAd.getPrice() == null) {
        adView.getPriceView().setVisibility(View.INVISIBLE);
    } else {
        adView.getPriceView().setVisibility(View.VISIBLE);
        ((TextView) adView.getPriceView()).setText(nativeAd.getPrice());
    }

    if (nativeAd.getStore() == null) {
        adView.getStoreView().setVisibility(View.INVISIBLE);
    } else {
        adView.getStoreView().setVisibility(View.VISIBLE);
        ((TextView) adView.getStoreView()).setText(nativeAd.getStore());
    }

    if (nativeAd.getStarRating() == null) {
        adView.getStarRatingView().setVisibility(View.INVISIBLE);
    } else {
        ((RatingBar) adView.getStarRatingView())
            .setRating(nativeAd.getStarRating().floatValue());
        adView.getStarRatingView().setVisibility(View.VISIBLE);
    }

    if (nativeAd.getAdvertiser() == null) {
        adView.getAdvertiserView().setVisibility(View.INVISIBLE);
    } else {
        ((TextView) adView.getAdvertiserView()).setText(nativeAd.getAdvertiser());
        adView.getAdvertiserView().setVisibility(View.VISIBLE);
    }

    // Assign native ad object to the native view.
    adView.setNativeAd(nativeAd);
}

It is important to note, after populating the ad view, you also need to register the UnifiedNativeAd object itself with the ad view object. The call to setNativeAd in the the code above performs this operation.

The last step in configuring the RecyclerView to display native advanced ads is updating the onBindViewHolder() method of RecyclerViewAdapter. The onBindViewHolder()method is called by RecyclerView to display the data at the specified position.

This method updates the contents of the RecyclerView.ViewHolder to reflect the item at the given position in a RecyclerView. Since the RecyclerView for the app supports multiple view types, you will need to call the getItemViewType method that you updated in the previous step to determine the view type of the given position.

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

Once you know the view type, you will get the item to be displayed at the specified position from mRecyclerViewItems, and cast it to the appropriate object type. For the UNIFIED_NATIVE_AD_VIEW_TYPE, you will invoke the populateNativeAdView() method you previously implemented to populate the ad assets within the ViewHolder.

Update the onBindViewHolder() method of RecyclerViewAdapter to what's shown below.

RecyclerViewAdapter.java

@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
    int viewType = getItemViewType(position);
    switch (viewType) {
        case UNIFIED_NATIVE_AD_VIEW_TYPE:
            UnifiedNativeAd nativeAd = (UnifiedNativeAd) mRecyclerViewItems.get(position);
            populateNativeAdView(nativeAd, ((UnifiedNativeAdViewHolder) holder).getAdView());
            break;
        case MENU_ITEM_VIEW_TYPE:
            // fall through
        default:
            MenuItemViewHolder menuItemHolder = (MenuItemViewHolder) holder;
            MenuItem menuItem = (MenuItem) mRecyclerViewItems.get(position);

            // Get the menu item image resource ID.
            String imageName = menuItem.getImageName();
            int imageResID = mContext.getResources().getIdentifier(imageName, "drawable",
                mContext.getPackageName());

            // Add the menu item details to the menu item view.
            menuItemHolder.menuItemImage.setImageResource(imageResID);
            menuItemHolder.menuItemName.setText(menuItem.getName());
            menuItemHolder.menuItemPrice.setText(menuItem.getPrice());
            menuItemHolder.menuItemCategory.setText(menuItem.getCategory());
            menuItemHolder.menuItemDescription.setText(menuItem.getDescription());
    }
}

With code to display the native advanced ads handled, all that remains is loading the ads themselves.

To start, define a constant in the MainActivity class that will specify the number of native ads to load and an ArrayList instance variable to store the ads that have loaded.

MainActivity.java

import com.google.android.gms.ads.formats.NativeAd;
...
public class MainActivity extends AppCompatActivity {
...
    // The number of native ads to load and display.
    public static final int NUMBER_OF_ADS = 5;

    // The AdLoader used to load ads.
    private AdLoader adLoader;

    // List of native ads that have been successfully loaded.
    private List<UnifiedNativeAd> mNativeAds = new ArrayList<>();

    ...

Next, define an additional constant in the string resources files (NativeAdvancedRecyclerExample/app/src/main/res/values/strings.xml) that will specify the ad unit ID to be used to request native advanced ads.

strings.xml

<resources>
   ...
   <string name="ad_unit_id">ca-app-pub-3940256099942544/8135179316</string>
   ...
</resources>

Native Advanced ads are loaded via the AdLoader class, which has its own AdLoader.Builder class to customize it during creation. There are two standard native ads advanced formats: app install and content. Both are represented by UnifiedNativeAd. This object contains the ad assets for the native ad.

The code snippet included below is simply a demonstration of how to build an AdLoader that can load the unified native ads. Don't include this code in your project yet.

(not to be included in project)

adLoader = new AdLoader.Builder(context, ADMOB_AD_UNIT_ID)
    .forUnifiedNativeAd(new UnifiedNativeAd.OnUnifiedNativeAdLoadedListener() {
        @Override
        public void onUnifiedNativeAdLoaded(UnifiedNativeAd unifiedNativeAd) {
            // Show the native ad.
        }
    })
    .withAdListener(new AdListener() {
        @Override
        public void onAdFailedToLoad(int errorCode) {
            // Handle the failure by logging, altering the UI, and so on.
        }
    })
    .withNativeAdOptions(new NativeAdOptions.Builder()
        // Methods in the NativeAdOptions.Builder class can be
        // used here to specify individual options settings.
        .build())
    .build();

Since you'll need more than one ad in for the app feed, following successfully loaded or failed to load ad, we will use the loadAds method on the AdLoader which allows us to load multiple unique ads with one request. Once the ad loader has finished loading the ads, you will need to insert the native ad objects into the to the list of items to be displayed by the RecyclerView.

Add the insertAdsInMenuItems() method, shown below, to the MainActivity class to perform this operation.

MainActivity.java

private void insertAdsInMenuItems() {
    if (mNativeAds.size() <= 0) {
        return;
    }

    int offset = (mRecyclerViewItems.size() / mNativeAds.size()) + 1;
    int index = 0;
    for (NativeAd ad: mNativeAds) {
        mRecyclerViewItems.add(index, ad);
        index = index + offset;
    }
}

Next, add the loadNativeAds() method, shown below, to the MainActivity class to load the required number of native ads. After the initial ad request is made, this method will check the adLoader.isLoading() method and once the ad loader is no longer loading, invoke insertAdsInMenuItems() to add successfully loaded ads to the list of items to be displayed by the RecyclerView.

MainActivity.java

import com.google.android.gms.ads.AdListener;
import com.google.android.gms.ads.AdLoader;
import com.google.android.gms.ads.AdRequest;
import com.google.android.gms.ads.formats.NativeAd;
import com.google.android.gms.ads.formats.UnifiedNativeAd;
...
private void loadNativeAds() {

    AdLoader.Builder builder = new AdLoader.Builder(this, getString(R.string.ad_unit_id));
    adLoader = builder.forUnifiedNativeAd(
        new UnifiedNativeAd.OnUnifiedNativeAdLoadedListener() {
            @Override
            public void onUnifiedNativeAdLoaded(UnifiedNativeAd unifiedNativeAd) {
                // A native ad loaded successfully, check if the ad loader has finished loading
                // and if so, insert the ads into the list.
                mNativeAds.add(unifiedNativeAd);
                if (!adLoader.isLoading()) {
                    insertAdsInMenuItems();
                }
            }
        }).withAdListener(
        new AdListener() {
            @Override
            public void onAdFailedToLoad(int errorCode) {
                // A native ad failed to load, check if the ad loader has finished loading
                // and if so, insert the ads into the list.
                Log.e("MainActivity", "The previous native ad failed to load. Attempting to"
                    + " load another.");
                if (!adLoader.isLoading()) {
                    insertAdsInMenuItems();
                }
            }
        }).build();

    // Load the Native Express ad.
    adLoader.loadAds(new AdRequest.Builder().build(), NUMBER_OF_ADS);
}

This loadNativeAds() method should be invoked in the onCreate() method of MainActivity. Add the call to loadNativeAds(), after the addMenuItemsFromJson() method invocation in onCreate:

MainActivity.java

@Override
protected void onCreate(Bundle savedInstanceState) {
    ...

    addMenuItemsFromJson();
    loadNativeAds();
    ...
}

The final step is to present the the app feed when ads have completed loading. The loadMenu() method replaces the LoadingScreenFragment, which displays a loading spinner, with the RecyclerViewFragment, which displays the RecyclerView for the app feed. Currently, this method is invoked in onCreate() of MainActivity when the menu items for the app are ready to be shown. You will change this behavior to only display the app feed when ads are have loaded and are ready to be shown.

To start, remove the call to loadMenu()in OnCreate().

MainActivity.java

protected void onCreate(Bundle savedInstanceState) {
    ...

    loadMenu();
}

Instead, invoke loadMenu() after insertAdsInMenuItems() in loadNativeAds(), as shown below.

MainActivity.java

private void loadNativeAds() {
    ...

        .OnUnifiedNativeAdLoadedListener() {
            @Override
            public void onUnifiedNativeAdLoaded(UnifiedNativeAd unifiedNativeAd) {
                ... 
                if (!adLoader.isLoading()) {
                    insertAdsInMenuItems();
                    loadMenu();
                }
            }
        }).withAdListener(
        new AdListener() {
            @Override
            public void onAdFailedToLoad(int errorCode) {
                ... 
                if (!adLoader.isLoading()) {
                    insertAdsInMenuItems();
                    loadMenu();
                }
    ...
}

Run your project

If you run your project now, you'll see native ads (both formats - content and app install) in your feed!

Your app is now ready to display native app install and content ads using the Google Mobile Ads SDK. Run the app and scroll through the feed to see native ads inserted at regular intervals amongst menu items.

What we've covered

Next Steps

Learn More