2012년 7월 18일 수요일

[JAVA] Reflection - 정해지지 않은 클래스를 사용하자


Reflections on Java Reflection


원문 : http://onjava.com/pub/a/onjava/2007/03/15/reflections-on-java-reflection.html
번역판 : http://www.hanb.co.kr/network/view.html?bi_id=1369

2012년 7월 10일 화요일

[안드로이드] API15>16젤리빈 변경 클래스 - ContentResolver

public final ContentProviderClient acquireUnstableContentProviderClient (Uri uri)

Since: API Level 16
acquireContentProviderClient(Uri)와 흡사하나, 대상 컨텐트 프로바이더의 안정성을 신뢰하지 않는 경우 사용한다. 이는 대상 컨텐트 프로바이더의 프로세스가 사라질 경우, 컨텐트 프로바이더에 의존된 프로세스들의 플랫폼 클린업 메카니즘을 해제 한다. 일반적으론, 한번 프로바이더를 얻으면 필요한 만큼 제약없이 사용 할 수 있으며, 프로세스가 백그라운드 상태여도 사라지지도 않는다고 가정 할 수 있다. 이 메소드를 사용 하면, 프로바이더와의 통신중 어떠한 오류가 발생 하더라도 나중에 재연결 할 수 있게, 반드시 close에 주의를 기울여야 한다. 특히, DeadObjectException을 잡아 컨텐트 프로바이더가 죽어버렸다는 걸 알 수 있는데, 이는 현재 ContentProviderClient 오브젝트가 유효하지 않으며, 이를 해제 해야 한다는 것을 나타낸다. 만일 프로바이더를 재시작해 새로운 작업을 수행하려 한다면, 새로 얻으면 된다.

public final ContentProviderClient acquireUnstableContentProviderClient (String name)

Since: API Level 16
acquireContentProviderClient(String)와 흡사 하나,  대상 컨텐트 프로바이더의 안정성을 신뢰하지 않는 경우 사용한다. 이는 대상 컨텐트 프로바이더의 프로세스가 사라질 경우, 컨텐트 프로바이더에 의존된 프로세스들의 플랫폼 클린업 메카니즘을 해제 한다. 일반적으론, 한번 프로바이더를 얻으면 필요한 만큼 제약없이 사용 할 수 있으며, 프로세스가 백그라운드 상태여도 사라지지도 않는다고 가정 할 수 있다. 이 메소드를 사용 하면, 프로바이더와의 통신중 어떠한 오류가 발생 하더라도 나중에 재연결 할 수 있게, 반드시 close에 주의를 기울여야 한다. 특히, DeadObjectException을 잡아 컨텐트 프로바이더가 죽어버렸다는 걸 알 수 있는데, 이는 현재 ContentProviderClient 오브젝트가 유효하지 않으며, 이를 해제 해야 한다는 것을 나타낸다. 만일 프로바이더를 재시작해 새로운 작업을 수행하려 한다면, 새로 얻으면 된다.

public final Cursor query (Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder, CancellationSignal cancellationSignal)

Since: API Level 16
주어진 URI로 쿼리를 수행해, 결과 집합의 Cursor를 리턴 한다.
최적의 성능을 위해, 호출자는 다음과 같은 가이드 라인을 따라야 한다:
  • 사용되지 않을 데이터를 저장소에서 읽는 것을 막기 위해 명시적인 프로젝션을 사용하라. 
  • selection 파라메터에 명시적인 값 대신에 'phone=?'와 같은  물음표 파라메터 마커를 사용하여, 해당 값만 다르게 하여 캐 동일한 쿼리로 인식 될 수 있도록 하라.
Parameters
uri컨텐트를 명시하기 위해 content:// 스키마를 사용하는 URI.
projection리턴받을 column의 리스트. NULL을 넣으면 모든 column을 리턴 하므로 비효율적임.
selection어떤 row를 리턴 할지 SQL WHERE 구문(WHERE 자체는 제외)형식으로 선언한 필터. NULL을 넣으면 모든 주어진 URI의 모든 row를 리턴함.
selectionArgs만일 selection에 ?를 사용 했다면, 순서대로 selectionArgs의 값들로 치환된다. 값들은 Strings으로 묶이게 된다.
sortOrder각 row를 어떻게 나열할지 SQL ORDER BY 구문(ORDER BY 자체는 제외) 형식으로 지정. NULL을 넣으면 기본값인 "unordered"가 사용된다.
cancellationSignal처리 중에 해당 작업을 취소시키기 위한 시그널로 없으면 null지정. 작업이 취소되면 쿼리가 수행된 후 OperationCanceledException 이 던져 진다.
Returns
  • 첫 항목의 바로 전을 가리키는 Cursor 오브젝트, 또는 null
See Also

[안드로이드] 젤리빈 추가 클래스 - CancellationSignal

원문
http://developer.android.com/reference/android/os/CancellationSignal.html
public final class
CancellationSignal
extends Object
java.lang.Object

android.os.CancellationSignal

Class Overview


진행중인 작업을 취소 할 수 있는 기능을 제공 합니다.

Summary


Nesterd Classes
interfaceCancellationSignal.OnCancelListener취소 후 호출될 리스너.
Public Constructors
CancellationSignal ()
 취소 시그널을 생성하며, 처음엔 취소되지 않은 상태 입니다.
Public Methods
voidcancel ()
작업을 취소하고 취소 리스너에 알립니다.
booleanisCanceled ()
작업이 취소되었다면 true를 반환합니다.
voidsetOnCancelListener ( CancellationSignal.OnCancelListener listener)
취소되면 호출될 취소 리스너를 지정합니다.
voidthrowIfCanceled ()
작업이 취소되면 OperationCanceledException을 던집니다..

[펼치기]
Inherited Methods
 From class java.lang.Object

Public Constructors



public CancellationSignal ()

Since: API Level 16 
취소 시그널을 생성하며, 처음엔 취소되지 않은 상태 입니다.

Public Methods



public void cancel ()

Since: API Level 16 
작업을 취소하고 취소 리스너에 알립니다. 만일 작업이 아직 시작되지 않았다면, 가능한한 바로 취소됩니다.

public boolean isCanceled ()

Since: API Level 16 
작업이 취소되었다면 true를 반환합니다.
Returns
  • 작업이 취소되었다면 True.

public void setOnCancelListener CancellationSignal.OnCancelListener linstener)

Since: API Level 16 
취소시 호출될 취소 리스너를 설정합니다. 이 메소드는 오래 걸리는 작업을 수행하는 동안, 취소 요청을 처리할 목적으로 데이터베이스나 컨텐트 프로바이더와 같은 취소 시그널의 수신자에 의해 사용될 것입니다. 이 메소드는 응용 프로그램 자체에서 사용되도록 의도된 메소드가 아닙니다. 만일 cancel()이 이미 호출 되었다면, 지정된 리스너도 즉시 호출됩니다. 이 메소드는 리스너가 제거된 뒤에는 호출되지 않음을 보장 합니다.
매개 변수
listener취소 리스너, NULL값을 지정하면 현재 지정된 리스너를 제거함.

public void throwIfCanceled ()

Since: API Level 16 
작업이 취소되면 OperationCanceledException을 던짐.
Throws
OperationCanceledException작업이 취소됨.

2012년 7월 8일 일요일

[안드로이드] 멀티스크린과 안드로이드 마켓


안드로이드 마켓에 릴리즈시 하나의 어플리케이션에 두개의 APK파일을 등록할 수 있는 MultipleScreens 기능이 있다.

AndroidManifest.xml 의 스크린사이즈가 다르거나 SDK Version이 다른 두개의 APK파일을 업로드 하여 Publish하면 되는거.. 하지만 해상도의 구분이 애매하였다.

열심히 구글링을 해보면...아래값들을 컨트롤하면 된다.
smallScreens = true (normalScreens 보다 작은 사이즈 지원)
normalScreens = true (normalScreens 사이즈 지원)
largeScreens = true (normalScreens 보다 큰 사이즈 지원)
xlargeScreens = true (largeScreens 보다 큰 사이즈 지원)


requiresSmallestWidthDp = 600 (Android 3.2 API Level 13이후부터 지원하는 attribute. 
600에 largeScreens = true, xlargeScreens = true를 설정하면 타블렛만 지원되는 어플이 된다.)


<supports-screens android:resizeable=["true"| "false"]
                  android:smallScreens = ["true" | "false"]
                  android:normalScreens = ["true" | "false"]
                  android:largeScreens = ["true" | "false"]
                  android:xlargeScreens = ["true" | "false"]
                  android:anyDensity=["true" | "false"]
                  android:requiresSmallestWidthDp="integer"
                  android:compatibleWidthLimitDp="integer"
                  android:largestWidthLimitDp="integer"/>

즉.....2.3에선 requiresSmallestWidthDp를 사용할 수 없고, 갤노트와 갤S2는 아래와 같이 구분하여 적용 시키면 마켓 필터링이 가능하다.


*. 갤럭시 S2
<supports-screens
     android:smallScreens="false"
     android:normalScreens="true"
     android:largeScreens="false"
     android:xlargeScreens="false"
     android:anyDensity="true"
/>


 *. 갤럭시 노트
<supports-screens
     android:smallScreens="false"
     android:normalScreens="false"
     android:largeScreens="true"
     android:xlargeScreens="false"
     android:anyDensity="true"
/>

추가로 엄청 중요한 사항이 생겼다. 위와 같이 했을 경우 마켓 릴리즈시 버전코드가 갤럭시 S2가 더 낮아야 한다. 즉!! 갤럭시 S2의 버전코드가 100이라면 갤럭시 노트의 버전코드는 101이 되어야 정상적인 릴리즈가 가능하다. 만약 갤럭시 노트의 버전 코드가 더 낮다면 빨간색 에러줄을 마주치게 된다. 아...이것때문에 엄청 암울했는데...ㅠㅠ 
혹 여기서 10.1인치를 필터링 시키려면 안드로이드마켓 등록시 지원등록단말에서 수동 삭제하면...ㅋㅋㅋㅋ된다.
내가 삽질한건??? 내가 원한건 다른 사이즈들은 다빼고 딱 normalScreens만 지원하고 싶었을 뿐인데...
이게 normalScreens = true로 하고, 다른 스크린을 false로 설정해도 normalScreens~xlargeScreens까지 지원된다는거다...
그래서 찾아보다가 아래와 compatible-screens를 찾게되었다. 역기서 screenSize="normal"로 설정하면 마켓상에서 딱!!! normalScreens만 지원된다...
허나...compatible-screens를 적용시키면 지원단말에서 국산단말은 제외되고, 해외향 단말만 지원된다.
젠장...된장...진장...아래처럼 모든 Density에 모든 screenSize를 설정해도 국내향단말은 지원단말에서 제외되어있다...ㅠㅠㅠㅠ
이걸 하나씩 확인해보다...왜 갤노트는 제외되지...왜 갤S2는 제외되지...
그러다 모든걸 적용시켜도 안된다는걸 알고 포기함.

    <compatible-screens>
        <screen android:screenDensity="xhdpi" android:screenSize="small"/>
        <screen android:screenDensity="ldpi" android:screenSize="small"/>
        <screen android:screenDensity="mdpi" android:screenSize="small"/>
        <screen android:screenDensity="hdpi" android:screenSize="small"/>
        <screen android:screenDensity="xhdpi" android:screenSize="normal"/>
        <screen android:screenDensity="ldpi" android:screenSize="normal"/>
        <screen android:screenDensity="mdpi" android:screenSize="normal"/>
        <screen android:screenDensity="hdpi" android:screenSize="normal"/>
        <screen android:screenDensity="xhdpi" android:screenSize="xlarge"/>
        <screen android:screenDensity="ldpi" android:screenSize="xlarge"/>
        <screen android:screenDensity="mdpi" android:screenSize="xlarge"/>
        <screen android:screenDensity="hdpi" android:screenSize="xlarge"/>
        <screen android:screenDensity="xhdpi" android:screenSize="large"/>
        <screen android:screenDensity="ldpi" android:screenSize="large"/>
        <screen android:screenDensity="mdpi" android:screenSize="large"/>
        <screen android:screenDensity="hdpi" android:screenSize="large"/>    
     </compatible-screens> 

1. 마지막으로 dpi구하는 공식
  context.getResources().getDisplayMetrics().density; 
2. dpi를 픽셀로 변환하는 공식
public static int convertDipToPx(Context context, int dip){
  final float scale = context.getResources().getDisplayMetrics().density;
  return (int) (dip * scale + 0.5f);
}


참조 : http://sptraulyo.tistory.com/447

[안드로이드] 스마트폰 레이아웃


요샌 안드로이드 폰 종류도 너무 많고 레이아웃, 해상도도 천차 만별...
외우려면 힘드니 이곳에 정리 하려 한다.

갤럭시넥서스: layout-sw360dp
갤럭시노트: layout-xhdpi-1280x800 (or layout-normal-xhdpi)
갤럭시탭10.1: layout-xlarge-mdpi(3.2이상 버전에서는 layout-sw800dp로도 가능)
HD(1280x720)폰: layout-xhdpi-1280x720 (layout-normal-xhdpi)
HTC Evo4g: layout-hdpi-960x540

OS버전 3.2이상에서는 layout-sw800dp와 같이 너비(짧은축의 길이)의 dip값으로 하면 편리할 듯 합니다.

해상도별 스크린 레이아웃안드로이드 2012/02/21 12:37
QVGA(240x320), 120dpi : HTC Tatoo
HVGA(320x480), 160dpi : 안드로원, HTC G1
WVGA(480x800), 240dpi : 넥서스원, 갤럭시A
FWVGA(480x854), 240dpi : 모토로이


1. Low desity 120 - ldpi
    QVGA(240x320)  : 2.6~3.0
    WQVGA(240x400) : 3.2~3.5
    FWQVGA(240X432) : 3.5~3.8


2. Medium density 160 - mdpi
   HVGA(320X480) : 3.0~3.5
   WVGA(480x800) : 4.8~5.5
   FWVGA(480X854) : 5.0~5.8


3. High density 240 - hdpi
   WVGA(480x800) : 3.3~4.0
   FWVGA(480X854) : 3.5~4.0


4. x High density 320 - xhdpi
    (720*1280)


갤럭시탭 10.1
drawable-xlarge-mdpi
layout-xlarge 또는 layout-1280x800


갤럭시탭 7.0
drawable-large-hdpi
layout-1024x600


일반폰 (480x800)
drawable-hdpi
layout


HD폰(1280x720)
drawable-xhdpi
layout-1280x720



갤럭시넥서스: layout-sw360dp
갤럭시노트: layout-xhdpi-1280x800 (or layout-normal-xhdpi)
갤럭시탭10.1: layout-xlarge-mdpi(3.2이상 버전에서는 layout-sw800dp로도 가능)
HD(1280x720)폰: layout-xhdpi-1280x720 (layout-normal-xhdpi)
HTC Evo4g: layout-hdpi-960x540

res/layout/ 폴더를 더더욱 구분하여 스마트폰의 해상도별 xml을 나눌뿐만 아니라
태블릿도 구분할수 있게되었어요(원래 그랬던건지..그냥 새로 만들어준건지는 나도몰라아아아)


res/layout/main_activity.xml          -> 스마트폰
res/layout-sw600dp/main_activity   -> 7인치 태블릿
res/layout-sw720dp/main_activity   -> 10인치 태블릿


public class MyActivity extends Activity 
{
@Override
protected void onCreate(Bundle savedInstanceState) 
{
super.onCreate();


Configuration config = getResources().getConfiguration();


if (config.smallestScreenWidthDp >= 600) 
{
setContentView(R.layout.main_activity_tablet);
} else {
setContentView(R.layout.main_activity);
}
}
}


—리소스포더이름으로구분처리
서로다른스크린의리소스관리
 - res/layout/my_layout.xml
Normal스크린사이즈레이아웃
 - res/layout-small/my_layout.xml
Small 스크린사이즈레이아웃
 - res/layout-large/my_layout.xml
Large 스크린사이즈레이아웃
 - res/drawable-ldpi/my_icon.png
Low density를위한아이콘
 - res/drawable-mdpi/dpi/my_icon.png
MediumDensity를위한아이콘
 - res/drawable-hdpi/my_icon.png
High Density를위한아이콘
 - res/drawable-nodpi/composite.xml
Density 와무관한리소스

* 밀도(Density)
 스크린해상도를기반으로물리적인넓이와높이안에얼마나많은픽셀이들어있는가를나타낸다. Lower density의스크린에서는같은넓이와높이안에더적은수의픽셀이있고, higher density의스크린에서는같은넓이와높이안에더많은수의픽셀이있다. 안드로이드는밀도를high, medium, low 세가지분류로나눈다. 플랫폼에서는실제스크린밀도에맞게리소스들의사이즈를조정한다.
Density-independent pixel (dip)
밀도와상관없이레이아웃의위치를표현할때사용하는가상의pixel 단위. Density-independent pixel 은기본밀도인160dip에서의물리적인 pixel과같다.
픽셀변환공식 pixels = dips * (density / 160)

아...저 토나오는 광경...같은게 하나도 없는 물건들...


갤럭시 노트
해상도  :  1280 * 800
Density  :  xhdpi
크기  :  5.3인치(large screen)
OS  :  Android 2.3 갤럭시 S2
해상도  :  800 * 480
Density  :  hdpi
크기  :  4.3인치(normal screen)
OS  :  Android 2.3  갤럭시 탭 10.1
해상도  :  1280 * 800
Density  :  mdpi
크기  :  10.1인치(xlarge screen)
OS  :  Android 3.0

참조 : http://sptraulyo.tistory.com/447

2012년 7월 6일 금요일

2012년 7월 4일 수요일

[Android] adb shell dumpsys


커맨드 창에 다음과 같이 입력하면 디바이스에 대한 자세한 정보를 확인 할 수 있다.
adb shell dumpsys
추가로 dumpsys 뒤에 옵션을 지정해 표시할 정보를 제한 할 수 있다. 
또한 dumpstate 도 있으니 디버깅에 유용하게 사용 하자.



dumpsys
  dumpsys는 안드로이드 폰의 어플리케이션 및 현재 기기의 상태에 대한 자세한 정보를 제공한다.
  (소스코드 위치: ./frameworks/base/cmds/dumpsys/dumpsys.cpp)

  dumpsys meminfo: 메모리 사용 정보를 표시
  dumpsys cpuinfo: CPU 프로세서 사용 정보를 표시
  dumpsys account: 모든 계정에 대한 정보를 표시
  dumpsys activity: Activity에 대한 정보를 표시
  dumpsys window: 키보드와 윈도우, 그리고 그들의 z order에 대한 정보를 표시
  dumpsys wifi: 접속 가능한 액세스 포인트와 현재의 연결 상태를 표시
  dumpsys power: 전원 관리와 관련된 정보(wakelock, screen off time 등)를 표시

dumpstate
  dumpstate는 device 상태정보를 추출하는 여러 명령어들의 조합으로 구성 (dumpsys를 포함)
  (소스코드 위치: ./frameworks/base/cmds/dumpstate/dumpstate.c)

  Usage: dumpstate  [-d]  [-o  file]  [-s]  [-z]
            -d: 파일 이름에 날짜 정보를 추가 (-o 옵션과 함께 사용)
            -o: 파일에 기록 (screen에는 표시하지 않음)
            -s: 결과를 콘솔 소켓에 기록
            -z: gzip 압축하여 파일로 기록 (-o 옵션과 함께 사용)

[안드로이드] SD 존재 확인

출처 : http://www.androes.com/141


일반적으로 외장카드 영역을 불러올때 /mnt/sdcard 이런 식으로 하드 코딩하시는 분들이 많은데
이런 경우 외장카드를 사용하지 않는 사용자인 경우 에러가 발생하게 됩니다.

사용자 폰에 외장카드 존재유무를 확인하여 처리하는 모듈을 간단히 구현해 봤으니 참고하세요!!

        String mSdPath;
        String ext = Environment.getExternalStorageState();
        if (ext.equals(Environment.MEDIA_MOUNTED)) {
            mSdPath = Environment.getExternalStorageDirectory().getAbsolutePath()+"/";
        } else {
            mSdPath = Environment.MEDIA_UNMOUNTED+"/";
        }
        File file = new File(mSdPath);
        if (!file.exists()) mSdPath = "";       

        // 파일 생성
        BufferedWriter out = new BufferedWriter(new FileWriter(mSdPath+"androes.txt"));
        out.write("test text messages");
        out.newLine();
        out.close();

        // 파일 삭제
        File file = new File(mSDPath + "/" + "androes.txt");
        file.delete();