Android:在recyclerview中实现mopub原生广告会产生错误的商品位置和IndexOutOfBoundsException

时间:2015-10-29 08:23:24

标签: android android-recyclerview mopub twitter-fabric

在我的Android应用中,我正在尝试实施mopub原生广告。在使用这些原生广告之前,我的应用按预期正常运行。现在,当单击列表项时,它会提供outofbound异常和不正确的项目。我正在使用recyclerview并使用无限滚动,它从我的api获取项目并正确显示项目,但是当点击项目时它会提供不正确的项目。

以下是我的recyclerview适配器。

package com.example.adapters;

import android.content.Context;
import android.content.Intent;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.ImageView;
import android.widget.TextView;

import com.example.MyApplication;
import com.example.R;
import com.example.events.ErrorLoadingFeed;
import com.example.events.FeedLoaded;
import com.example.events.LoadMoreFeed;
import com.example.model.Post;
import com.example.model.Pagination;
import com.example.ui.InfoActivity;
import com.example.utils.MyAppConstants;
import com.google.gson.Gson;
import com.squareup.picasso.Picasso;

import java.util.List;

import retrofit.Callback;
import retrofit.RetrofitError;
import retrofit.client.Header;
import retrofit.client.Response;

/**
 * Created by starwar on 08/09/15.
 */
public class PostRecycleAdapter extends RecyclerView.Adapter<com.example.adapters.PostRecycleAdapter.PostViewHolder> implements Callback<List<Post>> {

    private Context mContext;
    private List<Post> mPosts;
    // Allows to remember the last item shown on screen
    private int lastPosition = -1;
    //    Pagination
    private Pagination mPagination;

    public PostRecycleAdapter(Context context, List<Post> posts) {
        mContext = context;
        mPosts = posts;
    }

    @Override
    public PostViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.list_item, parent, false);

        PostViewHolder viewHolder = new PostViewHolder(view);
        return viewHolder;
    }

    @Override
    public void onBindViewHolder(PostViewHolder holder, int position) {
        holder.bindPost(mPosts.get(position));
        // Here you apply the animation when the view is bound
        setAnimation(holder.mPostName, position);

        //check for last item
        if ((position >= getItemCount() - 1)) {
            // Loading next set of list items on scroll
            if (mPagination != null && !mPagination.getOutOfRange() && mPagination.getNextPage() != null){
                MyApplication.bus.post(new LoadMoreFeed(mPagination));
            }
        }
    }

    @Override
    public int getItemCount() {
        return mPosts == null ? 0 : mPosts.size();
    }

    /**
     * Here is the key method to apply the animation
     */
    private void setAnimation(View viewToAnimate, int position)
    {
        // If the bound view wasn't previously displayed on screen, it's animated
        if (position > lastPosition)
        {
            Animation animation = AnimationUtils.loadAnimation(mContext, android.R.anim.slide_in_left);
            viewToAnimate.startAnimation(animation);
            lastPosition = position;
        }
    }

    public class PostViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {

        public TextView mPostName;
        public ImageView mAnchorImage;

        public PostViewHolder(View itemView) {
            super(itemView);

            mPostName = (TextView) itemView.findViewById(R.id.postName);
            mAnchorImage = (ImageView) itemView.findViewById(R.id.anchorImage);

            itemView.setOnClickListener(this);
        }

        public void bindPost(Post post) {
            mPostName.setText(post.getName());

            String postImage = post.getPostImage();
            Picasso.with(mContext)
                    .load(postImage)
                    .placeholder(R.drawable.avatar_empty)
                    .into(mAnchorImage);
        }

        @Override
        public void onClick(View view) {
            int position = getAdapterPosition(); // gets item position
            Post post = mPosts.get(position);
            int postId = post.getId();
            String postName = post.getName();

            Intent intent = new Intent(mContext, InfoActivity.class);
            intent.putExtra(MyAppConstants.POST_ID, postId);
            intent.putExtra(MyAppConstants.POST_NAME, postName);
            mContext.startActivity(intent);
        }
    }

    @Override
    public void success(List<Post> posts, Response response) {
        if (mPosts == null) {
            mPosts = posts;
        } else {
            mPosts.addAll(posts);
        }

        notifyDataSetChanged();

        List<Header> headerList = response.getHeaders();
        for(Header header : headerList) {
            if ("X-Pagination".equals(header.getName())) {
                Gson gson = new Gson();
                mPagination = gson.fromJson(header.getValue(), Pagination.class);
            }
        }

        MyApplication.bus.post(new FeedLoaded(mPagination));
    }

    @Override
    public void failure(RetrofitError error) {
        Log.d("Call", " : Failed => " + error);
        MyApplication.bus.post(new ErrorLoadingFeed(error));
    }

    public void clearData() {
        if (mPosts != null) {
            mPosts.clear();
            notifyDataSetChanged();
        }
    }

    public List<Post> getPosts() {
        return mPosts;
    }
}

我正在使用此处提供的指南来展示广告 https://dev.twitter.com/mopub/native/native-android-sdk-integration

请帮忙。我可以/应该做些什么来解决这个问题。

提前致谢。

1 个答案:

答案 0 :(得分:3)

我知道这是一个老问题,但我正在寻找几个小时的答案。可能我会用这个解决方案节省一些时间。

如果您仔细查看文档:{​​{3}},您会发现:

  

如果您在原始适配器上注册了任何数据观察者,则应该在MoPubRecyclerAdapter上注册它们,以便它们接收带有内容项调整位置的消息。如果您不这样做,您收到的插入和删除消息的位置可能不准确。如果您需要本地适配器中项目的位置,请务必检查isAd(位置)并使用MoPubRecyclerAdapter#getOriginalPosition。

因此,要获得真正的位置,必须使用 MoPubRecyclerAdapter.getOriginalPosition(position_in_your_adapter)方法。