📜 ⬆️ ⬇️

Integrating Admob Native Ads into ListView

In the spring of 2015, a new way of displaying ad units, namely Native ads (hereinafter referred to as native advertising), which is currently in beta release mode, was announced as part of Google Admob. Plus native advertising - it is highly adaptable to the design of the application, which allows you to show ads in such a way that it does not catch the eye and does not interfere with the work with the application. The article will mark certain moments that arose during the process of integrating Admob Native Ads into your own application (an example of what happened is shown in the picture, the names are deleted), and a practical example with code snippets is shown (you can download the full version here and see .

image A rather popular way to integrate native ads into mobile applications is to display blocks of ads in the list through an equal amount of data elements. For example, in the popular client myMail, a block of advertisements is displayed in the inbox every N letters. This experience does not shine with novelty, and has previously been successfully applied on Twitter. It is worth mentioning that Admob has certain rules for advertising in mobile applications , the failure of which is fraught with blocking Admob account. An important point - application developers have the right to display no more than 3 advertising banners on 1 page with scrollable content, and so that only 1 banner is displayed at a time in the visible part of the screen. These rules relate to banners, and it is still unknown whether the new rules regarding native advertising will be given. Nevertheless, it is worth considering this when developing.

So, the process of displaying native advertising in the list can be divided into the following steps:

  1. Downloading a certain number of ad units from the Admob server and storing them in a certain collection of objects (the ad loading process may not be fast, so it’s better to have several ad units ready).
  2. Issuance of downloaded advertising objects to the list adapter on request and, possibly, asynchronous loading of the next block.
  3. Determining the type of displayed list item (advertisement or data) based on its position and the total number of items in the adapter.
  4. Display layout advertising in the event that the displayed list item can be displayed as an advertising block (for example, if an element with a suitable position for advertising and at least one block of advertising has already been loaded with Admob).
  5. Publish data from the ad unit to the appropriate layout of the list item.

0. Project preparation


Create a new project, or open an existing one. First, you should connect com.google.android.gms: play-services-ads to the project module where you plan to add advertising displaying functionality, you can do this by adding a line to the module's build.gradle :
')
dependencies { //… compile 'com.google.android.gms:play-services-ads:7.8.0' //… } 

You may need to update the Google Play Services library in the Android SDK Manager.

1. Download ads from Admob


Deciding not to reinvent your bike, your humble servant took as a basis the functionality for native advertising from the Yahoo fetchr library , sharpening it under Admob, since the library is distributed under the Apache 2.0 license. To load blocks of advertising, create the class AdmobFetcher.java and initialize its fields:

 public class AdmobFetcher { private static final int PREFETCHED_ADS_SIZE = 2; private static final int MAX_FETCH_ATTEMPT = 4; private AdLoader adLoader; private List<NativeAd> mPrefetchedAdList = new ArrayList<NativeAd>(); private Map<Integer, NativeAd> adMapAtIndex = new HashMap<Integer, NativeAd>(); private int mNoOfFetchedAds; private int mFetchFailCount; private WeakReference<Context> mContext = new WeakReference<Context>(null); private String admobReleaseUnitId; } 

Where:
PREFETCHED_ADS_SIZE - the maximum number of pre-loaded ad units; MAX_FETCH_ATTEMPT - limit attempts to download ads;
adLoader - the entity of the com.google.android.gms.AdLoader class, which is responsible for downloading ads from the Admob server;
mPrefetchedAdList - collection with preloaded ads; adMapAtIndex - mapping for getting the necessary ad unit by index;
mNoOfFetchedAds , mFetchFailCount - the number of loaded ads and unsuccessful downloads, respectively; mContext - context, we store it in WeakReference to avoid changes, for example, when the device is rotated (this is the Yahoo fetchr implementation and it was decided to leave it as it is);
admobReleaseUnitId is the release unitId , which is used only to publish the release. Presumably, it will be possible to generate it in the Admob console , as well as for banner ads, but for now we are using the test unitId specified in the manual .

An important point - during debugging, it is strongly recommended to use the test unitId , otherwise Admob may consider clicks on ad units for cheating with all the ensuing consequences.

Add the adLoader initialization method to the class:

Expand
 private synchronized void setupAds() { //  unitId. String admobUnitId = mContext.get().getResources().getString(R.string.test_admob_unit_id); // String admobUnitId = mAdmobReleaseUnitId; adLoader = new AdLoader.Builder(mContext.get(), admobUnitId) .forAppInstallAd(new NativeAppInstallAd.OnAppInstallAdLoadedListener() { @Override public void onAppInstallAdLoaded(NativeAppInstallAd appInstallAd) { onAdFetched(appInstallAd); } }) .forContentAd(new NativeContentAd.OnContentAdLoadedListener() { @Override public void onContentAdLoaded(NativeContentAd contentAd) { onAdFetched(contentAd); } }) .withAdListener(new AdListener() { @Override public void onAdFailedToLoad(int errorCode) { mFetchFailCount++; // -   ensurePrefetchAmount(); //,    //    } }) .withNativeAdOptions(new NativeAdOptions.Builder().build()).build(); } 


Briefly by the method, first we get unitId , in debugging we use only the test one, for this we add the following line to res \ values ​​\ strings.xml :

 <string name="test_admob_unit_id">ca-app-pub-3940256099942544/2247696110</string> 

Then create an adLoader object. Currently, Admob has two types of native advertising that differ in appearance and structure: NativeAppInstallAd is the essence of the offer to install some third-party application, and NativeContentAd is a regular advertisement with some content. Both types are inherited from the base NativeAd . We process the receipt of both types of advertising in calls forAppInstallAd and in forContentAd . Possible errors during loading should be handled in a call withAdListener , passing an AdListener object with an overloaded onAdFailedToLoad . Calling withNativeAdOptions allows you to specify specific parameters for loading, for example, instead of images, only accept Url (by default, the option to load the images themselves), or the preferred orientation of the images. In detail with these methods and types can be found again in the above manual.

Method called upon successful upload:

 private synchronized void onAdFetched(NativeAd adNative) { if (canUseThisAd(adNative)) { mPrefetchedAdList.add(adNative); //    mNoOfFetchedAds++; } //    mFetchFailCount = 0; ensurePrefetchAmount(); //        notifyObserversOfAdSizeChange(); } 

In fact, in canUseThisAd, we check whether the correct information was received in the NativeAd object and add it to the collection of preloaded mPrefetchedAdList . Next comes the game with the mNoOfFetchedAds and mFetchFailCount counters , and in ensurePrefetchAmount we check whether a sufficient amount of advertising has been preloaded. I will give the code of the methods called above:

Expand
 //        private void notifyObserversOfAdSizeChange() { for (AdmobListener listener : mAdNativeListeners) { listener.onAdCountChanged(); } } //,    ,   ,   , //         private synchronized void ensurePrefetchAmount() { if (mPrefetchedAdList.size() < PREFETCHED_ADS_SIZE && (mFetchFailCount < MAX_FETCH_ATTEMPT)) { fetchAd(); } } //    ,  private boolean canUseThisAd(NativeAd adNative) { if (adNative != null) { CharSequence header = null, body = null; if (adNative instanceof NativeContentAd) { NativeContentAd ad = (NativeContentAd) adNative; header = ad.getHeadline(); body = ad.getBody(); } else if (adNative instanceof NativeAppInstallAd) { NativeAppInstallAd ad = (NativeAppInstallAd) adNative; header = ad.getHeadline(); body = ad.getBody(); } //   ,      :) return !TextUtils.isEmpty(header)&& !TextUtils.isEmpty(body); } } return false; } 


Let's write the implementation of loading ads:

Expand
 //       public synchronized void prefetchAds(Context context) { mContext = new WeakReference<Context>(context); setupAds(); // (. ) fetchAd(); //   } private synchronized void fetchAd() { Context context = mContext.get(); if (context != null) { //  adLoader.loadAd(getAdRequest()); } else { mFetchFailCount++; // ,     } } 


The getAdRequest method is implemented to build an AdRequest request using AdRequest.Builder . With the development of native advertising, Admob will probably be expanded by calling adBldr.addTestDevice (<device ID>) , in order to exclude some test devices from a real unitId , as already implemented in banner advertising. By the way, the call to addTestDevice is currently ignored, as I was indicated here .

 private synchronized AdRequest getAdRequest() { AdRequest.Builder adBldr = new AdRequest.Builder(); //.addTestDevice(AdRequest.DEVICE_ID_EMULATOR); //       unitId return adBldr.build(); } 

2. Issuance of downloaded advertisement objects to the list adapter


And, perhaps, the most important method in AdmobFetcher.java is the method of obtaining an ad unit using an external index with which the list adapter operates (this secret will be revealed a little further).

Expand
 public synchronized NativeAd getAdForIndex(final int index) { //        NativeAd adNative = adMapAtIndex.get(index); //        ,          if (adNative == null && mPrefetchedAdList.size() > 0) { //      adNative = mPrefetchedAdList.remove(0); //       ,    if (adNative != null) { adMapAtIndex.put(index, adNative); } } // ,     ensurePrefetchAmount(); return adNative; } 


Mapping is used to link external indexes and ad units. We will also add a subscription method for changing the amount of downloaded advertising:

 public synchronized void addListener(AdmobListener listener) { mAdNativeListeners.add(listener); } 

And create an appropriate interface for subscribers:

 public interface AdmobListener { void onAdCountChanged(); } 

3. Determine the type of displayed list item in the adapter


At this stage, you need to create a list adapter with the functionality to display ad units through an equal number of elements. To avoid mixing the ad code with the logic of displaying data in the list, which in itself can be quite complex, it makes sense to implement them in various classes. Perhaps someone would prefer inheritance, I also selected the aggregation and created the adapter-wrapper AdmobAdapterWrapper , in order to abstract from the data source and the logic of their display.

In practice, it will look like this: first , create an instance of the adapter that binds the list to a data source, for example, ABCListAdapter ; secondly , create an instance of AdmobAdapterWrapper to display in the list of advertisements; thirdly , we pass to the AdmobAdapterWrapper a link to the created instance of the ABCListAdapter ; fourth , specify the AdmobAdapterWrapper instance as an adapter for the ListView view element. Thus, for any call to notifyDataSetChanged in the ABCListAdapter adapter, the AdmobAdapterWrapper wrapper can also call notifyDataSetChanged and display the advertisement in the view item. So, let's create the AdmobAdapterWrapper.java list adapter class:

Expand
 public class AdmobAdapterWrapper extends BaseAdapter implements AdmobFetcher.AdmobListener { private BaseAdapter mAdapter; public BaseAdapter getAdapter() { return mAdapter; } public void setAdapter(BaseAdapter adapter) { mAdapter = adapter; mAdapter.registerDataSetObserver(new DataSetObserver() { @Override public void onChanged() { notifyDataSetChanged(); } @Override public void onInvalidated() { notifyDataSetInvalidated(); } }); } AdmobFetcher adFetcher; Context mContext; private final static int VIEW_TYPE_COUNT = 2; private final static int VIEW_TYPE_AD_CONTENT = 1; private final static int VIEW_TYPE_AD_INSTALL = 2; private final static int DEFAULT_NO_OF_DATA_BETWEEN_ADS = 10; private final static int DEFAULT_LIMIT_OF_ADS = 3; private int mNoOfDataBetweenAds; public int getNoOfDataBetweenAds() { return mNoOfDataBetweenAds; } public void setNoOfDataBetweenAds(int mNoOfDataBetweenAds) { this.mNoOfDataBetweenAds = mNoOfDataBetweenAds; } private int mLimitOfAds; public int getLimitOfAds() { return mLimitOfAds; } public void setLimitOfAds(int mLimitOfAds) { this.mLimitOfAds = mLimitOfAds; } private int mContentAdsLayoutId; public int getContentAdsLayoutId() { return mContentAdsLayoutId; } public void setContentAdsLayoutId(int mContentAdsLayoutId) { this.mContentAdsLayoutId = mContentAdsLayoutId; } private int mInstallAdsLayoutId; public int getInstallAdsLayoutId() { return mInstallAdsLayoutId; } public void setInstallAdsLayoutId(int mInstallAdsLayoutId) { this.mInstallAdsLayoutId = mInstallAdsLayoutId; } public AdmobAdapterWrapper(Context context) { setNoOfDataBetweenAds(DEFAULT_NO_OF_DATA_BETWEEN_ADS); setLimitOfAds(DEFAULT_LIMIT_OF_ADS); setContentAdsLayoutId(R.layout.adcontentlistview_item); setInstallAdsLayoutId(R.layout.adinstalllistview_item); mContext = context; adFetcher = new AdmobFetcher(); adFetcher.addListener(this); //     adFetcher.prefetchAds(context); } @Override public void onAdCountChanged() { notifyDataSetChanged(); } } 


AdmobAdapterWrapper implements the AdmobFetcher.AdmobListener interface, respectively, in the constructor, we create an AdmobFetcher instance, and then subscribe to change the number of loaded ads in this way:

 adFetcher = new AdmobFetcher(); adFetcher.addListener(this); 

Consider some class fields:

mAdapter: BaseAdapter - field for aggregation of data adapter, in our example it is an instance of ABCListAdapter , has get- and set-accessor. In the set-acessor after writing in the field we subscribe to changes in the data adapter;
adFetcher: AdmobFetcher - an object that is responsible for downloading ads from the Admob server; VIEW_TYPE_COUNT: int - the number of types of ad units, as mentioned earlier, is currently 2;
VIEW_TYPE_AD_CONTENT: int - an identifier of the type of advertisement with content;
VIEW_TYPE_AD_INSTALL: int - identifier of the type of advertisement for installing applications;
mNoOfDataBetweenAds: int - the interval (number) of data elements through which to display ad units and its default value DEFAULT_NO_OF_DATA_BETWEEN_ADS: int , equal to 10;
mLimitOfAds: int - the maximum number of ad units in the list and its default value is DEFAULT_LIMIT_OF_ADS: int equal to 3 (again, Admob rules and recommendations );
mContentAdsLayoutId: int and mInstallAdsLayoutId: int is the layout id for advertising with content and for advertising installing applications, respectively (more details about them are written here ). Layout id for ad units will be discussed later. At the end is the class constructor and implementation for AdmobFetcher.AdmobListener .

In order to determine the type of the displayed element (advertisement or data) we add the following methods:

Expand
 @Override public int getCount() { if (mAdapter != null) { int noOfAds = getAdsCountToPublish(); return mAdapter.getCount() > 0 ? mAdapter.getCount() + noOfAds : 0; } else { return 0; } } public int getAdsCountToPublish(){ int noOfAds = Math.min(adFetcher.getFetchedAdsCount(), mAdapter.getCount() / getNoOfDataBetweenAds()); return Math.min(noOfAds, getLimitOfAds()); } @Override public Object getItem(int position) { if (canShowAdAtPosition(position)) { //         //:      5 ,   position=11 //adPos   1 int adPos = getAdIndex(position); return adFetcher.getAdForIndex(adPos); } else { int origPos = getOriginalContentPosition(position); return mAdapter.getItem(origPos); } } @Override public long getItemId(int position) { return position; } @Override public int getViewTypeCount() { return VIEW_TYPE_COUNT + getAdapter().getViewTypeCount(); } @Override public int getItemViewType(int position) { if (canShowAdAtPosition(position)) { int adPos = getAdIndex(position); NativeAd ad = adFetcher.getAdForIndex(adPos); return ad instanceof NativeAppInstallAd ? VIEW_TYPE_AD_INSTALL : VIEW_TYPE_AD_CONTENT; } else { int origPos = getOriginalContentPosition(position); return mAdapter.getItemViewType(origPos); } } protected int getOriginalContentPosition(int position) { int noOfAds = getAdsCountToPublish(); // No of spaces for ads in the dataset, according to ad placement rules // ,   ,      int adSpacesCount = position / (getNoOfDataBetweenAds() + 1); return position - Math.min(adSpacesCount, noOfAds); } protected boolean canShowAdAtPosition(int position) { //    ,      ? //      ? return isAdPosition(position) && isAdAvailable(position); } private int getAdIndex(int position) { return (position / getNoOfDataBetweenAds()) - 1; } private boolean isAdPosition(int position) { return (position + 1) % (getNoOfDataBetweenAds() + 1) == 0; } private boolean isAdAvailable(int position) { int adIndex = getAdIndex(position); //          return position >= getNoOfDataBetweenAds() && adIndex >= 0 && adIndex < getLimitOfAds() && adFetcher.getFetchedAdsCount() > adIndex; } 


Where getCount is an overridden method of the BaseAdapter class that returns the total number of elements, including ad units. For example, if the data source has 10 items and the ad display interval mNoOfDataBetweenAds is set to 5, then getCount returns 12.

getAdsCountToPublish - returns the number of ad units that can be published to the list, as the smallest of the following values: the specified maximum number of ad units in the getLimitOfAds () list, the actual number of ad units loaded in adFetcher, and the potential number of advertisements in the list (i.e., how many we can place in this list in principle, based on the number of elements and the interval of advertising), as a ratio:

 mAdapter.getCount() / getNoOfDataBetweenAds() 

getItem is an overridden BaseAdapter method, in this implementation it checks (by calling the canShowAdAtPosition method) whether the ad unit can be displayed at the specified position , and if so, returns a NativeAd object from adFetcher , otherwise, an item from the data source.

You should also pay attention to the fact that before picking up an advertisement or an element, the position is converted to the corresponding index of the ad unit ( getAdIndex ) or the index of the data source ( getOriginalContentPosition ). getViewTypeCount is an overridden BaseAdapter method that calculates the number of view item types in the list as the sum of the view item types in the mAdapter and two types of ads, Install and Content . getItemViewType is another overridden BaseAdapter method that returns the type of the view item depending on the position indicated. getOriginalContentPosition and getAdIndex are methods that convert the index of the display element position to the original index of the element from the data source, as if there were no ads, and the index of the ad unit stored in adFetcher, respectively. canShowAdAtPosition - checks whether the ad block ( isAdPosition ) can be displayed in the ListView element with the position index, taking into account how much advertising is actually preloaded and available for display ( isAdAvailable ).

4. Display layout advertising


Create a new res \ layout \ adcontentlistview_item.xml : to display ads with content. This markup does not differ in optimality and it makes sense to get rid of unnecessary nesting of elements, but this option is quite suitable as a test example. The only point to which you should pay attention is the root element NativeContentAdView , which is used to automate the processing of user clicks or other actions with the block of advertising and place it on the shoulders of Google Play Services and Admob.

Expand
 <com.google.android.gms.ads.formats.NativeContentAdView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <TextView android:id="@+id/tvHeader" android:layout_width="match_parent" android:layout_height="wrap_content"/> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:layout_marginTop="2dp"> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/ivLogo"/> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" android:layout_marginLeft="5dp"> <TextView android:id="@+id/tvDescription" android:layout_width="wrap_content" android:layout_height="wrap_content"/> <TextView android:id="@+id/tvAdvertiser" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="1dp"/> </LinearLayout> </LinearLayout> <ImageView android:layout_width="match_parent" android:layout_height="200dp" android:id="@+id/ivImage" android:scaleType="center" android:layout_marginTop="2dp" android:background="#00FFFFFF"/> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingLeft="10dp" android:paddingRight="10dp" android:layout_marginTop="2dp" android:id="@+id/btnAction"/> </LinearLayout> </com.google.android.gms.ads.formats.NativeContentAdView> 


Similarly, create and markup for the type of advertising with the proposal to install the application res \ layout \ adinstalllistview_item.xml

Expand
 <com.google.android.gms.ads.formats.NativeAppInstallAdView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <TextView android:id="@+id/tvHeader" android:layout_width="match_parent" android:layout_height="wrap_content"/> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:layout_marginTop="2dp"> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/ivLogo"/> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" android:layout_marginLeft="5dp"> <TextView android:id="@+id/tvDescription" android:layout_width="wrap_content" android:layout_height="wrap_content"/> <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="1dp"> <TextView android:id="@+id/tvStore" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true"/> <TextView android:id="@+id/tvPrice" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true"/> </RelativeLayout> </LinearLayout> </LinearLayout> <ImageView android:layout_width="match_parent" android:layout_height="200dp" android:id="@+id/ivImage" android:scaleType="center" android:layout_marginTop="2dp" android:background="#00FFFFFF"/> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingLeft="10dp" android:paddingRight="10dp" android:layout_marginTop="2dp" android:id="@+id/btnAction"/> </LinearLayout> </com.google.android.gms.ads.formats.NativeAppInstallAdView> 


We will override the getView method in AdmobAdapterWrapper.java so that the adapter-wrapper can create the required View and publish data to it by the type of the displayed element

Expand
 @Override public View getView(int position, View convertView, ViewGroup parent) { switch (getItemViewType(position)) { case VIEW_TYPE_AD_INSTALL: NativeAppInstallAdView lvi1; NativeAppInstallAd ad1 = (NativeAppInstallAd) getItem(position); if (convertView == null) { lvi1 = getInstallAdView(parent, ad1); } else { lvi1 = (NativeAppInstallAdView) convertView; bindInstallAdView(lvi1, ad1); } return lvi1; case VIEW_TYPE_AD_CONTENT: NativeContentAdView lvi2; NativeContentAd ad2 = (NativeContentAd) getItem(position); if (convertView == null) { lvi2 = getContentAdView(parent, ad2); } else { lvi2 = (NativeContentAdView) convertView; bindContentAdView(lvi2, ad2); } return lvi2; default: int origPos = getOriginalContentPosition(position); return mAdapter.getView(origPos, convertView, parent); } } 


Where in case the displayed list item is an advertisement, we show the View for the corresponding ad unit, otherwise in the default section we show the View from the mAdapter .

To create new instances of View Ads, add the following methods for both types of ads:

Expand
 private NativeContentAdView getContentAdView(ViewGroup parent, NativeContentAd ad) { LayoutInflater inflater = (LayoutInflater) parent.getContext() .getSystemService(Context.LAYOUT_INFLATER_SERVICE); NativeContentAdView adView = (NativeContentAdView) inflater .inflate(getContentAdsLayoutId(), parent, false); bindContentAdView(adView, ad); return adView; } private NativeAppInstallAdView getInstallAdView(ViewGroup parent, NativeAppInstallAd ad) { LayoutInflater inflater = (LayoutInflater) parent.getContext() .getSystemService(Context.LAYOUT_INFLATER_SERVICE); NativeAppInstallAdView adView = (NativeAppInstallAdView) inflater .inflate(getInstallAdsLayoutId(), parent, false); bindInstallAdView(adView, ad); return adView; } 


5. Publishing data from the ad unit to the layout


In order to publish data from the ad unit, we implement the following methods in AdmobAdapterWrapper.java :

Expand
 private void bindContentAdView(NativeContentAdView adView, NativeContentAd ad) { if (adView == null || ad == null) return; TextView tvHeader = (TextView) adView.findViewById(R.id.tvHeader); tvHeader.setText(ad.getHeadline()); adView.setHeadlineView(tvHeader); TextView tvDescription = (TextView) adView.findViewById(R.id.tvDescription); tvDescription.setText(ad.getBody()); adView.setBodyView(tvDescription); ImageView ivLogo = (ImageView) adView.findViewById(R.id.ivLogo); if(ad.getLogo()!=null) ivLogo.setImageDrawable(ad.getLogo().getDrawable()); adView.setLogoView(ivLogo); Button btnAction = (Button) adView.findViewById(R.id.btnAction); btnAction.setText(ad.getCallToAction()); adView.setCallToActionView(btnAction); TextView tvAdvertiser = (TextView) adView.findViewById(R.id.tvAdvertiser); tvAdvertiser.setText(ad.getAdvertiser()); adView.setAdvertiserView(tvAdvertiser); ImageView ivImage = (ImageView) adView.findViewById(R.id.ivImage); if (ad.getImages() != null && ad.getImages().size() > 0) { ivImage.setImageDrawable(ad.getImages().get(0).getDrawable()); ivImage.setVisibility(View.VISIBLE); } else ivImage.setVisibility(View.GONE); adView.setImageView(ivImage); adView.setNativeAd(ad); } private void bindInstallAdView(NativeAppInstallAdView adView, NativeAppInstallAd ad) { if (adView == null || ad == null) return; TextView tvHeader = (TextView) adView.findViewById(R.id.tvHeader); tvHeader.setText(ad.getHeadline()); adView.setHeadlineView(tvHeader); TextView tvDescription = (TextView) adView.findViewById(R.id.tvDescription); tvDescription.setText(ad.getBody()); adView.setBodyView(tvDescription); ImageView ivLogo = (ImageView) adView.findViewById(R.id.ivLogo); if(ad.getIcon()!=null) ivLogo.setImageDrawable(ad.getIcon().getDrawable()); adView.setIconView(ivLogo); Button btnAction = (Button) adView.findViewById(R.id.btnAction); btnAction.setText(ad.getCallToAction()); adView.setCallToActionView(btnAction); TextView tvStore = (TextView) adView.findViewById(R.id.tvStore); tvStore.setText(ad.getStore()); adView.setStoreView(tvStore); TextView tvPrice = (TextView) adView.findViewById(R.id.tvPrice); tvPrice.setText(ad.getPrice()); adView.setPriceView(tvPrice); ImageView ivImage = (ImageView) adView.findViewById(R.id.ivImage); if (ad.getImages() != null && ad.getImages().size() > 0) { ivImage.setImageDrawable(ad.getImages().get(0).getDrawable()); ivImage.setVisibility(View.VISIBLE); } else ivImage.setVisibility(View.GONE); adView.setImageView(ivImage); adView.setNativeAd(ad); } } 


The methods are similar. The main point is the registration of all elements from the layout we created in the NativeAdView instance , for example:

 TextView tvHeader = (TextView) adView.findViewById(R.id.tvHeader); tvHeader.setText(ad.getHeadline()); //  adView   tvHeader adView.setHeadlineView(tvHeader); 

At the end of both methods, the NativeAd object itself is registered in the NativeAdView . So, having in the markup (for example, in the res \ layout \ activity_main.xml ) list:

 <ListView android:id="@+id/lvMessages" android:layout_width="match_parent" android:layout_height="match_parent"/> 

You can use AdmobAdapterWrapper as follows (in some class Activity , which displays this list).

Expand
 ListView lvMessages; AdmobAdapterWrapper adapterWrapper; //... @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initListViewItems(); } private void initListViewItems() { lvMessages = (ListView) findViewById(R.id.lvMessages); //    ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1); adapterWrapper = new AdmobAdapterWrapper(this); adapterWrapper.setAdapter(adapter); //     -. //   layout    //adapterWrapper.setInstallAdsLayoutId(R.layout.your_installad_layout); //adapterWrapper.setcontentAdsLayoutId(R.layout.your_installad_layout); //       adapterWrapper.setLimitOfAds(3); //   10       . //   ,      Admob's   //,           . adapterWrapper.setNoOfDataBetweenAds(10); lvMessages.setAdapter(adapterWrapper); //    - //    final String sItem = "item #"; ArrayList<String> lst = new ArrayList<String>(100); for(int i=1;i<=100;i++) lst.add(sItem.concat(Integer.toString(i))); adapter.addAll(lst); adapter.notifyDataSetChanged(); } //   @Override protected void onDestroy() { super.onDestroy(); adapterWrapper.destroyAds(); } 


The result can be approximately the same as shown in the “gif”.

image

findings


All code can be viewed here . Since there is not much time for the development of the library, I will be glad to see your "forks". In the near future development plans the following tasks:

  1. AdmobAdapterWrapper bindInstallAdView bindContentAdView, layout .
  2. Gradle Android library jCenter.
  3. RecyclerView

, , :
• : 3 1 , 1
UnitId , Admob .
• logcat
W/Ads﹕ Failed to load ad: 0
, as described, for example, here try to run not on an emulator, but on a real device, and without access to the root. Another reason may be a lack of advertising on the Admob server, in this case, you should wait some time after the first launch and try again (this is how it was with me).

I wish you a beautiful native advertising in your applications!

Source: https://habr.com/ru/post/269517/


All Articles