Android OS별 기능 분기

안드로이드 앱을 개발 하다보면 특정 API 부터 적용되는 기능들이 있다. 상위버전은 지원하게해야 되고 하위버전은 지원하지 않기 위해 보통은 API Level을 보고 판단하게 된다. 제조사가 OS의 기능을 100% 보장한다면 문제가 없지만 꼭 몇몇 제조사들은 빼버리기 때문에 ClassNotFoundException 예외가 발생한다. 

이런 문제점을 해결 하기위해 API Level 체크 외 다른 방법을 소개 할까한다.

기존 체크 방식
private void init() {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH){
        //사용가능한 버전이 아님
    }
    else{
        //사용가능한 버전
    }
}

 

위의 코드처럼 대부분 현재 SDK버전과 지원가능한 기능의 SDK버전을 비교해서 처리 하게 된다. 이럴 경우 실제로 제조사에서 해당기능을 임의로 빼버리는 경우 문제가 생기게 된다. 단순히 Try{} Catch{}로 Exception처리 할 수도 있으나, 좀 더 좋은 방법을 알아 보자.

ClassLoader와 Method라는 Class를 이용해서 Class와 Method를 invoke하는 방식이다.

좀 더 좋은 방법
public class MetadataEditorCompat {

    private Method mPutStringMethod;
    private Method mPutBitmapMethod;
    private Method mPutLongMethod;
    private Method mClearMethod;
    private Method mApplyMethod;

    private Object mActualMetadataEditor;

    /**
     * The metadata key for the content artwork / album art.
     */
    public final static int METADATA_KEY_ARTWORK = 100;

    private MetadataEditorCompat(Object actualMetadataEditor) {
        if (sHasRemoteControlAPIs && actualMetadataEditor == null) {
            throw new IllegalArgumentException("Remote Control API's exist, " + "should not be given a null MetadataEditor");
        }
        if (sHasRemoteControlAPIs) {
            Class metadataEditorClass = actualMetadataEditor.getClass();

            try {
                mPutStringMethod = metadataEditorClass.getMethod("putString", int.class, String.class);
                mPutBitmapMethod = metadataEditorClass.getMethod("putBitmap", int.class, Bitmap.class);
                mPutLongMethod = metadataEditorClass.getMethod("putLong", int.class, long.class);
                mClearMethod = metadataEditorClass.getMethod("clear", new Class[] {});
                mApplyMethod = metadataEditorClass.getMethod("apply", new Class[] {});
            } catch (Exception e) {
                throw new RuntimeException(e.getMessage(), e);
            }
        }
        mActualMetadataEditor = actualMetadataEditor;
    }

    public MetadataEditorCompat putString(int key, String value) {
        if (sHasRemoteControlAPIs) {
            try {
                mPutStringMethod.invoke(mActualMetadataEditor, key, value);
            } catch (Exception e) {
                throw new RuntimeException(e.getMessage(), e);
            }
        }
        return this;
    }

    public MetadataEditorCompat putBitmap(int key, Bitmap bitmap) {
        if (sHasRemoteControlAPIs) {
            try {
                mPutBitmapMethod.invoke(mActualMetadataEditor, key, bitmap);
            } catch (Exception e) {
                throw new RuntimeException(e.getMessage(), e);
            }
        }
        return this;
    }

    public MetadataEditorCompat putLong(int key, long value) {
        if (sHasRemoteControlAPIs) {
            try {
                mPutLongMethod.invoke(mActualMetadataEditor, key, value);
            } catch (Exception e) {
                throw new RuntimeException(e.getMessage(), e);
            }
        }
        return this;
    }

    public void clear() {
        if (sHasRemoteControlAPIs) {
            try {
                mClearMethod.invoke(mActualMetadataEditor, (Object[]) null);
            } catch (Exception e) {
                throw new RuntimeException(e.getMessage(), e);
            }
        }
    }

    public void apply() {
        if (sHasRemoteControlAPIs) {
            try {
                mApplyMethod.invoke(mActualMetadataEditor, (Object[]) null);
            } catch (Exception e) {
                throw new RuntimeException(e.getMessage(), e);
            }
        }
    }
}

위 예제코드는 RemoteControlClient로 ICS부터 사용가능 하다. getClassLoader()를 통해 Class를 가져오고, getMethod()를 통해 해당 Method를 가져와 invoke하는 방식이다. getClassLoader(), getMethod()로 호출시 ClassNotFoundExecpotion, NoSuchMethodException이 발생 하면 해당 클래스와 메소드를 사용하지 않도록 처리한다. 

실제 구글에서 안드로이드 RandomMusicPlayer 셈플 코드를 보면 이처럼 구성이 되어있다. 이렇게 method invoke방식이 약간 복잡 할 수 있으나 제조사의 안드로이드 OS의 커스터마이징시 발생 할 수 있는 예외를 처리 할 수 있다.

댓글 남기기