Сложность добавления нативной рекламы AdMob в Android Recyclerview - PullRequest
0 голосов
/ 09 февраля 2020

как дела? Я пытаюсь добавить нативную рекламу Google AdMob в фид повторного просмотра. Я следовал инструкциям, приведенным здесь. https://codelabs.developers.google.com/codelabs/admob-native-advanced-feed-android/#0. В основном это сработало. У меня есть реклама и сообщения отображаются. Но проблема, я думаю, заключается в количестве отображаемых элементов, публикаций моего приложения и рекламы. Я тестирую его, поэтому отображаются только четыре сообщения плюс одно собственное объявление. Но фид возвращает только три сообщения плюс одно объявление. Вот домашняя активность:

private PostAdapter postAdapter;
private List<Post> postList;
private List<String> followingList;
List<Object> mRecyclerViewItems = new ArrayList<>();

public static final int NUMBER_OF_ADS = 1;

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

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

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_home);
        mContext = HomeActivity.this;

        setupRecyclerView();
        loadNativeAds();
    }

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

        int offset = (mRecyclerViewItems.size() / mNativeAds.size()) + 1;
        Log.d(TAG, "insertAdsInMenuItems: m native ads value: " + mNativeAds);
        Log.d(TAG, "insertAdsInMenuItems: post list value: " + postList);
        Log.d(TAG, "insertAdsInMenuItems: offset value: " + offset);
        int index = 0;
        for (UnifiedNativeAd ad: mNativeAds) {
            mRecyclerViewItems.add(index, ad);
            index = index + offset;
            Log.d(TAG, "insertAdsInMenuItems: index value: " + index);
        }
    }

    private void loadNativeAds() {

        AdLoader.Builder builder = new AdLoader.Builder(this, getString(R.string.ad_mob_native_ad_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);
    }

private void setupRecyclerView(){
        recyclerView = findViewById(R.id.recycler_view_posts);
        recyclerView.setHasFixedSize(true);
        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(mContext);
        linearLayoutManager.setReverseLayout(true);
        linearLayoutManager.setStackFromEnd(true);
        recyclerView.setLayoutManager(linearLayoutManager);

        postList = new ArrayList<>();
        postAdapter = new PostAdapter(getApplicationContext(), postList, mRecyclerViewItems);
        recyclerView.setAdapter(postAdapter);

        checkFollowing();
    }

    private void checkFollowing(){
        Log.d(TAG, "checkFollowing: compile following list...");
        followingList = new ArrayList<>();
        DatabaseReference reference = FirebaseDatabase.getInstance().getReference().child("following").child(currentUserID);

        reference.addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                followingList.clear();
                for (DataSnapshot snapshot : dataSnapshot.getChildren()){
                    followingList.add(snapshot.getKey());
                    Log.d(TAG, "checkFollowing: following list array" + followingList);
                }

                displayPosts();
            }

            @Override
            public void onCancelled(@NonNull DatabaseError databaseError) {

            }
        });
    }

    private void displayPosts(){
        Log.d(TAG, "displayPosts: running....");
        allPostsReference.orderByKey().addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                postList.clear();
                for (DataSnapshot snapshot : dataSnapshot.getChildren()){
                    try{
                        Post post = snapshot.getValue(Post.class);
                        for (String id : followingList){
                            if (post.getUser_id().equals(id)){
                                postList.add(post);
                            }
                        }try{
                            if (post.getUser_id().equals(currentUserID)){
                                postList.add(post);
                            }
                        }catch (NullPointerException e){
                            e.getMessage();
                        }

                        int postCount = (int)dataSnapshot.getChildrenCount();
                        Log.d(TAG, "displayPosts: post count of my timeline: " + postCount);
                    }catch (NullPointerException e){
                        e.getMessage();
                    }catch (DatabaseException e){
                        e.getMessage();
                    }

                }
            }

            @Override
            public void onCancelled(@NonNull DatabaseError databaseError) {

            }
        });

    }

Вот так я добавляю нативную рекламу в mRecyclerViewItems и все посты в postList. Метод checkFollowing отображает только сообщения из тех, за кем я следую, и на данный момент это все сообщения в базе данных Firebase Realtime. И это соответствующие части класса Post Adapter:

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

    private static final String TAG = "PostAdapter";

    // 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;

    public Context mContext;
    public List<Post> mPost;
    public List<Object> mRecyclerViewItems;

    public PostAdapter(Context mContext, List<Post> mPost, List<Object> mRecyclerViewItems) {
        this.mContext = mContext;
        this.mPost = mPost;
        this.mRecyclerViewItems = mRecyclerViewItems;
    }

    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        switch (viewType){
            case UNIFIED_NATIVE_AD_VIEW_TYPE:
                View unifiedNativeLayoutView = LayoutInflater.from(
                        parent.getContext()).inflate(R.layout.layout_native_express_ad_container, parent, false);
                return new UnifiedNativeAdViewHolder(unifiedNativeLayoutView);

            case MENU_ITEM_VIEW_TYPE:
                //fall through

            default:
                View view = LayoutInflater.from(mContext).inflate(R.layout.layout_post_item, parent, false);
                return new PostViewHolder(view);
        }
    }

    @Override
    public void onBindViewHolder(@NonNull final 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:
                //follow through

            default:
                final PostViewHolder postViewHolder = (PostViewHolder) holder;
                Post post = (Post) mPost.get(position);
                final String postKey = post.getPost_key();

                mAuth = FirebaseAuth.getInstance();
                currentUserID = mAuth.getCurrentUser().getUid();
                publicUserReference = FirebaseDatabase.getInstance().getReference().child("public_user");
                allPostsReference = FirebaseDatabase.getInstance().getReference().child("all_posts");

                //some sample methods
                postViewHolder.setInitialLayouts(postKey);
                mVotes.setTextForVoteButtons(postKey, postViewHolder.voteOne, postViewHolder.voteTwo, postViewHolder.voteThree, postViewHolder.voteFour);
                postViewHolder.getProfilephotoFullnameUsername(postKey);
                postViewHolder.getVoteText(postKey);
                postViewHolder.getDate(postKey);
                postViewHolder.displayPhoto(postKey);
}

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

    @Override
    public int getItemViewType(int position) {

        try{
            Object recyclerViewItem = mRecyclerViewItems.get(position);
            if (recyclerViewItem instanceof UnifiedNativeAd) {
                return UNIFIED_NATIVE_AD_VIEW_TYPE;
            }
        }catch (IndexOutOfBoundsException e){
            e.printStackTrace();
        }
        return MENU_ITEM_VIEW_TYPE;
    }

Извините, если кода много, я просто запутался. Как я уже сказал, только три из моих четырех сообщений в базе данных возвращаются. Это как если бы родное объявление заняло свое место вместо того, чтобы быть добавленным в ленту вместе с элементами поста. Есть ли что-то, что мне не хватает? Должен ли я отправлять что-то, отличное от Home Activity, в почтовый адаптер? Любая помощь будет оценена. Спасибо.

1 Ответ

0 голосов
/ 02 мая 2020

Таким образом, у вас есть List<Post> и Ads двух типов данных, которые необходимо представить в один RecyclerView. Итак, теперь вам нужно объединить обе данные в один источник данных, который будет использоваться в RecyclerView.

Вот пример:

Первый : создайте класс данных, который объединит Post и Ads с именем PostAdsData:

public class PostAdsData {
    public int getType() {
        return type;
    }

    public UnifiedNativeAd getAds() {
        return ads;
    }

    public Post getPost() {
        return post;
    }

    public int type; // 1 is ads and 2 is post
    public UnifiedNativeAd ads;
    public Post post;
}

Второй: Ваш адаптер должен выглядеть следующим образом:

public class YourAdapter 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;

    public List<PostAdsData> postAdsDataList;

    public PostAdapter(Context mContext) {
       this.context = mContext;
    }

    public void setPostAdsDataList(List<PostAdsData> postAdsData){ // we set the data for the recyclerView here 
        this.postAdsDataList = postAdsData;
        notifyDataSetChanged();
    }

    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        switch (viewType) {
            // here do your thing as usual 
        }
    }

    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, final int position) {
        int viewType = getItemViewType(position);

        switch (viewType){
            // here switch viewType as usual,but refer the data from postAdsDataList
        }

     }

    @Override
    public int getItemViewType(int position) {
        if(postAdsDataList.get(position).getType() == 1){
            return  UNIFIED_NATIVE_AD_VIEW_TYPE;
        }else{
            return MENU_ITEM_VIEW_TYPE;
        }
    }

    @Override
    public int getItemCount() {
        if (postAdsDataList != null) {
            return postAdsDataList.size();
        } else {
            return 0;
        }
    }

}

Третий: в вашем HomeActivity, так что здесь вам нужно установить data (Post) в RecyclerView, вам необходимо «преобразовать» данные внутри List<Post> в List<PostAdsData> следующим образом:

private void displayContent(List<Post> posts){

    List<PostAdsData> postAdsDataList = new ArrayList<>();

    for(Post item : posts) {
        PostAdsData data = new PostAdsData();
        data.ads = null;
        data.post = item;
        data.type = 2; // here 1 for ads, 2 will be post
        postAdsDataList.add(data);
    }

    yourAdapter.setPostAdsDataList(postAdsDataList); // here set in the Posts data into the recyclerView
}

displayContent() Функция выше должна вызываться после получения Данные из Firebase я предположил. Так это будет выглядеть так:

private void displayPosts(){

    //ALL OTHER STUFF 
    @Override
    public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
       for(....){
         // after your for loop
         // then all the Post will added inside the List<Post>
       }

       // then we called  here 
       displayContent(postList) // your postList
    }
}

Итак, мы закончили вставку posts. Поэтому, когда вы получаете UnifiedNativeAd от Google Admob, нам также необходимо «преобразовать» UnifiedNativeAd в postAdsData объект, например так:

// add this to YourAdapter class 
public void insertAdsToRecyclerView(UnifiedNativeAd ad){ // if more than 1 ads,then here should be a list,and use for loop at the code below

    PostAdsData adsData = new PostAdsData();
    adsData.post = null;
    adsData.ads = ad;
    adsData.type = 1;

    postAdsDataList.add(0,adsData); // here will add the ads to the 1st item of the list
    notifyItemInserted(0);
}

Тогда в вашем insertAdsInMenuItems() станет это:

private void insertAdsInMenuItems() {
   postAdapter.insertAdsToRecyclerView(mNativeAds.get(0))// cause i seen you request for 1 ad only
}

Надеюсь, вы поняли идею. Теперь мы успешно объединили Post и Ad в 1 источник данных. Так что нам будет проще представить в RecylerView.

...