Java 带有自定义类的XmlPullParser不';不显示所有RSS源

Java 带有自定义类的XmlPullParser不';不显示所有RSS源,java,android,xml,class,xml-parsing,Java,Android,Xml,Class,Xml Parsing,我有以下自定义类从一些RSS源(如纽约时报、BBC等)获取新闻: 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

我有以下自定义类从一些RSS源(如纽约时报、BBC等)获取新闻:

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();
    }
这是我在设备上得到的输出:

 // 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);


    }
    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...
...

我做错了什么


非常感谢

parsersfeeds
中,在进入主循环之前实例化一个
News
对象,然后从XML中提取一个新闻块时,对其设置值并将其添加到
newsaray
。然后,在继续迭代时,每次都覆盖
新闻
对象
n
中的值。因为,最终会得到一个列表,其中包含单个实例的多个副本,
n
,其值设置为XML中的最后一个条目

要解决这个问题,需要在循环中移动声明。(编辑)我第一次尝试的问题是,我假设每个
新闻
对象都会在单个循环迭代中读取,但事实并非如此。每次遇到新的新闻项目时,您都需要实例化一个新的
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;
}
private News startNewItemIfRequired(新闻currentNewsItem,列表新闻数组){
如果(currentNewsItem==null){
currentNewsItem=新新闻();
newsArray.add(currentNewsItem);
}
返回当前新闻项;
}
这将在遇到“title”开始标记时创建一个新的新闻项,并将其添加到面板中,然后继续填充它,直到新的开始。为了安全起见,我添加了一些检查,如果没有“标题”,这些检查将防止空指针。这就是说,这确实增加了一个约束,即“title”必须首先出现在您收到的XML中——从您的日志中可以看出这是一种情况,但是如果您希望这有所不同,您将需要更复杂的内容

我要补充的是,这种流式方法是开始这项工作的最简单的方法,但是如果您希望在将来使其更加健壮(特别是防止XML结构的更改和缺少字段),那么最好先将XML作为文档读取,然后取出感兴趣的结构


恐怕我还不知道你的问题没有足够的代码让我在不花时间分析你的依赖关系的情况下站出来,所以我还不能亲自测试代码,但希望这能给你足够的代码来解决你的问题

parsersfeeds
中,在进入主循环之前实例化一个
News
对象,然后从XML中提取一个新闻块时,对其设置值并将其添加到
newsaray
。然后,在继续迭代时,每次都覆盖
新闻
对象
n
中的值。因为,最终会得到一个列表,其中包含单个实例的多个副本,
n
,其值设置为XML中的最后一个条目

要解决这个问题,需要在循环中移动声明。(编辑)我第一次尝试的问题是,我假设每个
新闻
对象都会在单个循环迭代中读取,但事实并非如此。每次遇到新的新闻项目时,您都需要实例化一个新的
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;
}
private News startNewItemIfRequired(新闻currentNewsItem,列表新闻数组){
如果(currentNewsItem==null){
currentNewsItem=新新闻();
newsArray.add(currentNewsItem);
}
返回当前新闻项;
}
这将在遇到“title”开始标记时创建一个新的新闻项,并将其添加到面板中,然后继续填充它,直到新的开始。为了安全起见,我添加了一些检查,如果没有“标题”,这些检查将防止空指针。这就是说,这确实增加了一个约束,即“title”必须首先出现在您收到的XML中——从您的日志中可以看出这是一种情况,但是如果您希望这有所不同,您将需要更复杂的内容

我要补充的是,这种流式方法是开始这项工作的最简单的方法,但是如果您希望在将来使其更加健壮(特别是防止XML结构的更改和缺少字段),那么最好先将XML作为文档读取,然后取出感兴趣的结构


恐怕我还不知道你的问题没有足够的代码让我在不花时间分析你的依赖关系的情况下站出来,所以我还不能亲自测试代码,但希望这能给你足够的代码来解决你的问题

问题是您创建了
News n=new News()对象一次,但每次都将该对象添加到ArrayList中,因此它总是显示在所有项目的最后一条新闻内容中。每次获得名为
item
的新标记时,都应该创建对象,并在标记
item
的末尾插入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();
}

问题是您创建了
News n=newnews()对象一次,但每次都将该对象添加到ArrayList中,因此它总是显示在所有项目的最后一条新闻内容中。每次获得名为
item
的新标记时,都应该创建对象,并在标记
item
的末尾插入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();
}

使用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);

使用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);

它不起作用:(而且,“if(n!=null)”始终为真,因此不需要它。如果我使用“News n=News()”,它会在GridView中给我空单元格,而如果我使用“News n=null”,它根本不会给我任何单元格。好的,我稍后再试,我注意到它甚至不会打印