📜 ⬆️ ⬇️

Native advertising returns: Native Admob, RecyclerView and briefly about the rules

Since 2015, the situation with Admob Native ads has not changed, native advertising is still in beta release, with limited access for publishers. In the official docks, there is a new edition and some explanations about how it is planned to implement these same Native ads. We, in turn, also did not sit idly, saving up material for the next article, and, as soon as free time appeared, slightly expanded the functionality of the admobadapter library. Namely, it implemented support for scrollable native ads for RecyclerView , just as we did in the previous article for ListView .

Let's make friends RecyclerView with Native Ads


image Since the previous experience proved to be quite good, in the case of RecyclerView we decided to implement a wrapper (hereinafter the wrapper) for the adapter. This allows the developer to create his own special and unique data adapter, and we are trying not to interfere with this endeavor. The developer then links the wrapper to the adapter using dependency injection , and in RecyclerView passes the link to the wrapper. Thus, we do not interfere in the logic of the adapter. When displaying a collection, the wrapper calculates where to display the ad unit, and where the source data is displayed. Since the considered part of the library does not carry any elegant solutions and innovative constructions, I would like to elaborate more on the features and differences in the implementation of scrollable native advertising for RecyclerView from ListView . The base adapter class for RecyclerView is RecyclerView.Adapter <~> , and for ListView , the BaseAdapter . If the use of the ViewHolder pattern for the ListView is an action from the category of best-practices , then in the RecyclerView.Adapter <VH extends RecyclerView.ViewHolder> declaration, the ViewHolder type parameter is mandatory. Base class requires redefinition of methods.
abstract int getItemCount() 
returns the total number of items stored by the adapter. In essence, it is similar to the int getCount () method;
 abstract void onBindViewHolder(VH holder, int position) 
bindes the view stored in holder to the data collection item with index position . This and the following methods came to "replace" the View getView method (int position, View convertView, ViewGroup parent) from BaseAdapter - earlier, depending on the scan results, convertView to null , or created a new convertView , or bind or the current to the corresponding data;
 abstract VH onCreateViewHolder(ViewGroup parent, int viewType) 
creates and returns a viewholder of the desired type viewType . The type of the viewType container should be used in case the elements of your collection need to be displayed in different ways according to a certain attribute. In this case, the method should also be defined.
 int getItemViewType(int position) 
returns the container type for the data collection item by index position . The BaseAdapter also needed to determine the total number of container types in the getViewTypeCount method, in RecyclerView.Adapter <~>, this is no longer necessary. In our example, getViewTypeCount returns a wrapper to 3: one type for elements from the original data collection (for the adapter), and two more for advertising with content and application installation advertising (see in the previous article). At the same time, the adapter can define its own logic for displaying container types and the wrapper does not need to know anything about it. So, the source code is better than a thousand words :)
Expand
  public class AdmobRecyclerAdapterWrapper<T, V extends View> extends RecyclerView.Adapter<ViewWrapper<V>> implements AdmobFetcher.AdmobListener { //... @Override public void onBindViewHolder(ViewWrapper<V> viewHolder, int position) { if (viewHolder==null) return; switch (viewHolder.getItemViewType()) { //  -    case VIEW_TYPE_AD_INSTALL: //  viewHolder.getView()     (recycling) NativeAppInstallAdView lvi1 = (NativeAppInstallAdView) viewHolder.getView(); //   . getItem      AdmobFetcher  ,      . NativeAppInstallAd ad1 = (NativeAppInstallAd) getItem(position); //    AdViewHelper.bindInstallAdView(lvi1, ad1); break; //  -    case VIEW_TYPE_AD_CONTENT: NativeContentAdView lvi2 = (NativeContentAdView) viewHolder.getView(); NativeContentAd ad2 = (NativeContentAd) getItem(position); AdViewHelper.bindContentAdView(lvi2, ad2); break; default: //     (   ),    (  ) int origPos = getOriginalContentPosition(position); //    mAdapter.onBindViewHolder(viewHolder, origPos); } } @Override public final ViewWrapper<V> onCreateViewHolder(ViewGroup parent, int viewType) { switch (viewType) { case VIEW_TYPE_AD_INSTALL: case VIEW_TYPE_AD_CONTENT: //  viewholder    viewType -     return new ViewWrapper<V>(onCreateItemView(parent, viewType)); default: //     return mAdapter.onCreateViewHolder(parent, viewType); } } //        (.    ) private V onCreateItemView(ViewGroup parent, int viewType) { switch (viewType) { case VIEW_TYPE_AD_INSTALL: NativeAppInstallAdView lvi1 = getInstallAdView(parent); return (V)lvi1; case VIEW_TYPE_AD_CONTENT: NativeContentAdView lvi2 = getContentAdView(parent); return (V)lvi2; default: return null; } } //      ,    //... } 


Some bureaucracy


At the beginning of the article we mentioned the clarifications in the official docks for Admob native advertising and one of the main changes is the publication rules . In general terms, the process of integrating native advertising should look like this (please correct me if you made a mistake where):
  1. Developing and obtaining approval from your account manager to mockup your future advertising, and its presentation in your UI, even before the implementation of the test version of the application (Voluntary)
  2. Testing ad templates in closed mode and with admob test publish id
  3. Getting the official approval that you have with the template and with the rules of placement is all right. Our assumption is that this procedure will be available directly from your developer console in alpha / beta testing mode, or from admob dashboard
  4. Publish an approved application

A formal check on the appearance of advertising in your UI will be performed according to the already published checklist .
A comment was also added to the developer-guide , the essence of which was to prevent developers from multi-threaded loading of advertising blocks by calling the loadAd method in the context of a single AdLoader object. That is, basically, there are a little more than two options :)

An example of the implementation of the second variant can be viewed, again, in our admobadapter library (without any claims to canonicity). Since these methods have already been described in more detail in a previous article , consider the AdmobFetcher code snippets responsible for loadAd synchronization. The flag is used for this purpose.
 AtomicBoolean lockFetch = new AtomicBoolean(); 
Before calling loadAd, we check the value of this flag, and if it is set to true — another block is currently being loaded, we exit. Otherwise, set it to true and try to load a block of ads.
Expand
  private synchronized void fetchAd() { Context context = mContext.get(); if (context != null) { if(lockFetch.getAndSet(true)) return; adLoader.loadAd(getAdRequest()); } else { mFetchFailCount++; } } 

To allow ad blocks to be loaded, we should set the flag to false, this can be done by subscribing to the loadAd completion when creating the AdLoader entity, as shown below
Expand
  adLoader = new AdLoader.Builder(mContext.get(), admobUnitId) .forAppInstallAd(new NativeAppInstallAd.OnAppInstallAdLoadedListener() { @Override public void onAppInstallAdLoaded(NativeAppInstallAd appInstallAd) { lockFetch.set(false); //... } }) .forContentAd(new NativeContentAd.OnContentAdLoadedListener() { @Override public void onContentAdLoaded(NativeContentAd contentAd) { lockFetch.set(false); //... } }) .withAdListener(new AdListener() { @Override public void onAdFailedToLoad(int errorCode) { lockFetch.set(false); mFetchFailCount++; //... } }).build(); 


Instead of conclusions


So, the new wrapper for RecyclerView has changed:
  1. Creating views to display data / advertising
  2. Binding views to data / advertising
  3. Redefinition of other abstract methods of the base class.

Remained as before:
  1. Mechanism for loading ads from the AdMob server ( AdmobFetcher class)
  2. The structure of advertising views (xml) and its filling during the binding
  3. Calculation of indexes and the number of ad units / data blocks
  4. The essence of the getItemCount () , getItemId (int position) and getItemViewType (int position) methods remain the same, but their names have changed.

The dry residue from the second part of the article - the official documentation on Admob native ads continues to evolve, as if hinting to us that the procedure for integrating native advertising into an application may be non-trivial and the amount of time spent will depend not only on our development speed, but also on moderation speed / adequacy of Admob / Google staff.
We would be grateful for the statistics if you vote in the attached polls! By good tradition, we wish you a beautiful advertising in your applications!

PS: It turns out that some of the information in this article is “slightly” outdated, I give a link to a new Google doc support.google.com/admob/answer/6270315?hl=en . As time appears, I will describe the connection process on Habré.

')

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


All Articles