【问题标题】:How to properly utilize a doinBackground() method in order to retrieve RSS items如何正确使用 doinBackground() 方法来检索 RSS 项目
【发布时间】:2015-10-25 23:48:33
【问题描述】:

现在我正在创建一个 RSS 阅读器,主要只是试图让项目的标题和描述显示在 ListView 上。我之前在没有 RSS 数据的情况下对其进行了测试,并确认该应用程序正确列出了我创建的项目。但是,在尝试对来自 RSS 的数据进行相同操作后,我遇到了检索实际 RSS 数据以及如何使用 doinBackground 方法的问题。

在阅读了 Google 关于 doinBackground 的文档后,我了解到它的类 (Async) 允许执行后台操作并将其结果显示在 UI 线程中。但是,我通常在提取 RSS 数据以及 doinBackground() 如何适合我的代码时遇到问题。有关如何正确检索数据和有效使用 doinbackground() 的任何想法?

我遇到问题的代码类别是 Headlines 和 RSSManager。代码如下:

标题片段

import android.os.Bundle;
import android.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import java.net.MalformedURLException;
import java.net.URL;

public class Headlines extends Fragment {
EditText editText;
Button gobutton;
ListView listView;

public Headlines() {
}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    View v = inflater.inflate(R.layout.fragment_headlines, container, false);
    editText = (EditText)v.findViewById(R.id.urlText);
    gobutton = (Button)v.findViewById(R.id.goButton);
    listView = (ListView)v.findViewById(R.id.listView);
    RSSFeedManager rfm = new RSSFeedManager();
    News [] news = new News[100]; // i shouldnt have to set the size of the array here since I did it in getFeed() in RSSFeedManager.java
    try {
        news = rfm.getFeed(String.valueOf(new URL("http://rss.cnn.com/rss/cnn_world.rss")));
    } catch (MalformedURLException e) {
        e.printStackTrace();
    }
    RssAdapter adapter = new RssAdapter(this.getActivity(),news);
    listView.setAdapter(adapter);
    /*gobutton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {

        }
    });*/
    return v;
}

}

RSSFeedManager

import android.os.AsyncTask;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

public class RSSFeedManager extends AsyncTask<String,Void,String> {
public URL rssURL;
News[] articles;

public News[] getFeed(String url) {
    try {
        String strURL = url;
        rssURL = new URL(url);
        DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
        Document doc = builder.parse(rssURL.openStream());

        //using Nodelist to get items within the rss, then creating
        //a News array the same size of the amount of items within the rss
        //then setting up a temporary "News" item which will be the temp object
        //used for storing multiple objects that contain title and description
        //of each item
        NodeList items = doc.getElementsByTagName("item");
        News[] articles = new News[items.getLength()];
        News news = null;

        //traverse through items and place the contents of each item within an RssItem object
        //then add to it to the News Array
        for (int i = 0; i < items.getLength(); i++) {
            Element item = (Element) items.item(i);
            news.setTitle(getValue(item, "title"));
            news.setDescription(getValue(item, "description"));
            articles[i] = news;
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
    return articles;
}

public String getValue(Element parent, String nodeName) {
    return parent.getElementsByTagName(nodeName).item(0).getFirstChild().getNodeValue();
}

@Override
protected String doInBackground(String... url) {
    String rssURL = url[0];
    URL urlTemp;
    try {
        //pulling the url from the params and converting it to type URL and then establishing a connection
        urlTemp = new URL(rssURL);
        HttpURLConnection urlConnection = (HttpURLConnection) urlTemp.openConnection();
        urlConnection.connect();
        /*
        *im thinking i need to call the getFeed() method
        *after establishing the httpurlconnection however
        *I also thought I may just need to move the getFeed()
        *code within doinBackground. Lost at this point due to the
        * return types of getFeed and doinBackground
        */
    } catch (MalformedURLException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return null;
}

}

【问题讨论】:

  • 你没有正确使用AsyncTaskdoInBackground(...)方法没有被执行,因为你从来没有在你创建的RSSFeedManager实例上调用execute(...)方法。
  • @Titus,谢谢,我忘了把它包括在内。但是此时我的 doInBackground 方法没有完成任何事情,因为我不确定除了 HTTPURLConnection 之外要包含什么。

标签: java android android-asynctask rss


【解决方案1】:

在挑选出每一行代码之后,我发现了我的 RSSFeedManager 类、doInBackground() 方法和 Headlines 类的一些问题。

从 RSSFeedManager 开始,这里有一些问题。我将实例化的News [] articles 实例化为类变量,然后在getFeeds() 方法中重新定义它。显然这会导致一些问题,并将articles 返回为空。我还删除了strURLrssURL,因为我做错了。不需要将 URL 传递给 getFeeds(),而是需要从 URL 传递 XML。我还稍微修改了代码以使用 News 类的构造函数。

这是 RSSFeedManager 的固定代码:

public class RSSFeedManager{

News[] articles;

public News[] getFeed(String html) {
    try {
        DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
        Document doc = builder.parse(new ByteArrayInputStream(html.getBytes()));

        NodeList items = doc.getElementsByTagName("item");
        articles = new News[items.getLength()];

        for (int i = 0; i < items.getLength(); i++) {
            Element item = (Element) items.item(i);
            News news = new News(getValue(item, "title"),getValue(item, "description").substring(0,100),"");
            articles[i] = news;
        }
    } catch (Exception e) {
        //e.printStackTrace();
        Log.d("EXCEPTION PARSING",e.toString());
    }
    return articles;
}

public String getValue(Element parent, String nodeName) {
    return parent.getElementsByTagName(nodeName).item(0).getFirstChild().getNodeValue();
}
}

正如我之前提到的,我意识到 RSSFeedManager 应该从 URL 接收 XML,而不是从 URL 本身接收 XML,并且 doInBackground() 应该发生在一个新类中。本质上,带有 Downloader 类的 doInBackground() 方法(扩展 AsyncTask 正在接收输入的 url,然后从该 RSS url 收集 XML。

这里是下载器类

public class Downloader extends AsyncTask<String, Void, String> {

@Override
protected String doInBackground(String... urls) {
    String result ="";
    try{
        URL url = new URL(urls[0]);
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        InputStream in = connection.getInputStream();
        BufferedReader reader = new BufferedReader(new InputStreamReader(in));
        String line = "";
        while((line=reader.readLine())!= null){
            result= result + line;
        }
        connection.disconnect();

    } catch (Exception e) {
        Log.e("Error fetching", e.toString());
    }

    return result;
}
}

因此,在完成这两个课程之后,我知道我需要在 Headlines 课程中解决一些问题。我最初蛮力地强制代码进行测试,以确保来自 RSS 提要的文章正确显示,并且他们确实如此,然后着手正确实现它。为了提醒人们,该程序的目的是显示来自用户指定的 RSS 提要的文章,方法是在 editText 中输入一个 url,这是一个 EditText 对象。然后用户按下goButton,类型为Button,然后列出来自editText的所有文章。我通过为goButton 创建一个onClickListener 并创建DownloaderRssFeedManager 类的对象来实现这一点,以便调用它们的方法来建立连接、检索URL 的XML,然后对其进行解析。

这是 Headline 类代码的 sn-p,我可以将所有内容联系在一起。

 public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    View v = inflater.inflate(R.layout.fragment_headlines, container, false);
    editText = (EditText)v.findViewById(R.id.urlText);
    gobutton = (Button)v.findViewById(R.id.goButton);
    listView = (ListView)v.findViewById(R.id.listView);
    parent = this.getActivity();
    gobutton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            RSSFeedManager rfm = new RSSFeedManager();
            String html = "";
            try {
                Downloader d = new Downloader();
                d.execute(editText.getText().toString());
                html = d.get();
                Log.d("HTML CAME BACK", html);
                news = rfm.getFeed(html);
                RssAdapter adapter = new RssAdapter(parent, news);
                listView.setAdapter(adapter);
            } catch (InterruptedException e) {
                Log.e("ERROR!!!!!", e.toString());
            } catch (ExecutionException e) {
                Log.e("ERROR!!!!!!!", e.toString());
                Toast.makeText(parent, e.toString(), Toast.LENGTH_LONG).show();
            } catch (Exception e) {
                Log.e("WEIRD!", e.toString());
                Toast.makeText(parent, e.toString(), Toast.LENGTH_LONG).show();
            }


        }
    });

所有这些更改都有助于解决问题,让我能够进一步完成这个程序,并了解更多关于 android 开发的信息。

【讨论】:

  • 您仍然没有正确使用AsyncTask,这一行d.get(); 阻塞,直到doInBackground() 方法返回并且由于您在UI 线程上执行d.get();,所以GUI 将冻结,直到页面被下载。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-07-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多