2017-05-29 84 views
0

我在Android應用程序中使用RecyclerView其獲取數據和改造解析JSON網址工作。我對這個GithubNativeExpressAdView java.lang.IndexOutOfBoundsException:無效指數0,大小爲0

我在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

要調用在不同的線程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 
      } 
+0

您好,感謝您的回答,但之後我嘗試你的建議應用程序是空白的,沒有錯誤。 並顯示E/RecyclerView:無適配器連接;在logcat上跳過佈局。所以我錯了? –

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) { 
    .. 
} 
相關問題