춤추는 개발자

[Android Studio] XML파싱과 AsyncTask 이해하기 본문

Android/study_til

[Android Studio] XML파싱과 AsyncTask 이해하기

Heon_9u 2020. 12. 29. 01:31
728x90
반응형

 

공공 데이터를 활용한 버스노선 앱 만들기를 진행하겠습니다. 버스 번호를 입력하면 해당 버스의 위치와 진행방향을 알 수 있는 앱으로 만들기 전에 필요한 이론들을 살펴보겠습니다.

1. XML 문서 파싱하기

 앱을 만들기 전에 공공데이터의 API를 요청하면 응답받게되는 XML문서를 파싱하는 방법을 알아보겠습니다. XML은 HTML과 다르게 사용자 정의 태그를 만들어서 사용할 수 있습니다. 이러한 장점 덕분에 API응답 문서로 유용하게 사용됩니다.

 Android에서 데이터 파싱 방법으로 DOM(Document Object Model), SAX(Simple API for XML), Pull Parser, JDOM, JSON 등이 있습니다. 여기서는 Pull Parser를 사용하겠습니다.

 

2. XmlPullParser 인터페이스

 XmlPullParser는 next(), nextInt() 등의 메소드를 가지고 있는 인터페이스로 본 예제에서는 next() 메소드를 활용해 문서를 순차적으로 읽으며 다음 이벤트를 발생시킬 수 있습니다. getEventType()을 활용해서 다음과 같은 이벤트 처리 상태를 얻을 수 있습니다.

 

상태 의미
START_DOCUMENT 문서의 시작을 의미
END_DOCUMENT 문서의 끝을 의미
START_TAG 태그의 시작 (예: <data>)
END_TAG 태그의 끝 (예: </data>)
TEXT 태그의 시작과 끝 사이 (예: <data> content </data>)

 

 START_TAG와 END_TAG는 getName()을 사용해야 하고 TEXT는 getText()를 사용해야 한다. <data>이순신</data>가 있다면 START_TAG, TEXT END_TAG가 순차적으로 발생한다. 만약 TEXT인 '이순신'이 없어도 발생하는 이벤트는 동일하다.

 또 다른 예로는 <data><data1> content </data1></data>인 경우 START_TAG, TEXT, START_TAG, TEXT, END_TAG, END_TAG 순으로 이벤트가 발생한다.

 

 다음은 XmlPullParser가 가지고 있는 중요 메소드이다. 다음 메소드를 사용하기 위해서는 먼저 XmlPullParser객체를 생성해야 한다.

 

메소드 기능
getEventType START_DOCUMENT, START_TAG, END_TAG, TEXT 등 이벤트 유형을 반환한다.
getName 태그명을 가져온다.
getText 태그의 시작과 끝 사이의 데이터를 가져온다.
next 다음 이벤트를 가져온다.

 

3. XmlPullParser 객체 생성하기

 XmlPullParserFactory 클래스의 메소드인 newPullParser를 사용해 XmlPullParser 객체를 생성해야 한다. 이때, XmlPullParserFactory 클래스의 객체를 먼저 생성해야 한다. XmlPullParserFactory 클래스의 객체를 생성할 때는 new 연산자가 아닌 newInstance를 사용한다는 점에 유의해야 한다.

 

XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
factory.setNamespaceAware(true);
XmlPullParser xmlpp = factory.newPullParser();

 


 이번에는 네트워크 작업시 반응이 없어서 생기는 에러를 예방할 수 있는 AsyncTask에 대해 알아보겠습니다.

 

1. AsyncTask 이해하기

 AsyncTask 클래스를 상속하는 DownloadWebData 클래스를 제작해서 사용하겠습니다. AsyncTask는 백그라운드 쓰레드를 가지고 있어서 별도의 Handler나 Thread없이 쉽게 코드를 작성할 수 있습니다.

 만약 화면을 갱신하는 UI 쓰레드가 통신 작업을 하고 있을 때, 화면을 터치하는 이벤트가 발생하게 된다면 ANR(Application Not Responding) 에러가 발생하게 됩니다. 즉, 통신 작업을 수행해 줄 다른 쓰레드가 필요하게 됩니다. 이럴 때, AsyncTask 클래스를 상속받아 사용하면 이러한 에러 걱정없이 편리하게 사용할 수 있습니다.

 

2. AsyncTask 실행 단계

 AsyncTask 클래스를 활용한 작업 단계는 다음과 같습니다. 4단계 중 2단계인 doInBackGround만 다른 쓰레드(백그라운드 쓰레드)에서 실행되고 나머지는 메인 쓰레드에서 실행됩니다. 본 예제에서는 2단계와 4단계만 사용합니다.

 

1단계 onPreExecute doInBackGround 단계 전에 UI Thread에 의해서 실행되며 BackGround 작업 진행 정보에 대한 프로그래스바를 표시할 경우 사용한다.
2단계 doInBackGround onPreExecute가 끝난 후에 호출되며 실제로 BackGround 쓰레드에서 작업을 수행한다. 이때 작업에 필요한 값을 execute에서 파라미터로 전달받는다. 본 예제에서는 downData 메소드를 호출하여 웹 문서를 다운로드하는 기능을 수행한다.
3단계 onProgressUpdate doInBackGround 작업 수행 중에 호출되는 publishProgress 실행 후, UI Thread에 의해서 호출된다. 주로 doInBackGround 작업의 진행 정도를 표시하기 위한 프로그래스바의 업데이트 등에 사용된다.
4단계 onPostExecute doInBackGround 작업이 끝나면 메인 쓰레드에 의해 실행된다. doInBackGround 수행 후 result값을 받아 XmlPullParser를 사용해서 데이터를 처리한다.

 

3. AsyncTask 사용법

 AsyncTask 클래스를 상속하는 DownloadWebContent 클래스 객체를 생성하고 객체명.execute를 사용하여 AsyncTask를 작동시킨다.

 

DownloadWebContent dwcl = new DownloadWebContent();
dwcl.execute(strUrl);

 

4. doInBackGround 단계 - 웹 서버에서 가져온 문서를 화면에 표시하기

 doInBackGround 단계에서 실행되는 downloadByUrl 메소드에서는 웹과 연결하여 데이터를 Byte단위로 받고, 이를 문자로 변환시키는 역할을 수행한다. 다음은 이를 처리하기 위해 사용된 클래스들이다.

 

클래스 기능
HttpURLConnection 웹에서 데이터를 주고받기 위한 통신 규약 기능을 가지고 있다. URL을 사용해 참조하는 자원에 대해 읽고 쓰는 일을 할 수 있다. openConnection 메소드를 사용해 웹과 연결하고 BufferdInputStream 클래스를 연결된 URL의 소스를 Byte 단위로 다운받는다.
InputStreamReader Byte 단위의 데이터를 문자로 변환
BufferedReader 문자 단위로 데이터를 버퍼에 저장하는 역할.
버퍼를 사용하면 웹 소스와 직접 작업을 하지 않고 중간에 버퍼(=메모리)를 사용하므로 속도가 매우 향상된다.

 

public String downloadByUrl(String myurl) throws IOException {
	HttpURLConnection conn = null;
    
    try {
    	URL url = new URL(myurl);
        conn = (HttpURLConnection) url.openConnection();
        BufferedInputStream buffer = new BufferedInputStream(conn.getInputStream());
        BufferdReader buffer_reader = new BufferdReader(new InputStreamReader(buffer, "utf-8");
        String line = null;
        String getData = "";
        
        while((line = buffer_reader.readeLine()) != null) {
        	getData += line;
        }
        
        return getData;
    } finally {
   		conn.disconnect();
    }
}

 

파일 입력과 관련된 클래스와 메소드는 다음과 같다. 여기서 Stream은 한쪽 방향에서 다른 방향으로 통신을 연결하고 데이터를 전송해주는 것이다. Stream은 Byte단위로 데이터를 전송합니다.

 

클래스 및 메소드 기능
BufferedInputStream Byte 단위로 데이터를 전송한다. InputStream의 자손 클래스이며 버퍼를 사용해기 때문에 입출력 속도가 우수하다.
BufferedReader 문자 단위로 데이터를 전송한다. InputStream 대신에 Reader를 쓰면 문자 단위로 데이터를 전송한다는 의미이다. Java는 C와 다르게 문자형 char가 2Byte이므로 Byte 기반의 Stream으로 2Byte를 처리하기 어렵다. 문자 형태의 웹 데이터를 사용하기 위해서 InputStreamReader를 사용해서 문자형 데이터로 변환시키고 BufferedReader 클래스를 사용해 버퍼에 자료를 담는다.
InputStreamReader Byte 기반의 Stream 데이터를 지정된 인코딩 문자 데이터로 변환해주는 작업을 한다.
readLine() BufferedReader 클래스의 메소드로 파일을 Line(줄) 단위로 읽어준다.

 

 여기까지 버스노선 앱을 만들기 전에 숙지해야할 사항들을 알아보았습니다. 다음 포스팅에서는 Open API 활용방법과 앱 제작과정을 포스팅하도록 하겠습니다.

 

 

728x90
반응형