내 멋대로 안드로이드 - 6

2022. 7. 20. 10:43모바일프로그래밍/안드로이드

728x90

오늘은 저번에 만들어 본 클래스에 대한 설명을 xml로 달아보고 ClassLoader를 만들어서 런타임상에서 원하는 스팩을 가진 플러그인 클래스를 가져 오는 것을 해보고자 합니다

물론 잘 될지는 해봐야 아는 것이지만

여하튼 우선 xml을 하나 정해 보도록 하겠습니다. 최우선 적으로 해야 할 것은 정형화된 형식의 xml을 위해서 DTD나 스키마를 만들어야 하겠지만 xml 파일의 양식이 방대하기도 하고 해 본지도 너무 오래 되기도 해서 당장 만들어 내기에는 약간의 시간이 필요하기 때문에 다음에 만들어 보기로 하고 xml만 하나 만들도록 하겠습니다.

대신, 컨테이너와 각 플러그 인의 규약은 다음과 같은 엘리먼트가 존재 하여야 하고 validation check가 되었다고 가정을 하겠습니다.

 

엘리먼트는 다음과 같이 plug-in, name, class, desc로 만들겠습니다. 어트리뷰트를 만들어도 되지만  최대한 간단하게 만들도록 하겠습니다

 

<?xml version="1.0" encoding="UTF-8"?>
<plug-in>
<!—플러그 인 이름 -->
   <name> Convert Temperature </name>
<!—로딩할 클래스 이름 -->
   <class> com.skcc.lec.plugin.ConvertTemp</class>
<!—로딩할 클래스 설명 -->
   <desc> 온도변화프로그램</desc>
<!—로딩할 클래스 아규먼트 ,로 구분한다-->
   <args> To Celsius,To Fahrenheit </args>
<plug-in>

 

위의 내용에서 args라는 엘리먼트를 정하고 우리가 저번에 만든 온도 변환 프로그램 플러그 인의 라벨을 아규먼트로 넘기도록 하겠습니다. 물론 여기까지는 어디까지나 제 생각이기때문에 여러가지 다른 구현이나 내용이 나올 수 있겠습니다만, 그 중에 한가지라 생각해 주시면 좋겠습니다

 

그리고 제가 세팅한 Android는 1.1 API이기 때문에 이 API에 따라서 코딩 하도록 하겠습니다. 

자바에서도 여러가지 xml파서가 존재하지만 그 시스템에서 지원해주는 파서를 사용하는 것이 옳다고 판단되는 바 안드로이드에서 제공하는 xml API를 사용하도록 하겠습니다

 

그럼 우선 먼저 API 중 눈에 띄는 몇몇개의 API 내용을 보면 javax.xml과 javax.xml.parsers라는 패키지가 존재 하는 데요

이 패키지를 사용해서 XML을 파싱하겠습니다

 



우선 com.skcc.lec.parser 라는 패키지를 만들고 PlugParser라는 이름으로 파서를 만들어 보도록 하겠습니다

 

그러면 구현 이전에 우리가 만들어야 될 플러그 인들의 내용을 SAX(Simple API for XML)로 파싱 할 것인지, 아니면 DOM(Document Object Model)으로 파싱 할 것인지를 결정하여야 할 것 같습니다.

 

 

사실 개발자 입장에서 보면 쓰는 방식이나 각 엘리먼트나 어트리뷰트를 불러오는 방식이 약간 틀릴 뿐이지 다른 것은 없는 것이가 생각이 들어서 어떤 것으로 구현해되 무방하다고 생각합니다

그래서 DOM보다는 보통 XML 레퍼런스나 책을 구성할 때 예제를 만드는 순이 DOM예제를 먼저 만들고 그 다음에 SAX를 만들기 때문에 SAX로 핸들링 하는 것이 좋다고 생각이 들어서 SAX 파서를 사용해서 구현해 보도록 하겠습니다.

 

일반적으로 DOM의 경우에는 XML 파일 전체를 읽어 들여서 각 엘리먼트나 어트리뷰트를 메모리에 올려 놓고 진행하는 경우에 많이 사용하는 방식이고 반면 SAX 파서의 경우에는 일일이 각 엘리언트나 어트리뷰트를 핸들링 해주어야 합니다

 

구현 소스를 보시면 DefaultHandler를 상속 받아서 사용하는 것을 보실 수 있을 것이고 콜백 방식으로 문서를 읽은 즉시에 사용자로 하여금 파싱 할 수 있도록 하고 있습니다. 그래서 DOM 방식보다는 빠르겠죠…

 

그러면 우리가 만든 파서를 사용하는 프로그램을 제작하고 다음과 같이 xml이 제대로 파싱이 되었는 지 확인 해 보고자 다음과 같이 만들어진 내용을 컨테이너에 System.out으로 삽입합니다

 

구현부에서 보시면 아시겠지만 toString() 메소드를 오버라이딩 하였습니다.

com.skcc.lec.parser.PlugParser parser;

	/** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
		super.onCreate(savedInstanceState);
        parser = new com.skcc.lec.parser.PlugParser("com/skcc/lec/plugin/");
        System.out.println(parser.getPlugInData());
        setContentView(R.layout.main);
    }

 

PlugParser 소스를 보시면 위에 아규먼트로 ("com/skcc/lec/plugin/")가 왜 넘어 가야는지 아시겠지만 아시다시피 자바에서 패키지의 개념은 어떻게 보면 디렉토리 혹은 폴더와 같은 개념으로 간주됩니다.

그래서 우리가 만약 com.skcc.lec이라고 패키지이름을 정하고 자바 파일을 컴파일 하면 com skcc 그리고 lec이라는 폴더가 생성되고 그 하부에 우리가 원하는 자바의 바이트 코드 즉 클래스가 설치 되도록 되어 있구요. 

 

내부적으로 자바는 패키지 이름 사이의 “.” 표시를  슬래시 즉 “/” 표시로 바꾸어서 사용하도록 되어 있습니다.

 

결국 소스 코드 중 XR.parse(new InputSource(getClass().getResourceAsStream(name)));  의 부분에서 getResourceAsStream을 사용해서 우리가 사용한 리소스를 부르기 위해서는 “com.aa.lec.plugin.plug-in.xml”이라고 부르는 것이 옳은 일이나 내부적으로 이 부분이 위의 설명 처럼 바뀌어 “com/aa/lec/plugin/plug-in.xml”이라고 불러야 되는 것입니다.

 

 

우리가 정한 플러그인이 이를 로딩하는 컨테이너와 서로를 모르기 위해서는

 

첫째, 컨테이너 입장에서는 플러그인 클래스의 설명자가 어디 있는 지 정도는 알고 있다고 가정하구요

    ( 여기에서는 “com/aa/lec/plugin”)

둘째, 그 하부 디렉토리에 플러그인을 설명하는 xml이 존재 한다는 규약이 정해져 있다고 가정하겠습니다

셋째, 그리고 xml의 정확한 이름은 “plug-in.xml”로 정해 놓도록 하겠습니다

 

PlugParser 자바 소스에서 이 부분을 핸들링 하는 init()메소드를  약간만 들여다 보면 다음과 SAXParserFactory  -> SAXParser -> XMLReader 같은 순서로 부르게 되어 있습니다(물론 당연한 얘기 이겠죠)

 

void init()
{
	try{
		StringBuffer sb = new StringBuffer();
		sb.append(pkgname).append(name); //패키지 명과 이름을 합친다

		SAXParserFactory SPF = SAXParserFactory.newInstance();               
		SAXParser SP = SPF.newSAXParser();                

		XMLReader XR = SP.getXMLReader();  
		plug = new PlugHandler();         
		
        XR.setContentHandler(plug); //핸들러 클래스를 붙인다.

		//리소스를 부른다
		XR.parse(new InputSource(getClass().getResourceAsStream(name)));
	}
	catch(javax.xml.parsers.ParserConfigurationException pce)
	{
		//에러는 여기에
	}
	catch(org.xml.sax.SAXException se)
	{
		//에러는 여기에
	}
	catch(java.io.IOException ie)
	{
		//에러는 여기에                            
	}
}

 

자 그럼 일반적인 자바에서는

저 번 글에서도 말했듯이 jar 파일을 사용해서 원하는 리소스며 자바 파일들을 압축하고 묶어서 사용했다면 안드로이드에서 apk 파일로 묶어서 사용하고 있습니다

그리고 jar 파일의 형식을 그대로 사용했기 때문에 jar 명령으로도 풀리게 되어 있습니다. 그것에 대한 증거로 다음과 같이

그림&nbsp;1&nbsp;안드로이드API

 

Java.util 패키지의 JarFile 클래스를 그대로 사용하게 됩니다

일반적인 java 1.6 기준의 API와 별반 틀릴것이 없지만 몇몇 구현이 덧붙혀진 것이 아닌가 생각이 됩니다

특히나 클래스 이름이 ~Verifier에서 볼 수 있듯이 이 애플리케이션의 증명서가 있는 지 없는 지에 대한 부분이 강화 된 것이 아닌가

조심스럽게 추측해 볼 수가 있겠습니다.

 

 

그림&nbsp;2&nbsp;JSE6.0 API

 

프로젝트를 다음과 같이 생성하고

android create project
	--target 2
	--name TobeePlugIn2
	--path C:\Android\documents\내꺼\Apps6
	--activity MyContainer
	--package com.skcc.lec.container

 

Ant debug로 소스를 컴파일하고 나면 bin 디렉토리 아래에 안드로이드에 설치하고자 하는 파일이 생성됩니다

 

 

보시다 시피 이름은 TobeePlugIn2-debug.apk로 정해 졌습니다

 

따로 이 파일을 풀어 보면 다음과 같은 폴더 들이 생성되는 것을 확인 해 볼 수 있습니다.

 

 

압축을 풀고서 확인해본 폴더들입니다

 

 

일반적인 자바 파일과 폴더들 이외에 여러 가지 파일들이 있습니다만 여기서는 현재 위에서 생성한 파일인 plug-in.xml이 있는 지 확인하는 작업만 거치겠습니다

 

 

 

결과적으로 리소스 파일이라고 생각되는 xml 파일 이외에는 아무것도 없는 형상이 되었습니다

자바를 좀 알고 있는 사람이라면 다음과 같은 궁금점이 생기겠군요

 

클래스 파일들이 어디 갔을까? 하구요 (저도 궁금합니다 ㅡ.ㅡ;;)  이 문제에 대해서 실마리는 dex 파일이 가지고 있는 것 같은 데 이 부분은 다음에 알아보기로 하고 계속 진행하도록 하겠습니다

 

Strings.xml을 열어서 app-name의 이름을 바꾸어 주고

<?xml version="1.0" encoding="utf-8"?>
	<resources>
           <string name="app_name">Temperature Converter Container2</string>
           <color name="myColor">#3399CC</color>
           <string name="buttonHandler">plugInClickHandler</string>
           <string name="plugin">launchIt</string>
	</resources>

자 ant install로 설치를 거치고 나면

 

 

위와 같이 Temperature Converter Container2가 생성 된 것을 알 수 있습니다

만든 애플리케이션을 실행하면,

우선 그에 해당하는 UI를 만든 것이 아니라서 System.out으로 출력했기 때문에 adb로 확인 해 보면 다음과 같이 제대로 잘 나온 것을 확인 해 볼 수 있습니다.

 

 

사실 위의 리소스 즉 plug-in.xml을 찾기 위해서 classloader라는 것을 내부적으로 사용 했는 데요

다음 시간에는 Class 엘리먼트인 com.skcc.lec.plugin.ConvertTemp 클래스를 클래스 로더를 사용해서 동적으로 로딩하고 UI에 붙히는 작업을 해 실제적으로 안드로이드에서 나의 애플리케이션이 들어가 있는 곳이 과연 어디에 있는 지 알아보도록 하겠습니다.

그리고, 제 개인적으로 자바에서 꽃이라고 생각는 부분을 고르라면 이 클래스 로딩 메커니즘이랑 가비지 컬렉터가 아닌가 생각해 봅니다.

 

물론 이 문서의 목적도 사실 안드로이드 자바에 포커스를 맞추고 있는 것이 아니라 우리가 구현한 것들이 과연 시스템과 어떤 연관 관계를 가지고 있는 가를 밝히는 데 주된 관점을 가지고 있기 때문에 자바 소스를 일일이 설명하지는 않았습니다

 다만 제가 올린 소스 파일은 에뮬레이터에서 잘 구동 하였음으로 올린 소스 파일을 참고 하시기 바랍니다.

 

Apps6.zip
0.05MB

728x90