Please Enable JavaScript!
Gon[ Enable JavaScript ]

안드로이드(Android) RSS 구현2 - XML 파싱클래스를 이용 RSS Reader 구현하기

 

개발환경 : Eclipse Mars, Android 4.2.2

 

이전에 작성했던 XML 파싱 클래스 예제에서 조금 더 확장하여 RSS XML 을 읽어와서 화면에 표현해 보도록 합니다. 이번 사용한 API Android SAX API 입니다. SAX XML 을 분석할수 있는 심플한 API 이며 원래 java 용으로 만들었습니다.

 

샘플 앱을 실행한 화면입니다. 왼쪽은 브라우저에서 RSS 주소로 들어가 데이터를 긁어 온 것이고 오른쪽은 앱을 실행해서 현재 12개의 데이터를 가져왔는데 제목만 표시 하였습니다.

 

안드로이드(Android) RSS 구현2 - XML 파싱클래스를 이용해서 RSS Reader 구현하기

먼저 환경설정을 해야 합니다. 인터넷을 접속해서 데이터를 가져와야 하기 때문에 AndroidManifest.xml INTERNET 퍼미션을 셋팅합니다.

 

<uses-permission android:name="android.permission.INTERNET" />

 

다음은 메인 activity xml 값을 가져오기 위해 AsyncTask 상속받아 ProcessXmlTask 클래스를 만듭니다. 인수로 RSS 피드값을 읽어올 주소를 넘깁니다.

 

ProcessXmlTask xmlTask = new ProcessXmlTask();
xmlTask.execute("http://mainia.tistory.com/rss");

 

만든 클래스에 doInBackground() 함수를 구현합니다. 이곳에 XML 값을 가져와서 파싱하는 코드가 들어갑니다.

 

protected Void doInBackground(String... urls) {
	try {
		
		URL rssUrl = new URL(urls[0]);
		SAXParserFactory mySAXParserFactory = SAXParserFactory.newInstance();
		SAXParser mySAXParser = mySAXParserFactory.newSAXParser();
		XMLReader myXMLReader = mySAXParser.getXMLReader();
		RSSHandler myRSSHandler = new RSSHandler();
		myXMLReader.setContentHandler(myRSSHandler);
		InputSource myInputSource = new InputSource(rssUrl.openStream());
		myXMLReader.parse(myInputSource);

	} catch (MalformedURLException e) {
		e.printStackTrace();
		mResult.setText("Cannot connect RSS!");
	} catch (ParserConfigurationException e) {
		e.printStackTrace();
		mResult.setText("Cannot connect RSS!");
	} catch (SAXException e) {
		e.printStackTrace();
		mResult.setText("Cannot connect RSS!");
	} catch (IOException e) {
		e.printStackTrace();
		mResult.setText("Cannot connect RSS!");
	}
	return null;
}

 

그리고 ProcessXmlTask 객체에서 결과값을 TextView 에 셋팅해야 하는데 onPostExecute() 함수를 오버라이딩해서 처리 합니다. doInBackground() 하면 Thread 에러 납니다. onPostExecute() 함수는 스레드가 종료되면 끝에 실행되는 함수입니다.

 

@Override
protected void onPostExecute(Void result) {
	mResult.setText(streamTitle);
	super.onPostExecute(result);
}

 

다음은 SAX API DefaultHandler 을 상속받아 만든 RSSHandler 입니다. 상속하게 되면 필수로 구현해야 되는 함수들이 있는데 startDocument, endDocument, startElemnet, endElement, characters 등이 있습니다. 함수명에서 알수 있듯이 xml 문서가 시작되고 끝날 때, 요소가 시작될때와 종료될때함수들입니다. 이곳에서 값을 읽어와 문자열을 구성한 것입니다.

 

private class RSSHandler extends DefaultHandler {
	final int stateUnknown = 0;
	final int stateTitle = 1;
	int state = stateUnknown;

	int numberOfTitle = 0;
	String strTitle = "";
	String strElement = "";

	@Override
	public void startDocument() throws SAXException {
		strTitle = "--- Start Document ---\n";
	}

	@Override
	public void endDocument() throws SAXException {
		strTitle += "--- End Document ---";
		streamTitle = "Number Of Title: " + String.valueOf(numberOfTitle) + "\n" + strTitle;
	}

	@Override
	public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
		if (localName.equalsIgnoreCase("title")) {
			state = stateTitle;
			strElement = "Title: ";
			numberOfTitle++;
		} else {
			state = stateUnknown;
		}
	}

	@Override
	public void endElement(String uri, String localName, String qName) throws SAXException {
		if (localName.equalsIgnoreCase("title")) {
			strTitle += strElement + "\n";
		}
		state = stateUnknown;
	}

	@Override
	public void characters(char[] ch, int start, int length) throws SAXException {
		String strCharacters = new String(ch, start, length);
		if (state == stateTitle) {
			strElement += strCharacters;
		}
	}
}

 

레이아웃 xml 은 간단하므로 생략하도록 하겠습니다. 아래는 메인 activity 의 전체 소스입니다.

 

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;

import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.widget.TextView;

public class XmlSAXParserActivity extends Activity {

	String streamTitle = "";
	private TextView mResult;
	
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_xml_saxparser);

		mResult = (TextView) findViewById(R.id.result);

		ProcessXmlTask xmlTask = new ProcessXmlTask();
		xmlTask.execute("http://mainia.tistory.com/rss");
	}

	// AsyncTask<Params,Progress,Result>
	private class ProcessXmlTask extends AsyncTask<String, Void, Void> {
		
		protected Void doInBackground(String... urls) {
			try {
				
				URL rssUrl = new URL(urls[0]);
				SAXParserFactory mySAXParserFactory = SAXParserFactory.newInstance();
				SAXParser mySAXParser = mySAXParserFactory.newSAXParser();
				XMLReader myXMLReader = mySAXParser.getXMLReader();
				RSSHandler myRSSHandler = new RSSHandler();
				myXMLReader.setContentHandler(myRSSHandler);
				InputSource myInputSource = new InputSource(rssUrl.openStream());
				myXMLReader.parse(myInputSource);

			} catch (MalformedURLException e) {
				e.printStackTrace();
				mResult.setText("Cannot connect RSS!");
			} catch (ParserConfigurationException e) {
				e.printStackTrace();
				mResult.setText("Cannot connect RSS!");
			} catch (SAXException e) {
				e.printStackTrace();
				mResult.setText("Cannot connect RSS!");
			} catch (IOException e) {
				e.printStackTrace();
				mResult.setText("Cannot connect RSS!");
			}
			return null;
		}
		
		@Override
		protected void onPostExecute(Void result) {
			mResult.setText(streamTitle);
			super.onPostExecute(result);
		}
	}

	private class RSSHandler extends DefaultHandler {
		final int stateUnknown = 0;
		final int stateTitle = 1;
		int state = stateUnknown;

		int numberOfTitle = 0;
		String strTitle = "";
		String strElement = "";

		@Override
		public void startDocument() throws SAXException {
			strTitle = "--- Start Document ---\n";
		}

		@Override
		public void endDocument() throws SAXException {
			strTitle += "--- End Document ---";
			streamTitle = "Number Of Title: " + String.valueOf(numberOfTitle) + "\n" + strTitle;
		}

		@Override
		public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
			if (localName.equalsIgnoreCase("title")) {
				state = stateTitle;
				strElement = "Title: ";
				numberOfTitle++;
			} else {
				state = stateUnknown;
			}
		}

		@Override
		public void endElement(String uri, String localName, String qName) throws SAXException {
			if (localName.equalsIgnoreCase("title")) {
				strTitle += strElement + "\n";
			}
			state = stateUnknown;
		}

		@Override
		public void characters(char[] ch, int start, int length) throws SAXException {
			String strCharacters = new String(ch, start, length);
			if (state == stateTitle) {
				strElement += strCharacters;
			}
		}
	}
}
Posted by 녹두장군

댓글을 달아 주세요

  1. 2014.12.16 18:21  댓글주소  수정/삭제  댓글쓰기

    비밀댓글입니다

  2. Favicon of https://prodh.tistory.com 스무수 2015.01.06 13:59 신고  댓글주소  수정/삭제  댓글쓰기

    질문하나드릴게요
    xml데이터를 긁어온다는게 무슨뜻인가요??

  3. 참고했습니다! 2016.09.20 14:31  댓글주소  수정/삭제  댓글쓰기

    안녕하세요! 설명 정말 좋아서 잘 보고 참고했습니다! 감사합니다ㅎㅎ 하나 여쭈어볼게 있는데 파싱하려는 xml과 java파일이 하나씩 있잖아요? 저는 상황이 xml하나에 파싱java 하나와 이 xml에 기능을 넣어줄 xml의 java 하나 이렇게 java파일이 두개가 있어요 ㅜㅜ 정리하자면 서로 다른 두개의 java파일이 하나의 xml을 불러 각자 기능을 부여하는거죠! xml은 뜨긴 뜨는데 기능이 안들어가는거같아서... 혹시 이렇게 하면 안되는 건가요?