RXJava Android - 尝试提取RSS提要时的网络异常

时间:2015-10-07 15:26:37

标签: java android rx-java rx-android

我目前正在尝试将RSS Feed作为XML文件下载,我尝试使用RXJava而不是AsyncTask来解析和下载该文件。

我在主线程错误上找到了一个网络,但是我正试图拉下来。

以下是主要活动中的observable相关代码

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        recyclerView = (RecyclerView) findViewById(R.id.rv_test_items);
        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);

        final ArrayList<TestItem> testItems = new ArrayList<>();
        //testItems.add(new TestItem("Title here", "Content here"));

        RssReader reader = new RssReader("http://www.feedforall.com/sample.xml");

        // Subscribe on a new background thread, while returning the result on the UI thread.
        // Using the RSS Classes we will pull the rss items from the rss feed and then create our
        // own TestItem from them.
        try {
            Observable
                    .from(reader.getItems())
                    .subscribeOn(Schedulers.newThread())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(new Action1<RssItem>() {
                        @Override
                        public void call(RssItem item) {
                            TestItem newItem = new TestItem(item.getTitle(), item.getDescription());
                            testItems.add(newItem);
                        }
                    });
        } catch (Exception e) {
            e.printStackTrace();
            Log.e("App", "Failed to download RSS Items");
        }

        TestItemAdapter testItemAdapter = new TestItemAdapter(testItems);

        recyclerView.setLayoutManager(linearLayoutManager);
        recyclerView.setAdapter(testItemAdapter);

这是我的RSSReader类

public class RssReader {
    private String rssUrl;

    public RssReader(String url) {
        rssUrl = url;
    }

    public List<RssItem> getItems() throws Exception {
        SAXParserFactory factory = SAXParserFactory.newInstance();
        SAXParser saxParser = factory.newSAXParser();
        //Creates a new RssHandler which will do all the parsing.
        RssHandler handler = new RssHandler();
        //Pass SaxParser the RssHandler that was created.
        saxParser.parse(rssUrl, handler);
        return handler.getRssItemList();
    }
}

我的RSSHandler类

public class RssHandler extends DefaultHandler {
    private List<RssItem> rssItemList;
    private RssItem currentItem;
    private boolean parsingTitle;
    private boolean parsingLink;
    private boolean parsingDescription;

    public RssHandler() {
        //Initializes a new ArrayList that will hold all the generated RSS items.
        rssItemList = new ArrayList<RssItem>();
    }

    public List<RssItem> getRssItemList() {
        return rssItemList;
    }


    //Called when an opening tag is reached, such as <item> or <title>
    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        if (qName.equals("item"))
            currentItem = new RssItem();
        else if (qName.equals("title"))
            parsingTitle = true;
        else if (qName.equals("link"))
            parsingLink = true;
        else if (qName.equals("description"))
            parsingDescription = true;
        else if (qName.equals("media:thumbnail") || qName.equals("media:content") || qName.equals("image")) {
            if (attributes.getValue("url") != null)
                currentItem.setImageUrl(attributes.getValue("url"));
        }
    }

    //Called when a closing tag is reached, such as </item> or </title>
    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
        if (qName.equals("item")) {
            //End of an item so add the currentItem to the list of items.
            rssItemList.add(currentItem);
            currentItem = null;
        } else if (qName.equals("title"))
            parsingTitle = false;
        else if (qName.equals("link"))
            parsingLink = false;
        else if (qName.equals("description"))
            parsingDescription = false;
    }

    //Goes through character by character when parsing whats inside of a tag.
    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        if (currentItem != null) {
            //If parsingTitle is true, then that means we are inside a <title> tag so the text is the title of an item.
            if (parsingTitle)
                currentItem.setTitle(new String(ch, start, length));
                //If parsingLink is true, then that means we are inside a <link> tag so the text is the link of an item.
            else if (parsingLink)
                currentItem.setLink(new String(ch, start, length));
                //If parsingDescription is true, then that means we are inside a <description> tag so the text is the description of an item.
            else if (parsingDescription)
                currentItem.setDescription(new String(ch, start, length));
        }
    }
}

堆栈跟踪

10-07 11:39:15.040 1959-1959/? I/art: Late-enabling -Xcheck:jni
10-07 11:39:15.208 1959-1959/? W/System.err: java.io.IOException: Couldn't open http://www.feedforall.com/sample.xml
10-07 11:39:15.208 1959-1959/? W/System.err:     at org.apache.harmony.xml.ExpatParser.openUrl(ExpatParser.java:755)
10-07 11:39:15.208 1959-1959/? W/System.err:     at org.apache.harmony.xml.ExpatReader.parse(ExpatReader.java:292)
10-07 11:39:15.208 1959-1959/? W/System.err:     at javax.xml.parsers.SAXParser.parse(SAXParser.java:390)
10-07 11:39:15.208 1959-1959/? W/System.err:     at javax.xml.parsers.SAXParser.parse(SAXParser.java:266)
10-07 11:39:15.208 1959-1959/? W/System.err:     at com.polymorphicinc.retrofitsample.rss.RssReader.getItems(RssReader.java:36)
10-07 11:39:15.208 1959-1959/? W/System.err:     at com.polymorphicinc.retrofitsample.ui.MainActivity.onCreate(MainActivity.java:47)
10-07 11:39:15.208 1959-1959/? W/System.err:     at android.app.Activity.performCreate(Activity.java:5990)
10-07 11:39:15.208 1959-1959/? W/System.err:     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1106)
10-07 11:39:15.208 1959-1959/? W/System.err:     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2278)
10-07 11:39:15.208 1959-1959/? W/System.err:     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2387)
10-07 11:39:15.208 1959-1959/? W/System.err:     at android.app.ActivityThread.access$800(ActivityThread.java:151)
10-07 11:39:15.208 1959-1959/? W/System.err:     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1303)
10-07 11:39:15.208 1959-1959/? W/System.err:     at android.os.Handler.dispatchMessage(Handler.java:102)
10-07 11:39:15.208 1959-1959/? W/System.err:     at android.os.Looper.loop(Looper.java:135)
10-07 11:39:15.208 1959-1959/? W/System.err:     at android.app.ActivityThread.main(ActivityThread.java:5254)
10-07 11:39:15.208 1959-1959/? W/System.err:     at java.lang.reflect.Method.invoke(Native Method)
10-07 11:39:15.209 1959-1959/? W/System.err:     at java.lang.reflect.Method.invoke(Method.java:372)
10-07 11:39:15.209 1959-1959/? W/System.err:     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
10-07 11:39:15.209 1959-1959/? W/System.err:     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
10-07 11:39:15.209 1959-1959/? W/System.err: Caused by: android.os.NetworkOnMainThreadException
10-07 11:39:15.209 1959-1959/? W/System.err:     at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1147)
10-07 11:39:15.209 1959-1959/? W/System.err:     at java.net.InetAddress.lookupHostByName(InetAddress.java:418)
10-07 11:39:15.209 1959-1959/? W/System.err:     at java.net.InetAddress.getAllByNameImpl(InetAddress.java:252)
10-07 11:39:15.209 1959-1959/? W/System.err:     at java.net.InetAddress.getAllByName(InetAddress.java:215)
10-07 11:39:15.209 1959-1959/? W/System.err:     at com.android.okhttp.HostResolver$1.getAllByName(HostResolver.java:29)
10-07 11:39:15.209 1959-1959/? W/System.err:     at com.android.okhttp.internal.http.RouteSelector.resetNextInetSocketAddress(RouteSelector.java:232)
10-07 11:39:15.209 1959-1959/? W/System.err:     at com.android.okhttp.internal.http.RouteSelector.next(RouteSelector.java:124)
10-07 11:39:15.209 1959-1959/? W/System.err:     at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:272)
10-07 11:39:15.209 1959-1959/? W/System.err:     at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:211)
10-07 11:39:15.209 1959-1959/? W/System.err:     at com.android.okhttp.internal.http.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:382)
10-07 11:39:15.209 1959-1959/? W/System.err:     at com.android.okhttp.internal.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:332)
10-07 11:39:15.209 1959-1959/? W/System.err:     at com.android.okhttp.internal.http.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:199)
10-07 11:39:15.209 1959-1959/? W/System.err:     at org.apache.harmony.xml.ExpatParser.openUrl(ExpatParser.java:753)
10-07 11:39:15.209 1959-1959/? W/System.err:    ... 18 more
10-07 11:39:15.209 1959-1959/? E/App: Failed to download RSS Items
10-07 11:39:15.215 1959-1978/? D/OpenGLRenderer: Use EGL_SWAP_BEHAVIOR_PRESERVED: true
10-07 11:39:15.216 1959-1959/? D/: HostConnection::get() New Host Connection established 0xb42d9a00, tid 1959
10-07 11:39:15.219 1959-1959/? D/Atlas: Validating map...
10-07 11:39:15.281 1959-1978/? D/libEGL: loaded /system/lib/egl/libEGL_emulation.so
10-07 11:39:15.282 1959-1978/? D/libEGL: loaded /system/lib/egl/libGLESv1_CM_emulation.so
10-07 11:39:15.286 1959-1978/? D/libEGL: loaded /system/lib/egl/libGLESv2_emulation.so
10-07 11:39:15.295 1959-1978/? D/: HostConnection::get() New Host Connection established 0xb42d9b90, tid 1978
10-07 11:39:15.311 1959-1978/? I/OpenGLRenderer: Initialized EGL, version 1.4
10-07 11:39:15.360 1959-1978/? D/OpenGLRenderer: Enabling debug mode 0
10-07 11:39:15.381 1959-1978/? W/EGL_emulation: eglSurfaceAttrib not implemented
10-07 11:39:15.381 1959-1978/? W/OpenGLRenderer: Failed to set EGL_SWAP_BEHAVIOR on surface 0xb424bb40, error=EGL_SUCCESS

2 个答案:

答案 0 :(得分:2)

看看这个以了解如何做到这一点:

public class RssReader {
    private String rssUrl;

    public RssReader(String url) {
        rssUrl = url;
    }

    public Observable<List<RssItem>> getItems() {
        return Observable.create(new Observable.OnSubscribe<List<RssItem>>() {
            @Override
            public void call(Subscriber<? super List<RssItem>> subscriber) {
                try {

                    SAXParserFactory factory = SAXParserFactory.newInstance();
                    SAXParser saxParser = factory.newSAXParser();
                    //Creates a new RssHandler which will do all the parsing.
                    RssHandler handler = new RssHandler();
                    //Pass SaxParser the RssHandler that was created.
                    saxParser.parse(rssUrl, handler);
                    subscriber.onNext(handler.getRssItemList());
                    subscriber.onCompleted();
                } catch (Exception e) {
                    subscriber.onError(e);
                }
            }
        });
    }
}


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    recyclerView = (RecyclerView) findViewById(R.id.rv_test_items);
    LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
    recyclerView.setLayoutManager(linearLayoutManager);
    RssReader reader = new RssReader("http://www.feedforall.com/sample.xml");
    reader.getItems()
            .subscribeOn(Schedulers.newThread())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(new Action1<List<RssItem>>() {
                @Override
                public void call(List<RssItem> items) {
                    final ArrayList<TestItem> testItems = new ArrayList<>(items.size());
                    for (int size = items.size(), i = 0; i < size; i++) {
                        RssItem item = items.get(i);
                        testItems.add(new TestItem(item.getTitle(), item.getDescription()));
                    }
                    recyclerView.setAdapter(new TestItemAdapter(testItems));
                }
            }, new Action1<Throwable>() {
                @Override
                public void call(Throwable e) {
                    e.printStackTrace();
                    Log.e("App", "Failed to download RSS Items");
                }
            });
}

答案 1 :(得分:0)

试试这个

Observable.defer(() -> Observable.from(reader.getItems())
          .subscribeOn(Schedulers.newThread())
          .observeOn(AndroidSchedulers.mainThread())
          .subscribe(new Action1<RssItem>() {
                    @Override
                    public void call(RssItem item) {
                        TestItem newItem = new TestItem(item.getTitle(), item.getDescription());
                        testItems.add(newItem);
                    }
                });