In Android Studio choose New Project → Empty Views Activity, with Language Java and Minimum SDK API 24.
2. When to show an interstitial
An interstitial covers the whole screen, so show it only at a natural break, like between levels, never in the middle of something. Showing it at the wrong moment annoys users and breaks AdMob's rules.
3. Keep your IDs out of the code
In app/build.gradle.kts, add the import, the localProperties loader, the two build types, buildConfig = true, and the dependency, exactly as shown in Required setup. The dependency line is:
Press Sync Now. Debug builds now get Google's test IDs, and release builds read yours from local.properties, which is never committed. Your code reads the ad unit ID as BuildConfig.INTERSTITIAL_AD_UNIT_ID.
4. Add the app ID to the manifest
Inside <application> in AndroidManifest.xml, add the APPLICATION_ID meta-data with the value ${ADMOB_APP_ID}. Gradle fills it in. Without an app ID, the app crashes on launch. The SDK adds the internet permission for you.
5. Build the screen
A big Level 1 badge, a Finish level button, and a small status line that tells you whether the ad is loading or ready.
6. Start the SDK and load early
Call MobileAds.initialize on a background thread, then InterstitialAd.load(...) straight away. Loading takes a moment, so do it long before you need the ad. onAdLoaded hands you the ad; keep it in a field.
7. Show it at the break
When a level ends, check two things: is this an ad break (every second level), and is an ad loaded? If both, call ad.show(this). Otherwise just go to the next level; the game never waits for an ad.
8. Carry on afterwards
A FullScreenContentCallback tells you when the user closes the ad (onAdDismissedFullScreenContent), or if it couldn't be shown. Either way, move to the next level.
9. Load the next one
Each interstitial can be shown only once. Set the field to null and call loadAd() again, so a fresh ad is ready for the next break.
10. Run it
Tap Finish level twice. A full-screen Test Ad appears; close it and you're on level 3.
Publish with your own ads
In the AdMob console, add your app and create an ad unit.
Build a release version. Keep testing with debug builds: tapping your own live ads can get your AdMob account suspended.
What's improved over the video
The current SDK (25.5.0), the ad loaded early and shown only at a break, the game never blocked by a missing ad, a fresh ad loaded after each one, and your real IDs kept out of the code.
Files affected
Check what to add and what to replace before copying code.
Add each part where its comment says, then press Sync Now.
app/build.gradle.kts
import java.util.Properties
// At the very top of app/build.gradle.kts, after the importsval localProperties =Properties().apply{
rootProject.file("local.properties").takeIf{ it.exists()}?.inputStream()?.use{load(it)}}// Inside android { ... }
buildTypes {// Debug builds always show Google's test ads, so you can never click your own real ads by mistake.
debug {
manifestPlaceholders["ADMOB_APP_ID"]="ca-app-pub-3940256099942544~3347511713"buildConfigField("String","INTERSTITIAL_AD_UNIT_ID","\"ca-app-pub-3940256099942544/1033173712\"")}// Release builds use your own IDs from local.properties.
release {
manifestPlaceholders["ADMOB_APP_ID"]= localProperties.getProperty("ADMOB_APP_ID","")buildConfigField("String","INTERSTITIAL_AD_UNIT_ID","\"${localProperties.getProperty("ADMOB_INTERSTITIAL_ID","")}\"")}}
buildFeatures {
buildConfig =true}// Inside dependencies { ... }implementation("com.google.android.gms:play-services-ads:25.5.0")
Your real IDs (for release)
Add these lines
Where: local.properties (project folder)
Never committed, so your IDs stay out of your code and off GitHub.
local.properties (project folder)
# Only needed when you publish. Debug builds use test ads.
ADMOB_APP_ID=ca-app-pub-xxxxxxxxxxxxxxxx~xxxxxxxxxx
ADMOB_INTERSTITIAL_ID=ca-app-pub-xxxxxxxxxxxxxxxx/xxxxxxxxxx
Application code
Select a file to see its code and where it belongs.
This code uses package com.example.admobinterstitial. Change that first line to your own package, the one at the top of your MainActivity.
Loads an interstitial early, shows it after every second level, and loads the next one.
MainActivity.java
packagecom.example.admobinterstitial;importandroid.os.Bundle;importandroid.widget.TextView;importandroidx.annotation.NonNull;importandroidx.appcompat.app.AppCompatActivity;importcom.google.android.gms.ads.AdError;importcom.google.android.gms.ads.AdRequest;importcom.google.android.gms.ads.FullScreenContentCallback;importcom.google.android.gms.ads.LoadAdError;importcom.google.android.gms.ads.MobileAds;importcom.google.android.gms.ads.interstitial.InterstitialAd;importcom.google.android.gms.ads.interstitial.InterstitialAdLoadCallback;/**
* A tiny level game that shows a full-screen interstitial ad between levels.
* The ad is loaded early, so it's ready the moment it's needed, and shown only at a natural break:
* after every second level, never in the middle of play.
*/publicclassMainActivityextendsAppCompatActivity{privatestaticfinalintLEVELS_BETWEEN_ADS=2;privateInterstitialAd ad;privateint level =1;privateTextView levelText, adStatus;@OverrideprotectedvoidonCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);Screens.setUp(this,R.layout.activity_main);
levelText =findViewById(R.id.textLevel);
adStatus =findViewById(R.id.textAdStatus);if(savedInstanceState !=null) level = savedInstanceState.getInt("level",1);showLevel();// Start the Mobile Ads SDK once, off the main thread, so the app opens quickly.newThread(()->MobileAds.initialize(this, status ->{})).start();loadAd();findViewById(R.id.btnFinish).setOnClickListener(v ->finishLevel());}@OverrideprotectedvoidonSaveInstanceState(@NonNullBundle outState){super.onSaveInstanceState(outState);
outState.putInt("level", level);}/**
* Loads the next ad in the background. An ad can be shown only once, so load a new one after each.
* The ad unit ID comes from app/build.gradle.kts: a test ID while you develop, yours in release.
*/privatevoidloadAd(){
adStatus.setText(R.string.ad_loading);InterstitialAd.load(this,BuildConfig.INTERSTITIAL_AD_UNIT_ID,newAdRequest.Builder().build(),newInterstitialAdLoadCallback(){@OverridepublicvoidonAdLoaded(@NonNullInterstitialAd loaded){
ad = loaded;
adStatus.setText(R.string.ad_ready);}@OverridepublicvoidonAdFailedToLoad(@NonNullLoadAdError error){// No ad this time; the game simply carries on without one.
ad =null;
adStatus.setText(getString(R.string.ad_failed, error.getMessage()));}});}privatevoidfinishLevel(){boolean adBreak = level %LEVELS_BETWEEN_ADS==0;if(adBreak && ad !=null){
ad.setFullScreenContentCallback(newFullScreenContentCallback(){@OverridepublicvoidonAdDismissedFullScreenContent(){nextLevel();}@OverridepublicvoidonAdFailedToShowFullScreenContent(@NonNullAdError error){nextLevel();}});
ad.show(this);
ad =null;// Used up: load a fresh one for the next break.loadAd();}else{nextLevel();}}privatevoidnextLevel(){
level++;showLevel();}privatevoidshowLevel(){
levelText.setText(getString(R.string.level, level));}}