我正在研究Android应用程序,它使用RecyclerView和Retrofit获取数据以解析JSON Url。我有关于此Github
的以下教程我在Android Studio上的项目没有错误,我可以运行应用程序。但是当我打开MainActivity时它会崩溃。
我得到的错误
java.lang.IndexOutOfBoundsException: Invalid index 0, size is 0
以下行是在setUpAndLoadNativeExpressAds
上final NativeExpressAdView adView = (NativeExpressAdView) mRecyclerViewItems.get(i);
这是MainActivity
public class MainActivity extends AppCompatActivity{
public static final int ITEMS_PER_AD = 3;
private static final int NATIVE_EXPRESS_AD_HEIGHT = 150;
private static final String AD_UNIT_ID = ADMOB_NATIVE_MENU_ID;
private StartAppAd startAppAd = new StartAppAd(this);
private RecyclerView mRecyclerView;
private List<Object> mRecyclerViewItems = new ArrayList<>();
private KontenAdapter kontenAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
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);
// mRecyclerViewItems = new ArrayList<>();
// Update the RecyclerView item's list with menu items and Native Express ads.
// addMenuItemsFromJson();
loadJSON();
// initData();
setUpAndLoadNativeExpressAds();
}
/**
* Adds Native Express ads to the items list.
*/
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(MainActivity.this);
mRecyclerViewItems.add(i, adView);
}
}
/**
* Sets up and loads the Native Express ads.
*/
private void setUpAndLoadNativeExpressAds() {
mRecyclerView.post(new Runnable() {
@Override
public void run() {
final float scale = MainActivity.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());
}
private void loadJSON() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.myjson.com/") //https://api.myjson.com/bins/v4dzd
.addConverterFactory(GsonConverterFactory.create())
.build();
RequestInterface request = retrofit.create(RequestInterface.class);
Call<JSONResponse> call = request.getJSON();
call.enqueue(new Callback<JSONResponse>() {
@Override
public void onResponse(Call<JSONResponse> call, Response<JSONResponse> response) {
JSONResponse jsonResponse = response.body();
mRecyclerViewItems = new ArrayList<Object>(Arrays.asList(jsonResponse.getKonten()));
addNativeExpressAds();
RecyclerView.Adapter adapter = new KontenAdapter(mRecyclerViewItems, getApplicationContext());
mRecyclerView.setAdapter(adapter);
}
@Override
public void onFailure(Call<JSONResponse> call, Throwable t) {
Log.d("Error", t.getMessage());
}
});
}
/**
* Adds {@link KontenItem}'s from a JSON file.
*/
private void addMenuItemsFromJson() {
try {
String jsonDataString = readJsonDataFromFile();
JSONArray menuItemsJsonArray = new JSONArray(jsonDataString);
for (int i = 0; i < menuItemsJsonArray.length(); ++i) {
JSONObject menuItemObject = menuItemsJsonArray.getJSONObject(i);
String menuItemName = menuItemObject.getString("name");
String menuItemDescription = menuItemObject.getString("description");
String menuItemPrice = menuItemObject.getString("price");
String menuItemCategory = menuItemObject.getString("category");
String menuItemImageName = menuItemObject.getString("photo");
String menuItemUrl = menuItemObject.getString("url");
KontenItem kontenItem = new KontenItem(menuItemName, menuItemDescription, menuItemPrice,
menuItemCategory, menuItemImageName, menuItemUrl);
mRecyclerViewItems.add(kontenItem);
}
} catch (IOException | JSONException exception) {
Log.e(MainActivity.class.getName(), "Unable to parse JSON file.", exception);
}
}
/**
* Reads the JSON file and converts the JSON data to a {@link String}.
*
* @return A {@link String} representation of the JSON data.
* @throws IOException if unable to read the JSON file.
*/
private String readJsonDataFromFile() throws IOException {
InputStream inputStream = null;
StringBuilder builder = new StringBuilder();
try {
String jsonDataString = null;
inputStream = getResources().openRawResource(R.raw.menu_items_json);
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(inputStream, "UTF-8"));
while ((jsonDataString = bufferedReader.readLine()) != null) {
builder.append(jsonDataString);
}
} finally {
if (inputStream != null) {
inputStream.close();
}
}
return new String(builder);
}
}
这是MyAdapter
public class KontenAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
// 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;
public KontenAdapter(List<Object> recyclerViewItems, Context context) {
this.mContext = context;
this.mRecyclerViewItems = recyclerViewItems;
}
/**
* The {@link MenuItemViewHolder} class.
* Provides a reference to each view in the menu item view.
*/
public class MenuItemViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
private TextView menuItemName;
private TextView menuItemDescription;
private TextView menuItemPrice;
private TextView menuItemCategory;
private ImageView menuItemImage;
private TextView menuItemUrl;
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);
menuItemUrl = (TextView) view.findViewById(R.id.menu_item_url);
view.setOnClickListener(this);
}
@Override
public void onClick(View v) {
Intent detailIntent = new Intent(v.getContext(), PostActivity.class);
detailIntent.putExtra("name",menuItemName.getText().toString() );
detailIntent.putExtra("url", menuItemUrl.getText().toString());
mContext.startActivity(detailIntent);
}
}
/**
* 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 % MainActivity.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, int position) {
int viewType = getItemViewType(position);
switch (viewType) {
case MENU_ITEM_VIEW_TYPE:
MenuItemViewHolder menuItemHolder = (MenuItemViewHolder) holder;
KontenItem kontenItem = (KontenItem) mRecyclerViewItems.get(position);
// Get the menu item image resource ID.
String imageName = kontenItem.getImageName();
int imageResID = mContext.getResources().getIdentifier(imageName, "drawable",
mContext.getPackageName());
// Add the menu item details to the menu item view.
menuItemHolder.menuItemImage.setImageResource(imageResID);
menuItemHolder.menuItemName.setText(kontenItem.getName());
menuItemHolder.menuItemPrice.setText(kontenItem.getPrice());
menuItemHolder.menuItemCategory.setText(kontenItem.getCategory());
menuItemHolder.menuItemDescription.setText(kontenItem.getDescription());
menuItemHolder.menuItemUrl.setText(kontenItem.getInstructionUrl());
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);
}
}
}
KontenItem.java
class KontenItem {
private final String name;
private final String description;
private final String price;
private final String category;
private final String imageName;
private final String instructionUrl;
public KontenItem(String name, String description, String price, String category,
String imageName, String instructionUrl) {
this.name = name;
this.description = description;
this.price = price;
this.category = category;
this.imageName = imageName;
this.instructionUrl = instructionUrl;
}
public String getName() {
return name;
}
public String getDescription() {
return description;
}
public String getPrice() {
return price;
}
public String getCategory() {
return category;
}
public String getImageName() {
return imageName;
}
public String getInstructionUrl() {
return instructionUrl;
}
}
提前致谢!
答案 0 :(得分:0)
您正在呼叫addNativeExpressAds()
和
for (int i = 0; i <= mRecyclerViewItems.size(); i += ITEMS_PER_AD) {
final NativeExpressAdView adView = (NativeExpressAdView) mRecyclerViewItems.get(i);
在不同的主题中。因此,mRecyclerViewItems.get(i)
在初始化之前使用。
我建议使用
@Override
public void onResponse(Call<JSONResponse> call, Response<JSONResponse> response) {
JSONResponse jsonResponse = response.body();
mRecyclerViewItems = new ArrayList<Object>(Arrays.asList(jsonResponse.getKonten()));
addNativeExpressAds();
RecyclerView.Adapter adapter = new KontenAdapter(mRecyclerViewItems, getApplicationContext());
mRecyclerView.setAdapter(adapter);
setUpAndLoadNativeExpressAds(); // << ADD THIS METHOD HERE AND REMOVE THE OTHER CALLING
}
答案 1 :(得分:0)
您的问题是mRecyclerViewItems
是基于零的数组/集合。然而在setUpAndLoadNativeExpressAds()
中,即使你没有元素,你也会迭代,然后要求元素0。
for (int i = 0; i <= mRecyclerViewItems.size(); i += ITEMS_PER_AD) {
final NativeExpressAdView adView = (NativeExpressAdView) mRecyclerViewItems.get(i);
..
}
你应该
for (int i = 0; i < mRecyclerViewItems.size(); i += ITEMS_PER_AD) {
..
}