我正在尝试开发一个实现无限滚动Recyclerview的应用程序,当recyclerview到达底部时,它会加载50个项目,并且每10个项目之间放置一个admob原生广告。问题是滚动,我得到空指针异常。我试图弄清楚在活动类的onscroll方法上添加新项目的逻辑。这是异常的图像
以及活动和适配器类的代码。
活动类:
// A Native Express ad is placed in every nth position in the RecyclerView.
public static final int ITEMS_PER_AD = 10;
// The Native Express ad height.
private static final int NATIVE_EXPRESS_AD_HEIGHT = 150;
// The Native Express ad unit ID.
private static final String AD_UNIT_ID = "ca-app-pub-3940256099942544/1072772517";
// The RecyclerView that holds and displays Native Express ads and menu items.
private RecyclerView mRecyclerView;
// List of Native Express ads and MenuItems that populate the RecyclerView.
private List<Object> mRecyclerViewItems = new ArrayList<>();
private int loadCount;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_recyclerview_with_ads);
mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);
// Use this setting to improve performance if you know that changes
// in content do not change the layout size of the RecyclerView.
mRecyclerView.setHasFixedSize(true);
// Specify a linear layout manager.
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(layoutManager);
generateData();
// Update the RecyclerView item's list with menu items and Native Express ads.
addNativeExpressAds();
setUpAndLoadNativeExpressAds();
// Specify an adapter.
final RecyclerViewAdapter adapter = new RecyclerViewAdapter(RecyclerviewWithAds.this, mRecyclerViewItems, mRecyclerView);
mRecyclerView.setAdapter(adapter);
adapter.setOnLoadMoreListener(new OnLoadMoreListener() {
@Override
public void onLoadMore() {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
//load data
//cant figure out the logic here.
Log.e("loadcount", "" + (loadCount + 1));
loadCount++;
Log.e("itemsList", "" + mRecyclerViewItems.size());
final int index = mRecyclerViewItems.size() - ((6 * loadCount) - (loadCount - 1));
Log.e("Modulus", "" + (mRecyclerViewItems.size() % ITEMS_PER_AD));
Log.e("index", "" + index);
final int end = index + 50;
for (int i = index; i <= end; i++) {
mRecyclerViewItems.add(new MenuItem("name " + i));
}
for (int i = (index + (ITEMS_PER_AD - (loadCount - 1))); i <= end; i += ITEMS_PER_AD) {
final NativeExpressAdView adView = new NativeExpressAdView(RecyclerviewWithAds.this);
Log.e("ads position", "" + i);
mRecyclerViewItems.add(i, adView);
}
mRecyclerView.post(new Runnable() {
@Override
public void run() {
final float scale = RecyclerviewWithAds.this.getResources().getDisplayMetrics().density;
int i;
// Set the ad size and ad unit ID for each Native Express ad in the items list.
for (i = (index + (ITEMS_PER_AD - (loadCount -1))); i <= end; i += ITEMS_PER_AD) {
final NativeExpressAdView adView =
(NativeExpressAdView) mRecyclerViewItems.get(i);
final CardView cardView = (CardView) findViewById(R.id.ad_card_view);
final int adWidth = cardView.getWidth() - cardView.getPaddingLeft()
- cardView.getPaddingRight();
AdSize adSize = new AdSize((int) (adWidth / scale), NATIVE_EXPRESS_AD_HEIGHT);
adView.setAdSize(adSize);
adView.setAdUnitId(AD_UNIT_ID);
}
// Load the first Native Express ad in the items list.
loadNativeExpressAd(0);
}
});
adapter.notifyDataSetChanged();
adapter.setLoaded();
}
}, 1000);
}
});
}
/**
* Adds Native Express ads to the items list.
*/
public void generateData() {
for (int i = 0; i < 50; i++) {
mRecyclerViewItems.add(new MenuItem("name " + i));
}
}
private void addNativeExpressAds() {
// Loop through the items array and place a new Native Express ad in every ith position in
// the items List.
for (int i = 0; i <= mRecyclerViewItems.size(); i += ITEMS_PER_AD) {
final NativeExpressAdView adView = new NativeExpressAdView(RecyclerviewWithAds.this);
mRecyclerViewItems.add(i, adView);
}
}
/**
* Sets up and loads the Native Express ads.
*/
private void setUpAndLoadNativeExpressAds() {
// Use a Runnable to ensure that the RecyclerView has been laid out before setting the
// ad size for the Native Express ad. This allows us to set the Native Express ad's
// width to match the full width of the RecyclerView.
mRecyclerView.post(new Runnable() {
@Override
public void run() {
final float scale = RecyclerviewWithAds.this.getResources().getDisplayMetrics().density;
// Set the ad size and ad unit ID for each Native Express ad in the items list.
for (int i = 0; i <= mRecyclerViewItems.size(); i += ITEMS_PER_AD) {
final NativeExpressAdView adView =
(NativeExpressAdView) mRecyclerViewItems.get(i);
final CardView cardView = (CardView) findViewById(R.id.ad_card_view);
final int adWidth = cardView.getWidth() - cardView.getPaddingLeft()
- cardView.getPaddingRight();
AdSize adSize = new AdSize((int) (adWidth / scale), NATIVE_EXPRESS_AD_HEIGHT);
adView.setAdSize(adSize);
adView.setAdUnitId(AD_UNIT_ID);
}
// Load the first Native Express ad in the items list.
loadNativeExpressAd(0);
}
});
}
/**
* Loads the Native Express ads in the items list.
*/
private void loadNativeExpressAd(final int index) {
if (index >= mRecyclerViewItems.size()) {
return;
}
Object item = mRecyclerViewItems.get(index);
if (!(item instanceof NativeExpressAdView)) {
throw new ClassCastException("Expected item at index " + index + " to be a Native"
+ " Express ad.");
}
final NativeExpressAdView adView = (NativeExpressAdView) item;
// Set an AdListener on the NativeExpressAdView to wait for the previous Native Express ad
// to finish loading before loading the next ad in the items list.
adView.setAdListener(new AdListener() {
@Override
public void onAdLoaded() {
super.onAdLoaded();
// The previous Native Express ad loaded successfully, call this method again to
// load the next ad in the items list.
loadNativeExpressAd(index + ITEMS_PER_AD);
}
@Override
public void onAdFailedToLoad(int errorCode) {
// The previous Native Express ad failed to load. Call this method again to load
// the next ad in the items list.
Log.e("MainActivity", "The previous Native Express ad failed to load. Attempting to"
+ " load the next Native Express ad in the items list.");
loadNativeExpressAd(index + ITEMS_PER_AD);
}
});
// Load the Native Express ad.
adView.loadAd(new AdRequest.Builder().build());
}
适配器类:
// A menu item view type.
private static final int MENU_ITEM_VIEW_TYPE = 0;
// The Native Express ad view type.
private static final int NATIVE_EXPRESS_AD_VIEW_TYPE = 1;
// An Activity's Context.
private final Context mContext;
// The list of Native Express ads and menu items.
private final List<Object> mRecyclerViewItems;
private int visibleThreshold = 5;
private int lastVisibleItem, totalItemCount;
private boolean isLoading;
private OnLoadMoreListener mOnLoadMoreListener;
/**
* For this example app, the recyclerViewItems list contains only
* {@link MenuItem} and {@link NativeExpressAdView} types.
*/
public RecyclerViewAdapter(Context context, List<Object> recyclerViewItems,RecyclerView mRecyclerView) {
this.mContext = context;
this.mRecyclerViewItems = recyclerViewItems;
final LinearLayoutManager linearLayoutManager = (LinearLayoutManager) mRecyclerView.getLayoutManager();
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
if (dy > 0) {
totalItemCount = linearLayoutManager.getItemCount();
lastVisibleItem = linearLayoutManager.findLastVisibleItemPosition();
if (!isLoading && totalItemCount <= (lastVisibleItem + visibleThreshold)) {
if (mOnLoadMoreListener != null) {
mOnLoadMoreListener.onLoadMore();
}
isLoading = true;
}
}
}
});
}
/**
* The {@link MenuItemViewHolder} class.
* Provides a reference to each view in the menu item view.
*/
public class MenuItemViewHolder extends RecyclerView.ViewHolder {
private TextView menuItemName;
private TextView menuItemDescription;
private TextView menuItemPrice;
private TextView menuItemCategory;
private ImageView menuItemImage;
MenuItemViewHolder(View view) {
super(view);
menuItemImage = (ImageView) view.findViewById(R.id.menu_item_image);
menuItemName = (TextView) view.findViewById(R.id.menu_item_name);
menuItemPrice = (TextView) view.findViewById(R.id.menu_item_price);
menuItemCategory = (TextView) view.findViewById(R.id.menu_item_category);
menuItemDescription = (TextView) view.findViewById(R.id.menu_item_description);
}
}
/**
* The {@link NativeExpressAdViewHolder} class.
*/
public class NativeExpressAdViewHolder extends RecyclerView.ViewHolder {
NativeExpressAdViewHolder(View view) {
super(view);
}
}
@Override
public int getItemCount() {
return mRecyclerViewItems.size();
}
/**
* Determines the view type for the given position.
*/
@Override
public int getItemViewType(int position) {
return (position % RecyclerviewWithAds.ITEMS_PER_AD == 0) ? NATIVE_EXPRESS_AD_VIEW_TYPE
: MENU_ITEM_VIEW_TYPE;
}
/**
* Creates a new view for a menu item view or a Native Express ad view
* based on the viewType. This method is invoked by the layout manager.
*/
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
switch (viewType) {
case MENU_ITEM_VIEW_TYPE:
View menuItemLayoutView = LayoutInflater.from(viewGroup.getContext()).inflate(
R.layout.menu_item_container, viewGroup, false);
return new MenuItemViewHolder(menuItemLayoutView);
case NATIVE_EXPRESS_AD_VIEW_TYPE:
// fall through
default:
View nativeExpressLayoutView = LayoutInflater.from(
viewGroup.getContext()).inflate(R.layout.native_express_ad_container,
viewGroup, false);
return new NativeExpressAdViewHolder(nativeExpressLayoutView);
}
}
/**
* Replaces the content in the views that make up the menu item view and the
* Native Express ad view. This method is invoked by the layout manager.
*/
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
int viewType = getItemViewType(position);
switch (viewType) {
case MENU_ITEM_VIEW_TYPE:
MenuItemViewHolder menuItemHolder = (MenuItemViewHolder) holder;
MenuItem menuItem = (MenuItem) mRecyclerViewItems.get(position);
// Get the menu item image resource ID.
// Add the menu item details to the menu item view.
menuItemHolder.menuItemName.setText(menuItem.getName());
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(mContext, "position : "+ position , Toast.LENGTH_SHORT).show();
}
});
break;
case NATIVE_EXPRESS_AD_VIEW_TYPE:
// fall through
default:
NativeExpressAdViewHolder nativeExpressHolder =
(NativeExpressAdViewHolder) holder;
NativeExpressAdView adView =
(NativeExpressAdView) mRecyclerViewItems.get(position);
ViewGroup adCardView = (ViewGroup) nativeExpressHolder.itemView;
// The NativeExpressAdViewHolder recycled by the RecyclerView may be a different
// instance than the one used previously for this position. Clear the
// NativeExpressAdViewHolder of any subviews in case it has a different
// AdView associated with it, and make sure the AdView for this position doesn't
// already have a parent of a different recycled NativeExpressAdViewHolder.
if (adCardView.getChildCount() > 0) {
adCardView.removeAllViews();
}
if (adView.getParent() != null) {
((ViewGroup) adView.getParent()).removeView(adView);
}
// Add the Native Express ad to the native express ad view.
adCardView.addView(adView);
}
}
//Extra methods
public void setOnLoadMoreListener(OnLoadMoreListener mOnLoadMoreListener) {
this.mOnLoadMoreListener = mOnLoadMoreListener;
}
public void setLoaded() {
isLoading = false;
}
如果有人帮我有效地实施这一点,我将非常感激。