2017-07-26 38 views
0

我有以下的自定義類從幾個RSS像紐約時報,BBC等:飼料來獲取新聞XmlPullParser與自定義類不顯示所有的RSS訂閱

class News{ 
    String title; 
    String link; 
    String imageURL; 
} 

這是我的代碼用它來解析XML數據:

void getRSSList() { 
    newsArray = new ArrayList<News>(); 

    // Load each RSS feed URL in a for loop 
    for (int i = 0; i < catURLsList.size(); i++) { 
     String feedURL = catURLsList.get(i); 
     try { 
      StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build(); 
      StrictMode.setThreadPolicy(policy); 

      URL aUrl = new URL(feedURL); 
      InputStream is = getInputStream(aUrl); 
      parseRssFeeds(is); 
      } catch (MalformedURLException e) { 
       e.printStackTrace(); 
      } 
    } 
} 




void parseRssFeeds(InputStream is) { 

     News n = new News(); 

     try { 
      XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); 
      factory.setNamespaceAware(false); 
      XmlPullParser xpp = factory.newPullParser(); 
      xpp.setInput(is, "UTF_8"); 

      boolean insideItem = false; 

      // Returns the type of current event: START_TAG, END_TAG, etc.. 
      int eventType = xpp.getEventType(); 
      while (eventType != XmlPullParser.END_DOCUMENT) { 
       if (eventType == XmlPullParser.START_TAG) { 

        if (xpp.getName().equalsIgnoreCase("item")) { 
         insideItem = true; 

        // Get LINK 
        } else if (xpp.getName().equalsIgnoreCase("link")) { 
         if (insideItem) { 
          n.link = xpp.nextText(); 
          Log.i("log-", "LINK: " + n.link); 
         } 

        // Get TITLE 
        } else if (xpp.getName().equalsIgnoreCase("title")) { 
         if (insideItem) { 
          n.title = xpp.nextText(); 
          Log.i("log-", "TITLE: " + n.title); 
         } 

        // Get MEDIA URL 
        } else if (xpp.getName().equalsIgnoreCase("media:content")) { 
         if (insideItem) 
          n.imageURL = xpp.getAttributeValue(null, "url"); 
          Log.i("log-", "MEDIA URL: " + n.imageURL); 
        } 

       } else if (eventType == XmlPullParser.END_TAG && xpp.getName().equalsIgnoreCase("item")) { 
        insideItem = false; 
       } 

       // Add news objects to the newsArray 
       newsArray.add(n); 

       eventType = xpp.next(); // move to next element 

      } // end WHILE loop 

     } catch(Exception e) { e.printStackTrace(); } 


     setNewsGridView(); 
    } 

setNewsGridView()調用與GridAdapter內,顯示標題和RSSfeeds的圖像的方法,問題是,我得到了我的logcat的所有標題,鏈接和媒體的URL ,但我只得到一個新聞提要重複編輯在我的GridView的每個單元格中,可能與newsArray的大小相同。

這是我GridAdapter:

// MARK: - SET NEWS GRID VIEW --------------------------------------------- 
    void setNewsGridView() { 

     class GridAdapter extends BaseAdapter { 
      private Context context; 
      public GridAdapter(Context context, List<News> objects) { 
       super(); 
       this.context = context; 
      } 


      // CONFIGURE CELL 
      @Override 
      public View getView(int position, View cell, ViewGroup parent) { 
       if (cell == null) { 
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
        cell = inflater.inflate(R.layout.cell_news, null); 
       } 

       // Get News object 
       News n = newsArray.get(position); 


       // Get Title 
       TextView titleTxt = (TextView) cell.findViewById(R.id.cnTitleTxt); 
       titleTxt.setText(n.title); 


       // Get Image 
       ImageView newsImg = (ImageView)cell.findViewById(R.id.cnImage); 
       if (n.imageURL != null) { 
        Picasso.with(context).load(n.imageURL).into(newsImg); 
       } else { newsImg.setImageResource(R.drawable.logo); } 



       return cell; 
      } 

      @Override public int getCount() { return newsArray.size(); } 
      @Override public Object getItem(int position) { return newsArray.get(position); } 
      @Override public long getItemId(int position) { return position; } 
     } 


     // Init GridView and set its adapter 
     GridView aGrid = (GridView) findViewById(R.id.hNewsGridView); 
     aGrid.setAdapter(new GridAdapter(Home.this, newsArray)); 

     // Set number of Columns accordingly to the device used 
     float scalefactor = getResources().getDisplayMetrics().density * 150; // 150 is the cell's width 
     int number = getWindowManager().getDefaultDisplay().getWidth(); 
     int columns = (int) ((float) number/(float) scalefactor); 
     aGrid.setNumColumns(columns); 


    } 

我logcat的,當我運行的應用程序:

I/log-: TITLE: Senate Votes Down Broad Obamacare Repeal 
    I/log-: LINK: https://www.nytimes.com/2017/07/25/us/politics/senate-health-care.html?partner=rss&emc=rss 
    I/log-: MEDIA URL: https://static01.nyt.com/images/2017/07/26/us/26dc-health-sub1/26dc-health-sub1-moth.jpg 
    I/log-: TITLE: John McCain to Senate: ‘We’re Getting Nothing Done’ 
    I/log-: LINK: https://www.nytimes.com/video/us/politics/100000005305566/john-mccain-health-bill-vote.html?partner=rss&emc=rss 
    I/log-: TITLE: McCain Returns to Cast Vote to Help the President Who Derided Him 
    I/log-: LINK: https://www.nytimes.com/2017/07/25/us/politics/mccain-health-care-brain-cancer 

etc... 
... 

這是輸出我得到的設備上:

enter image description here

我在做什麼錯?

非常感謝!

回答

2

Inside parseRssFeeds您在進入主循環之前實例化一個News對象,然後當您從XML中提取新聞塊時,將在此設置值並將其添加到newsArray。然後,在繼續迭代時,每次覆蓋News對象n中的值。從Java passes objects as references開始,最終會生成一個包含單個實例的多個副本的列表,其值爲n,其值設置爲XML中的最後一個條目。

要解決此問題,您需要在循環中移動聲明。 (編輯)我在這裏第一次嘗試的問題是,我認爲每個News對象將在單個循環迭代期間被讀取,但情況並非如此。你需要在每次遇到一個新的新聞項目的時候,應該給你的東西像下面實例化一個新News對象:

  // Returns the type of current event: START_TAG, END_TAG, etc.. 
      News currentNewsItem = null; 
      int eventType = xpp.getEventType(); 
      while (eventType != XmlPullParser.END_DOCUMENT) { 

       if (eventType == XmlPullParser.START_TAG) { 
        if (xpp.getName().equalsIgnoreCase("item")) { 
         insideItem = true; 

        // Get LINK 
        } else if (xpp.getName().equalsIgnoreCase("link")) { 
         if (insideItem) { 
          // If no item is currently in progress, start one 
          currentNewsItem = startNewItemIfRequired(currentNewsItem, newsArray); 

          currentNewsItem.link = xpp.nextText(); 
          Log.i("log-", "LINK: " + currentNewsItem.link); 
         } 

        // Get TITLE 
        } else if (xpp.getName().equalsIgnoreCase("title")) { 
         if (insideItem) { 
          // Start a new news item, even if one is already in progress 
          currentNewsItem = startNewItemIfRequired(null, newsArray); 

          currentNewsItem.title = xpp.nextText(); 
          Log.i("log-", "TITLE: " + currentNewsItem.title); 
         } 

        // Get MEDIA URL 
        } else if (xpp.getName().equalsIgnoreCase("media:content")) { 
         if (insideItem) 
          // If no item is currently in progress, start one 
          currentNewsItem = startNewItemIfRequired(currentNewsItem, newsArray); 

          currentNewsItem.imageURL = xpp.getAttributeValue(null, "url"); 
          Log.i("log-", "MEDIA URL: " + currentNewsItem.imageURL); 
        } 

       } else if (eventType == XmlPullParser.END_TAG && xpp.getName().equalsIgnoreCase("item")) { 
        insideItem = false; 
       } 

       eventType = xpp.next(); // move to next element 

      } // end WHILE loop 

     } catch(Exception e) { e.printStackTrace(); } 

有了這個附加功能:

private News startNewItemIfRequired(News currentNewsItem, List<News> newsArray) { 
    if (currentNewsItem==null){ 
     currentNewsItem = new News(); 
     newsArray.add(currentNewsItem); 
    } 
    return currentNewsItem; 
} 

這將創建一個新的新聞項目遇到「標題」開始標記時,並將其添加到面板,然後繼續填充,直到開始新標記。爲了安全起見,我添加了一些檢查,如果沒有「標題」,它將防止空指針。也就是說,這確實會添加一個約束條件,即「title」必須首先出現在您收到的XML中 - 這似乎是您日誌中的情況,但是如果您期望這會發生變化,您將需要一些更復雜的東西。

我想補充一點,這種流式傳輸方式是最簡單的方法,但如果您希望將來可以使用這種方法(尤其是防止XML結構和缺失字段的變化),您可能會先閱讀XML作爲文檔,然後提取出您感興趣的結構。

恐怕我還沒有你的問題沒有足夠的代碼讓我不用花費一些時間來分解你的依賴關係,所以我一直沒有能夠真正測試自己的代碼,但希望這會給你足夠的時間去解決你的問題!

+0

它不工作:(也, 「如果(N!= NULL)」 始終是真實的,所以它不是如果我使用「News n = new News()」,它會在我的GridView中給我空單元格,而如果我使用「News n = null」,它根本不會給我任何單元格。 – cubycode

+0

好的,我會稍後再試,我注意到它甚至不打印日誌,並且即使我在我的應用程序中根本不使用SQL,它仍然會打印SQL錯誤... – cubycode

+0

n如果eventType是類型爲「item」的START_TAG或非START_TAG,則它將爲空,因爲它始於空值且始終不會填充。當你說它不起作用時,你會得到什麼?可能有很多部分填充的面板,一些帶有鏈接,一些標題和一些URL? – hugh

2

問題是你一次創建了News n = new News();對象,但每次將該對象添加到ArrayList中,所以它始終顯示所有項目中的最新新聞內容。每當有新的標籤被調用item,並且在標籤item的末尾int時,您應該創建對象,您應該插入到ArrayList中。

你應該做這樣的,

void parseRssFeeds(InputStream is) { 

    // News n = new News(); your are creating object only here. 
    News n = null; 

    try { 
     XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); 
     factory.setNamespaceAware(false); 
     XmlPullParser xpp = factory.newPullParser(); 
     xpp.setInput(is, "UTF_8"); 

     boolean insideItem = false; 

     // Returns the type of current event: START_TAG, END_TAG, etc.. 
     int eventType = xpp.getEventType(); 
     while (eventType != XmlPullParser.END_DOCUMENT) { 
      if (eventType == XmlPullParser.START_TAG) { 

       if (xpp.getName().equalsIgnoreCase("item")) { 
        insideItem = true; 
        n = new News(); // you should intialize the object every time here 

        // Get LINK 
       } else if (xpp.getName().equalsIgnoreCase("link")) { 
        if (insideItem) { 
         n.link = xpp.nextText(); 
         Log.i("log-", "LINK: " + n.link); 
        } 

        // Get TITLE 
       } else if (xpp.getName().equalsIgnoreCase("title")) { 
        if (insideItem) { 
         n.title = xpp.nextText(); 
         Log.i("log-", "TITLE: " + n.title); 
        } 

        // Get MEDIA URL 
       } else if (xpp.getName().equalsIgnoreCase("media:content")) { 
        if (insideItem) 
         n.imageURL = xpp.getAttributeValue(null, "url"); 
        Log.i("log-", "MEDIA URL: " + n.imageURL); 
       } 

      } else if (eventType == XmlPullParser.END_TAG && xpp.getName().equalsIgnoreCase("item")) { 
       insideItem = false; 
       // End of the item tag, we should add it into the list 
       // Add news objects to the newsArray 
       newsArray.add(n); 
      } 


      eventType = xpp.next(); // move to next element 

     } // end WHILE loop 

    } catch (Exception e) { 
     e.printStackTrace(); 
    } 


    setNewsGridView(); 
} 
+0

完美的作品,謝謝! – cubycode

0

改造與SimpleXmlConverter

  OkHttpClient okHttpClient = new 
      OkHttpClient.Builder().readTimeout(60, 
      TimeUnit.SECONDS).connectTimeout(60, TimeUnit.SECONDS) 
      .addInterceptor(new Interceptor() { 
     @Override 
     public Response intercept(Interceptor.Chain chain) throws IOException 
     { 
      Request original = chain.request(); 

      Request.Builder requestBuilder = original.newBuilder() 
        .header("Accept", "application/xml"); 

      Request request = requestBuilder.build(); 
      return chain.proceed(request); 
     } 
    }).build(); 

    retrofitClient = new Retrofit.Builder() 
      .baseUrl(RestAPI.baseURL) 
      .client(okHttpClient) 
      .addConverterFactory(SimpleXmlConverterFactory.create()) 
      .build(); 

    restAPI = retrofitClient.create(RestAPI.class);