반응형

1. 다국어 지원을 위한 values 추가


기본적으로 안드로이드 앱에서 사용되는 문자열들은 res\values\strings.xml에 정의해서 사용합니다.


여러 언어를 지원하려면 새로운 언어를 위한 values 디렉토리를 만들고 그 안에 그 언어로 된 strings.xml을 만들면 됩니다. 새로운 언어를 위한 values 디렉토리의 형식은 values-"언어 코드 2자리(소문자)" 입니다. 예를 들어 영어라면 values-en, 일어라면 values-jp 등으로 만들면 됩니다.


언어 코드는 ISO 639-1의 두자리를 사용하고, 그 코드는 http://www.loc.gov/standards/iso639-2/php/code_list.php 에서 찾아볼 수 있습니다.


아래에 가장 많이 쓸 것 같은 7개 언어를 정리해 봤습니다. (저는 영어, 한국어 이외에는 쓸 일이 없겠네요.)

  • 한국어 ko
  • 영어 en
  • 일어 jp 
  • 중국어 zh 
  • 불어 fr 
  • 독일어 de
  • 스페인어 es

만약 영어처럼 사용하는 지역이 여러 곳인 언어에 대해 특정 지역을 추가로 지정하고 싶으면

ISO 3166-1-alpha-2의 지역 코드 2자리를 values-"언어 코드 2자리(소문자)"-r"지역 코드 2자리(대문자)" 로 붙이면 됩니다. 예를 들어 미국에서 사용하는 영어라고 콕 집어 지정하고 싶으면 en-r에 US를 붙여서 values-en-rUS 로 하면 됩니다.


이에 대한 코드는 https://www.iso.org/obp/ui/#search/code/ 에 잘 나와 있습니다.



2. 다국어 지원을 위한 strings.xml 의 예제


한국어와 영어를 지원하는 앱의 예를 들어보도록 하겠습니다. 슬프지만, 영어를 할 줄 아는 사람이 전세계적으로 보면 더 많기 때문에 기본은 영어로 하고 한국어를 추가하도록 하겠습니다.


1) res\values\strings.xml


영어로 된 strings.xml은 다음과 같습니다.


1
2
3
4
5
6
7
8
<resources>
    <string name="app_name">Sample</string>

    <string name="hello">Hello</string>
    <string name="android">android</string>
    
    <string name="some_key">ca-app-pub-3930256*^^*99962527/6300978111</string>-->
</resources>


2) res\values-ko\strings.xml


한글을 위해 values-ko 디렉토리를 만들고 그 안에 strings.xml을 새로 만듭니다. 이 때 기본(영어) strings.xml와 내용이 동일하다면 아래처럼 생략해도 무방합니다. 특히 some_key와 같이 복잡한 내용이라면 한 곳에서 관리하는 것이 좋아보입니다. 하지만, 기본적으로 안드로이드에서는 모든 항목에 대해 별도로 나눠서 관리하는 것을 더 좋아하는 것도 같습니다.


1
2
3
4
5
<resources>
    <string name="app_name">예제</string>

    <string name="hello">안녕</string>
</resources>



3. 다국어 사용 예제


관리는 나눠서 하지만, 사용할 때는 동일하게 하는 것이 안드로이드의 다국어 지원 방식의 장점입니다. 익숙할테니 짧게 살펴보겠습니다.


1) xml


AndroidManifest.xml이나 layout 등에서는 다음 @string/app_name 처럼 사용하면 됩니다.

이 경우라면 기기 설정을 한국어로 한 경우라면 앱의 아이콘 아래 이름이 '예제'가 될 것이고, 나머지 경우라면 'Sample'이 될 것입니다.

 

1
2
    <application
        android:label="@string/app_name"


2) java


Activity와 같은 소스에서는 다음처럼 사용합니다.


1
        mTextView.setText(R.string.hello);



4. 앱 배포


만약 위의 예제처럼 두 개의 strings.xml이 다른 경우에는 배포를 위해 apk를 만들 때 다음과 같은 에러를 볼 수 있습니다.


Error:Execution failed for task ':app:lintVitalRelease'.

> Lint found fatal errors while assembling a release target.

To proceed, either fix the issues identified by lint, or modify your build script as follows:

...

android {

    lintOptions {

        checkReleaseBuilds false

        // Or, if you prefer, you can continue to check for errors in release builds,

        // but continue the build even when errors are found:

        abortOnError false

    }

}

...


이 경우 lint를 무시하고 싶다면 에러 메시지에서 말하는 것처럼 app 수준의 build.gradle에 아래처럼 추가하면 됩니다.


1
2
3
4
5
6
7
8
9
android {
    ...
    lintOptions {
        checkReleaseBuilds false
        // Or, if you prefer, you can continue to check for errors in release builds,
        // but continue the build even when errors are found:
        abortOnError false
    }
}



5. 예외


strings.xml에 정의한 것만으로는 부족할 때가 있는데 대표적인 경우가 다른 값들과 결합해서 문자열을 만들 때 입니다. 예를 들어 상품을 판매한다고 할 때 "이 상품은 1,000원입니다." 라고 한국어로 표현하는 것을 영어로 한다면 "It costs 1 USD." 처럼 문법이나 화폐 단위에 따라 문자열을 별도로 구성해줘야 할 필요가 생깁니다.


이런 경우에는 다음처럼 기기의 언어 코드를 가져와서 직접 적합한 문자열을 만들 수 있습니다.


1
2
3
4
5
6
7
8
        Locale mLocale = getResources().getConfiguration().locale;
        String language = mLocale.getLanguage();

        if (language.contains("ko"))
            //한국어인 경우 처리
        else if (language.contains("ko") {
            //한국어가 아닌경우 처리
        }


이상으로 안드로이드 앱에서 다국어를 지원하는 방법을 살펴봤습니다. 




출처: http://zeany.net/49 [소소한 IT 이야기]

반응형
,
반응형

디렉토리 구조

 파일, 폴더

 설명

 asets 폴더

 리소스 폴더이다.

 최초는 비어 있는데, 이 안에 비디오, 오디오 등의 파일을 저장한다.

 bin 폴더

 컴파일된 결과 파일이 저장된다.

 gen/R.java

 프로젝트 내의 각종 개체에 접근할 수 있는 ID를 정의한다.

 툴이 자동으로 관리하므로 직접 편집해서는 안된다.

 res

 문자열, 이미지 등 애플레케이션에서 사용할 리소스 파일

 src

 애플리케이션 소스코드 

 AndroidManifest.xml

 프로젝트의 버전이나 이름, 구성 등에 대한 정보를 가진다.

 default.properties

 프로젝트의 빌드 타겟이 명시되어 있다.

 proguard.cgf

 프로젝트의 빌드 타겟이 명시되어 있다.

 .classpath

 소스 파일의 위치, 출력 폴더, 공통 라이브러리 위치 등에 대한 정보가 기록되어 있다.

 .project

 빌드 순서와 방법 등이 명시되어 있다.

 리소스, 프리 컴파일, 자바 컴파일, APK 생성 순으로 빌드됨을 알 수 있다.

 

 

 

 

리소스 디렉토리

리소스 디렉토리는 이미지를 넣는 drawable 디렉토리와

레이아웃 XML 파일을 넣는 layout디렉토리 등으로 이루어져 있다.

 

기본 프로젝트에 자동으로 생성되지 않은 raw, xml 디렉토리 등은 직접 생성하면 된다.

 

어떤 모드에서라도 동일하게 보여지고 싶다면 res/layout/ 디렉토리에 작성해야 하며,

모드별로 각각 다르게 보여주고 싶다면, res/layout-port/, res/layout-land/에 작성한다.

 

 리소스

설명 

 res/drawable-hdpi

 hdpi에서 보여질 이미지

 res/drawable-ldpi

 ldpi에서 보여질 이미지

 res/drawable-mdpi

 mdpi에서 보여질 이미지

 res/drawable-xhdpi

 xhdpi에서 보여질 이미지

 res/drawable-nodpi

 밀도(density)에 상관없이 보여질 이미지

 res/layout/

 사용자 인터페이스 레이아웃을 정의하는 XML 파일

 res/layout-port/

 사용자 인터페이스 레이아웃을 정의하는 XML 파일(세로 모드)

 res/layout-land/

 사용자 인터페이스 레이아웃을 정의하는 XML 파일(가로 모드)

 res/menu/

 메뉴를 정의하는 XML 파일

 res/values/

 문자열 등의 각종 값을 정의하는 파일

 res/xml/

 XML 형태로 저장된 다양한 파일

 res/raw/

 기타 파일(mp3, mp4 등)

 

자세한 부분은

http://developer.android.com/guide/practices/ui_guidelines/index.html

여기서 참조한다.

 

 

 

매니페스트 구조

 <uses-permission />

 애플리케이션이 필요로 하는 권한

 <permission />

 외부 액티비티나 서비스가 필요로 하는 권한

 <instrumentation />

 액티비티가 실행되는 등의 주요 이벤트가 발생했을 때,

 애플리케이션의 어떤 부분을 호출할지를 지정(기록, 모니터링 등)

 <uses-library />

 추가로 필요로 하는 라이브러리 지정(구글 맵스)

 <uses-sdk />

 애플리케이션이 필요로 하는 안드로이드 버전

 <application />

 애플리케이션과 관련된 정보


반응형
,
반응형


안드로이드는 기본적으로 리눅스 커널 위에 탑재된 안드로이드 런타임인 DVM(Dalvik Virtual Machine, 달빅 가상 머신)에서 동작한다. 이를 그림으로 간단히 표현하면 다음과 같다.



안드로이드의 주요 컴포넌트를 각 영역별로 정리하면 다음과 같다.


  • 애플리케이션(APPLICATIONS): 자바로 개발된 애플리케이션이 위치하는 영역이며, 이메일 클라이언트, SMS 프로그램, 달력, 지도, 브라우저, 주소록 등의 애플리케이션이 탑재되어 있다. 또한 우리가 자바로 개발한 애플리케이션이 탑재되는 영역이 바로 여기이다.

  • 애플리케이션 프레임워크(APPLICATION FRAMEWORK): 애플리케이션 프레임워크는 애플리케이션을 개발하기 위해 필요한 각종 API를 제공하는 영역이다. 이 영역에 있는 각종 API를 사용하면 화면에 버튼이나 텍스트 등을 표현하거나 주소록 같은 다른 애플리케이션의 데이터를 사용할 수도 있다. 또한 이미지, 문자열 등의 여러 데이터를 접근하거나 애플리케이션의 생명주기(lifecycle)를 관리하는 API도 이 영역에서 제공한다.

  • 라이브러리(LIBRARIES): 안드로이드에서 사용할 수 있는 다양한 C/C++ 라이브러리를 제공하는 영역이다. 이 영역의 라이브러리는 모두 애플리케이션 프레임워크를 통해 개발자가 사용할 수 있게 하고 있다. BSD(버클리 소프트웨어 배포판)를 기반으로 한 표준 C 시스템 라이브러리가 임베디드 리눅스 기반의 디바이스에 맞게 수정되어 있으며, PacketVideo의 OpenCore를 기반으로 한 미디어 라이브러리는 MPEG4, H.264, MP3, AAC, AMR, JPG, PNG 등의 파일들을 지원한다. 서피스 매니저(surface manager)는 2D, 3D 그래픽를 지원하며, WebKit은 브라우저 기능을 지원한다. 그리고 임베디드용으로 개발된 데이터베이스 엔진인 SQLite(에스큐엘라이트)를 제공하고 있다.

  • 안드로이드 런타임(ANDROID RUNTIME): 안드로이드는 자바 기반으로 동작하지만 JVM(자바 가상 머신, Java Virtual Machine)을 그대로 사용하지 않고 DVM(달빅 가상 머신, Dalvik Virtual Machine)을 사용하고 있다. 그래서 작성된 소스 코드(.java)는 자바 컴파일러에 의해 클래스 파일(.class)로 컴파일되며, 클래스 파일은 DX 컴파일러에 달빅 바이트 코드로 변환되며 달빅 실행파일(.dex, Dalvik Executable)과 최적화된 달빅 실행파일(.odex, Optimized Dalvik Executable)로 저장된다. 이 파일들은 안드로이드 기기에서 실행되기 그리고 달빅은 메모리가 작은 소형 기기에서도 효율적으로 동작할 수 있도록 최적화되어 있다. 참고로 안드로이드 4.4(킷캣) 이전에는 Dalvik 기반이었지만 4.4에서는 ART가 새롭게 도입되었으며 안드로이드 5.0(롤리팝)부터는 ART 기반으로 변경되었다.

  • 리눅스 커널(LINUX KERNEL): 안드로이드는 리눅스 커널 3.0.1(안드로이드 4.0)을 기반으로 하며, 이를 통해 보안, 메모리 관리, 프로세스 관리, 네트워크 스택과 각종 드라이버를 제공한다.

TIP & TECH 달빅(Dalvik)
안드로이드는 자바 코드로 작성하기 때문에 자바 가상 머신(JVM, Java Virtual Machine) 상에서 동작한다고 생각할 수 있지만 실제로는 달빅 가상 머신(DVM, Dalvik Virtual Machine) 상에서 동작한다. 달빅은 자바 코드를 최적화시켜 소형 기기에서도 잘 작동할 수 있도록 해주며 자바 바이트 코드를 변환해서 확장자가 dex(Dalvik Executable)인 바이트 코드를 생성한다. 또한 달빅은 JIT(Just In Time) 컴파일 방식을 사용하기 때문에 앱을 실행할 때마다 바이트 코드를 머신 코드로 변경하며 이 과정에서 추가적인 메모리를 필요로 한다.안드로이드 4.4(킷캣)까지만 사용되었으며 5.0(롤리팝)부터는 ART로 변경되었다.

TIP & TECH ART(Android Run Time)
안드로이드 5.5(롤리팝)부터 기본으로 채택되었으며 다음과 같은 장점을 가지며 하위호환성을 위해 달빅과 동일한 바이트코드를 사용한다.

  • AOT(Ahead-of-time) 컴파일
  • 가비지컬렉션 기능 향상
  • 디버깅 지원 기능 향상

ART에서 채택한 AOT 컴파일은 앱이 실행될 때 바이트 코드를 변환하는 대신에 앱이 설치될 때 DEX 바이트 코드를 머신 코드로 변환하는 작업을 한다. 그래서 설치 시간이 길어지지만 실행시간은 짧아지는 장점이 있다.

반응형
,
반응형

GC는 Garbage Collector의 약자입니다


dalvikvm Tag 로 


GC_CONCURRENT freed 11405k, 59% free 3107K/7431K, external 3299k/4120k, puased 4ms+3ms


라는 log가 찍힙니다. 


다음과 같은 format으로 로그가 찍힙니다.


[Reason] [Amount Freed], [Heap Statistics], [External Memory Statistics], [Pause Time]


[Reason] : GC 발동의 원인을 나타냅니다.


1. GC_FOR_MALLOC : 객체 생성의 있어서 힘에 메모리를 할달 받아야 할 때 힙에 남아있는 사용가능한 메모리 공간이 충분치 않을때.

2. GC_EXPLICIT : GC가 명시적으로 불렸을 때. Runtime.gc(), VMRuntime.gc(), SIGUSR1 등.

3. GC_CONCURRENT : 힙의 사용 한계점(사용 한계점은 내부적으로 정해진다.)을 넘어섰을때.

4. GC_EXTERNAL_ALLOC : VM이 garbage 될 객체들이 사용하고 있는 공간을 그렇지 않은 객체들을 위해 공간을 미리 확보하려 할때.

5. GC_HPROF_DUMP_HEAP : 힙의 컨텐츠를 파일로 저장할 때(WITH_HPROF flag를 사용할 때만)


[Amount Freed] : 말 그대로 읽은 파일의 Kbyte를 나타낸다.


[Heap Statistics] : GC가 발동 된 이후의 상태를 말한다. 


59% free 3107K/7431K => 남은 공간 59%, 사용중인 공간 3107K, 힙의 총 사이즈 7413K


[External Memory Statistics] : 외부 메모리 관련인데.... Bitmap 관련해서 외부메모리 따로 할당하는 것인데... 잘 이해가 안가서 생략.... ㅈㅅ (Bitmap 관련해서 따로 메모리를 쓰는 경우가 아니라면 값이 변하지 않는 것 같습니다.)


[Pause Time] : GC로 인해 일시정지된 시간 (milliseconds)


4ms+3ms => GC_CONCURRENT 일때에만 2개의 []ms+[]ms 꼴로 출력된다. 앞의 []ms는 GC가 발동되기 이전의 pause 시간이고, 뒤의 []ms는 garbage collecting이 거의 완료된 순간에 pause된 시간이다. 


참고 문헌 : http://stackoverflow.com/questions/4976566/what-do-gc-for-malloc-gc-explicit-and-other-gc-mean-in-android-logcat 


반응형
,
반응형

startWith: 문자열이 지정한 문자로 시작하는지 판단 같으면 true반환 아니면 false를 반환한다.(대소문자구별)

1
2
3
String str = "apple";
boolean startsWith = str.startsWith("a");
System.out.println("startsWith: " + startsWith);

결과값:true


endWith:문자열 마지막에 지정한 문자가 있는지를 판단후 있으면 true, 없으면 false를 반환한다.(대소문자구별)

1
2
3
String str = "test";
boolean endsWith = str.endsWith("t");
System.out.println("endsWith: " + endsWith);

결과값:true


equals:두개의 String에 값만을 비교해서 같으면 true, 다르면 false를 반환한다.(대소비교)

1
2
3
4
String str1 = "java";
String str2 = "java";
boolean equals = str1.equals(str2);
System.out.println("equals: " + equals);

결과값:true


indexOf:지정한 문자가 문자열에 몇번째에 있는지를 반환한다.

1
2
3
String str = "abcdef";
int indexOf = str.indexOf("d");
System.out.println("indexOf: " + indexOf);

결과값:3


lastindexOf:문자열에 지정한 문자가 마지막몇번째에 있는 int를 반환한다.

1
2
3
String str = "AdnroidApp";
int lastIndexOf = str.lastIndexOf("A");
System.out.println("lastIndexOf:" + lastIndexOf);

결과값:7


length:문자열의 길이를 반환한다.

1
2
3
String str = "abcdef";
int length = str.length();
System.out.println("length: " + length);

결과값:6


replace:문자열에 지정한 문자" "가 있으면 새로 지정한 문자" "로 바꿔서 출력한다.

1
2
3
String str = "A*B*C*D";
String replace = str.replace("*", "-");
System.out.println("replace: " + replace);

결과값: A-B-C-D



replaceAll:정규표현식을 지정한 문자로 바꿔서 출력한다.

1
2
3
String str = "AB CD";
String replaceAll = str.replaceAll("\\p{Space}", "*");
System.out.println("replaceAll: " + replaceAll);

결과값: AB*CD


split:지정한 문자로 문자열을 나눌수 있다.(배열로 반환)

1
2
3
String str = "A:B:C:D:abcd";
String[] split = str.split(":");
System.out.println("split: " + split[1]);

결과값:B


substring:문자열에 지정한 범위에 속하는 문자열을 반환한다.(시작범위에 값은 포함하고, 끝나는 범위에 값은 포함하지않는다.)

1
2
3
String str = "ABCDEF";
String substring = str.substring(0, 2);
System.out.println("substring: " + substring);

결과값:AB


toLowerCase: 문자열에 대문자를 소문자로 변환한다.

1
2
3
String str = "abcDEF";
String toLowerCase = str.toLowerCase();
System.out.println("toLowerCase: " + toLowerCase);

결과값:abcdef


toUpperCase:문자열에 소문자를 대문자로 변환한다.

1
2
3
String str = "abcDEF";
String toUppercase = str.toUpperCase();
System.out.println("toUppercase: " + toUppercase);

결과값:ABCDEF


toString:문자열을 그대로 반환해준다.

1
2
3
String str = "1234";
String toString = str.toString();
System.out.println("toString: " + toString);

결과값:1234


trim:문자열에 공백을 없에준다.

1
2
3
4
String s = "     java java java     ";
String v;
v = s.trim();
System.out.println("trim:" + v);

결과값:java java java


valueOf:지정한 개체의 원시 값을 반환

1
2
3
4
5
6
int i = 12345;
long l = 1L;
char c = '1';
System.out.println("valueOf: " + String.valueOf (i));
System.out.println("valueOf: " + String.valueOf (l));
System.out.println("valueOf: " + String.valueOf (c));

결과값:

valueOf: 12345

valueOf: 1

valueOf: 1


compareTo:두개의 String를 앞에서부터 순사적으로 비교하다가 틀린부분이 있으면 비교하는 String에 캐릭터값을 반환한다.(대소문자를 구별)

1
2
3
4
5
6
7
8
9
10
String str1 = "A";
String str2 = "B";
int compareTo = str1.compareTo(str2);<p></p>
if(compareTo > 0){<p></p>
       System.out.println(str1 + " > " +str2);
} else if (compareTo == 0){
       System.out.println(str1 + " = " +str2);
} else{
       System.out.println(str1 + " < " +str2);
}

결과값:

A < B


contains:두개의 String을 비교해서 비교대상 String을 포함하고 있으면true, 다르면 false를 반환한다.

1
2
3
4
String str1 = "abcd";
String str2 = "c";
boolean contains = str1.contains(str2);
System.out.println("contains: " + contains);

결과값:true


charAt:지정한 index번째에 문자를 반환한다.

1
2
3
String str = "charAt";
char charAt = str.charAt(2);
System.out.println("charAt: " + charAt);

결과값:a


concat:문자와 문자를 결합해준다.

1
2
3
4
String str1 = "Han";
String str2 = "SeeJin";
String concat = str1.concat(str2);
System.out.println("concat: " + concat);

결과값:HanSeeJin


format:서식문자열을 이용해서 서식화된 문자열을 반환한다.

1
2
3
int i = 123456789;
String str = String.format("%,d", i);
System.out.println("format: " + str);

결과값:123,456,789


matches:지정한 정규 표현과 일치 할때 true를 반환한다.

1
2
3
4
5
int i = 123456;
String str1 = String.format("%,d", i);
String str2 = "123456";
boolean matches = str1.matches(str2);
System.out.println("matches: " + matches);

결과값:false


replaceFirst:문자열에 지정한 문자" "가 있으면 첫번째만 새로지정한 문자" "로 바꿔서 출력한다.

1
2
3
String str = "Aman";
String replaceFirst = str.replaceFirst("A", "super");
System.out.println("replaceFirst: " + replaceFirst);

결과값:superman


참고 : http://sks3297.tistory.com/28

반응형
,
반응형

안드로이드에서 URL이미지 로딩을 위해 잘만들어진 오손소스 라이브러리를 소개한다.

 

Android Universal Image Loader

Android Universal Image Loader는 많은 앱에 적용되어 있고, Executor, 스레드 풀 크기, , Bitmap Options 등 변경할 수 있는 옵션이 있다. android.app.Application 클래스를 상속한 클래스에서 ImageLoader 객체를 초기화한 후 각종 옵션을 설정하고 사용할 수 있다.

 

AQuery

AQuery는 XML 파싱과 권한 관리 등 다양한 기능을 가진 라이브러리이나 이미지 로딩과 캐시 기능도 제공하기 때문에 분석 대상으로 선정했다. jQuery와 비슷한 메서드 체인 문법을 지원한다. 

 

droid4me Bitmap Downloader

droid4me Bitmap Downloader(이하 droid4me)도 Activity 라이프사이클 관리, 예외 처리, 로깅 등의 기능을 제공하는 라이브러리이나 이미지 처리와 캐시도 제공한다. 

 

Volley Image Loader

Volley Image Loader(이하 Volley)는 Google I/O 2013에서 발표된 뜨거운 라이브러리이다. HTTP API 호출에도 초점을 맞추고 있기 때문에 HTTP 클라이언트 라이브러리로 분류할 만도 하다. Google Play 앱에 쓰였으며, Google I/O에서 관련 세션의 발표자는 Volley의 성능이 다른 모든 라이브러리를 압도했다고 자신 있게 말했다. 

 

Novoda’s Android Image Loader

Novoda’s Android Image Loader(이하 Novoda)는 이미지 로딩의 기본적인 기능에 충실한 라이브러리이다. ImageView에 Tag를 설정하여, Tag에서 URL을 불러와서 다운로드하는 방식으로 동작한다. 

 

Picasso

Picasso는 근래에 많은 오픈 소스를 공개하고 있는 Square Inc.가 개발한 라이브러리이다. Square Inc.에서 개발한 HTTP 클라이언트 오픈 소스인 OkHttp를 HTTP 클라이언트로 활용한다. 메서드 체인 방식이라 직관적이고 사용하기 편리하다. 


반응형
,
반응형

http://www.netmite.com/android/mydroid/2.0/packages/apps/ 

 

다운 받는 방법을 모르겠다 ㅠㅠ소스 참고할때 유용할 듯


반응형
,
반응형

try {

PackageInfo info = getPackageManager().getPackageInfo(

            "패키지명", 

            PackageManager.GET_SIGNATURES);

for (Signature signature : info.signatures) {

MessageDigest md = MessageDigest.getInstance("SHA");

  md.update(signature.toByteArray());

  Log.d("debug", Base64.encodeToString(md.digest(), Base64.DEFAULT));

}

} catch (NameNotFoundException e) {

} catch (NoSuchAlgorithmException e) {

}

반응형
,
반응형

데이터 구조가 잡히기 전 임시? 데이터 파일용으로 xml을 사용하려고 합니다. 뭐 만들어두면 간단한 설정파일등에 사용도 가능하구요.


기존에 잘 썼던 TinyXml을 쓸까 하다가 MSXml과 XmlLite등 다른 것들도 포착이 되네요. 세부적으로 프로그래밍 API까진 아니고 간단하게 리서치 한 내용을 포스팅 해봅니다.

  • XML 파싱 방식
SAX(Simple API for XML)와 DOM(Document Object Model)이 있습니다.

  • SAX(Simple API for XML)
XML문서 구성요소를 읽어 들일때마다 이벤트로 처리해 주기 때문에 대용량 처리에 적합하고 빠르고, 대용량 문서나 많은 문서를 처리할 때 적절합니다. 단점으로는 읽어낸 데이터를 다시 이용할 수 없어 재활용하려면 자료구조를 따로 만들어줘야 합니다.
  • DOM(Document Object Model)
각각의 구성요소를 객체로 모델링화해서 객체가 가진 속성과 메소드를 통해 문서의 구조와 데이터를 다룰 수 있도록 W3C가 국제표준으로 제안한 XML 프로그래밍 인터페이스입니다.

XML 문서를 해석하여 DOMTree형태로 메모리에 올립니다. 해서 자료구조를 가지고 있어서 데이터를 바로 읽고 수정뿐 아니라 노드 추가등의 작업도 가능합니다. SAX보단 느립니다.
DOM 방식
UTF-8 파싱을 지원하지만 기본적으로 유니코드로 컴파일이 안된다.
UTF-8로 된 파일에서 한글을 읽을 때 MultiByteToWideChar에 CP_UTF8옵션으로 읽을 것.
UTF-16미지원

    • MSXML
DOM 방식.
COM.
SAX도 지원하는듯.
MSXML버젼 때문에 정상적으로 파싱 하지 못하는 경우가 발생할 수 있다. 별도 MSXML 배포버젼이 있지만 일반적으로 유저들은 IE를 설치할 때 같이 배포된 MSXML을 사용하기 때문에 사용자의  IE버젼과 OS버젼에 따라 이런 경우가 발생한다.
이걸로 개발하면 유저들도 닷넷 프레임워크를 필요로 한다. 그런데 요즘엔 XP SP2이상이면 기본으로 깔려 있으니 상관 없을 듯.

SAX방식.
작고 가볍다.
MSXML에 비해 제공되는 기능은 적다. 파싱을 위한 코딩 량이 기존에 비해 커질 수 있다.
SAX방식.
SAX 방식.
utf-16지원.
Apache 프로젝트중 하나.
유니코드 지원 되는 듯.
파싱만 된다. 생성은 안됨.

  • ACEXML
SAX 방식.
utf-16지원.


검색해보니 17메가짜리 XML을 파싱하는데 SAX는 1초 DOM은 62초 넘게 걸렸다고 하네요. DOM은 XML 용량이 크지않고 데이터에 임의 접근이 자주 일어날 때, 내용을 XML 파일로 백업할 때 유용할 듯합니다. 그외 나머지는  SAX방식으로 접근하면 될 듯 하네요.

그나저나 구글 블로거에서 쓰니 영 글 모양새가 이쁘지가 않은...;; 


반응형
,
반응형

미쳐버릴 정도로 날 괴롭힌 녀석 XML

우선 내가 파싱하고 싶었던 데이터는

<person>

       <student>

             <num>1</num>

             <name>Yang YuMi</name>

             <university>Korea University</university>

             <major>English History</major>

             <valunteer>Yes</valunteer>

             <language>English, Russian, Japaness</language>

             <hobby>Dance Sports</hobby>

             <talent>Sing</talent>

       </student>

       <student>

             <num>2</num>

             <name>Kim JunhMin</name>

             <university>SukMyung University</university>

             <major>Language Information</major>

             <valunteer>Yes</valunteer>

             <language>English, Japaness</language>

             <hobby>Movie, Travel</hobby>

             <talent>English, Japaness</talent>

       </student>

       <student>

             <num>3</num>

             <name>Jung MinJu</name>

             <university>InHa University</university>

             <major>Architector</major>

             <valunteer>Yes</valunteer>

             <language>English, French, Japaness</language>

             <hobby>Playing Guitar, Draw Picture</hobby>

             <talent>French</talent>

       </student>

</person>

 

이런 식이었고 책에는 대부분 학생 노드 아래 하나의 노드에 하나의 Text만 있는지라 프로그래밍 실력이 부족해서 인지 아무튼 XML 파일에 있는 위의 데이터를 String 객체에 집어 넣는데 까지는 성공했는데DOM파서를 써서 불러오면 null값이 불러진다 던지아니면 node의 이름만(num, name 같은 것들불러와서 참 고생했습니다아래 방법은 XmlPullParser를 이용한 해결책입니다. DOM 파서를 사용해보고 싶었는데 잘 안되더라구요.

 

 

우선 XML파일 위치는 프로젝트에 [assets] 폴더를 생성하고 그 안에 집어 넣었습니다. String 객체에 집어 넣는 방법은 아래와 같습니다.

 

try {

              personXMLString = getXMLFileFromAssets();

       } catch (IOException e) {

             // TODO Auto-generated catch block

                    e.printStackTrace();

       }

}

위의 소스는 public void onCreate(Bundle savedInstanceState에서 넣었습니다물론 다른 곳에서 호출해도 상관없다는 거 잘아시죠?

personXMLString  String으로 getXMLFileFromAssets(); XML 파일에서 String으로 저장한 것을 리턴해 준 값을 받습니다좀 더 자세한 것은 아래 getXMLFileFromAssets() 를 보시면 알 수 있을 겁니다.

private String getXMLFileFromAssets() throws IOException {

            

             AssetManager assetManager = getResources().getAssets();

             AssetInputStream ais = (AssetInputStream)assetManager.open("personinfo.xml");     

             BufferedReader br = new BufferedReader(new InputStreamReader(ais));

      

             String line;

             StringBuilder data = new StringBuilder();

             while((line=br.readLine()) != null)

                    data.append(line);

             Log.i("getXML", data.toString());

            

             return data.toString();

            

       }

보시기 어려우면 Eclipse에 복사해서 보시면 쉬우실 겁니다personinfo.xml 에서 데이터를 뽑아내서 String에 저장합니다.

 

그리고 가장 중요한 XmlPullParser를 이용한 각각의 데이터를 저장하는 법입니다.

private void PullParserFromXML(String data) {

             boolean boolean_num = false,

                           boolean_name = false,

                           boolean_university = false,

                           boolean_major = false,

                           boolean_valunteer = false,

                           boolean_language = false,

                           boolean_hobby = false,

                           boolean_talent = false,

             boolean done = false;

            

             try{

                    XmlPullParserFactory factory = XmlPullParserFactory.newInstance();

                    XmlPullParser parser = factory.newPullParser();

                    String sTag;

                    parser.setInput(new StringReader(data));

                   

                    int eventType = parser.getEventType();

                   

                    while(eventType != XmlPullParser.END_DOCUMENT) {

                           switch(eventType) {

                           case XmlPullParser.START_DOCUMENT:            // 문서의 시작

                                 Person = new ArrayList<pesronData>();

                                 break;

                                

                           case XmlPullParser.END_DOCUMENT:        // 문서의 

                                 break;

                                

                           case XmlPullParser.START_TAG:                 // 시작 태그를 만나면 이름을 살펴봐서작업(아무 일도 안하거나 값을 읽어 저장

                                 sTag = parser.getName();

                                 if(sTag.equals("student"))

                                        StudentData = new personData();

                                 if(sTag.equals("num"))

                                        boolean_num = true;

                                 else if(sTag.equals("name"))

                                        boolean_name = true;

                                 else if(sTag.equals("university"))

                                        boolean_university = true;

                                 else if(sTag.equals("major"))

                                        boolean_major = true;

                                 else if(sTag.equals("valunteer"))

                                        boolean_valunteer = true;

                                 else if(sTag.equals("language"))

                                        boolean_language = true;

                                 else if(sTag.equals("hobby"))

                                        boolean_hobby = true;

                                 else if(sTag.equals("talent"))

                                        boolean_talent = true;

                                 break;

                                

                           case XmlPullParser.END_TAG:                   // End 태그를 만나면

                                 sTag = parser.getName();

                                 if(sTag.equalsIgnoreCase("student") && StudentData != null){

                                        Person.add(StudentData);

                                 }

                                 break;

                                

                           case XmlPullParser.TEXT:

                                 if(boolean_num) {

                                        StudentData.setPersonNum(parser.getText());

                                        boolean_num = false;

                                 } else if(boolean_name) {

                                        StudentData.setPersonName(parser.getText());

                                        boolean_name = false;

                                 } else if(boolean_university) {

                                        StudentData.setPersonUniversity(parser.getText());

                                        boolean_university = false;

                                 } else if(boolean_major) {

                                        StudentData.setPersonMajor(parser.getText());

                                        boolean_major = false;

                                 } else if(boolean_valunteer) {

                                        StudentData.setPersonValunteer(parser.getText());

                                        boolean_valunteer = false;

                                 } else if(boolean_language) {

                                        StudentData.setPersonLanguage(parser.getText());

                                        boolean_language = false;

                                 } else if(boolean_hobby) {

                                        StudentData.setPersonHobby(parser.getText());

                                        boolean_hobby = false;

                                 } else if(boolean_talent) {

                                        StudentData.setPersonTalent(parser.getText());

                                        boolean_talent = false;

                                 break;

                           }                               

 

                           eventType = parser.next();

                    }

                    Log.i("PullXML"Person.get(0).getPersonNum() + " " +Person.get(0).getPersonMajor());

                    Log.i("PullXML"Person.get(1).getPersonNum() + " " +Person.get(0).getPersonMajor());

                    Log.i("PullXML"Person.get(2).getPersonNum() + " " +Person.get(0).getPersonMajor());

             } catch(Exception ex) {

                   

             }

       }

화면에 어찌 보이실지는 모르겠지만 처음 보시면 매우 복잡해 보이겠지만 자세히 들여다 보시면 참 쓸 때 없이 복잡한 소스입니다이렇게 짜면서도 과연 이렇게 밖에 도리가 없는가라는 의구심이 계속 들었지만 우선 이렇게 하면 저장은 할 수 있습니다.

소스를 자세히 보시면 PersonStudentData 가 있는데 아래와 같이 소스 시작 전에 선언해 준 값입니다.

List<personData> Person = null;

       personData StudentData = null;

위의 personData는 클래스로 만든 것입니다소스는 아래와 같아요.

public class PersonData {

       private String personNum;

       private String personName;

       private String personUniversity;

       private String personMajor;

       private String personValunteer;

       private String personLanguage;

       private String personHobby;

       private String personTalent;

       private String personMainPhoto;

       private String personUtubeURL;

      

       public String getPersonNum() {

             return personNum;

       }

       public void setPersonNum(String personNum) {

             this.personNum = personNum;

       }

       public String getPersonName() {

             return personName;

       }

       public void setPersonName(String personName) {

             this.personName = personName;

       }

       public String getPersonUniversity() {

             return personUniversity;

       }

       public void setPersonUniversity(String personUniversity) {

             this.personUniversity = personUniversity;

       }

       public String getPersonMajor() {

             return personMajor;

       }

       public void setPersonMajor(String personMajor) {

             this.personMajor = personMajor;

       }

       public String getPersonValunteer() {

             return personValunteer;

       }

       public void setPersonValunteer(String personValunteer) {

             this.personValunteer = personValunteer;

       }

       public String getPersonLanguage() {

             return personLanguage;

       }

       public void setPersonLanguage(String personLanguage) {

             this.personLanguage = personLanguage;

       }

       public String getPersonHobby() {

             return personHobby;

       }

       public void setPersonHobby(String personHobby) {

             this.personHobby = personHobby;

       }

       public String getPersonTalent() {

             return personTalent;

       }

       public void setPersonTalent(String personTalent) {

             this.personTalent = personTalent;

       }

       public String getPersonMainPhoto() {

             return personMainPhoto;

       }

       public void setPersonMainPhoto(String personMainPhoto) {

             this.personMainPhoto = personMainPhoto;

       }

       public String getPersonUtubeURL() {

             return personUtubeURL;

       }

       public void setPersonUtubeURL(String personUtubeURL) {

             this.personUtubeURL = personUtubeURL;

       }

}

Eclipse를 사용하면 쉽게 만들 수 있으니 참고하세요.

 

이것저것 시도하면서 배운 것도 많지만아직 수정해야 될 부분이 많아 보입니다딱 봐도 효율성도 엄청 부족한 점이 많고요수정할지는 불확실하지만 좀 더 나은 방법으로 수정하게 되면 올리도록 하죠커뮤니티에 올려볼까??

그리고 마지막으로 위의 문제를 해결할 수 있었던 블로그입니다누구신지는 모르겠지만 진심 감사하게 느낍니다서로서로 돕고 사는 게 인터넷 문화 아니겠습니까?

http://gaspotion.tistory.com/entry/Xmlparser-%EA%B8%B0%EB%B3%B8-%EC%98%88%EC%A0%9C 

반응형
,