: 안드로이드는 계속 발전하기 때문에 버전에 따라서 동작이 변경된다. 다음은 안드로이드 버전 표이다. 버전과 API 레벨을 참고해서 버전에 따라 호환성에 맞게 코드를 작성해야 한다.


안드로이드에서 버전을 지정하기 위해서 android:minSdkVersion과 android:targetSdkVersion을 기재해야 한다. 보통 안드로이드 프로젝트를 생성할 때 설정하며 build.gradle 에서도 설정이 가능하다. 


- minSdkVersion : 앱이 실행될 수 있는 최소한의 API 레벨을 일컫는다. minSdkVersion API 레벨 미만의 디바이스는 앱 설치가 안 된다. 


- compileSdkVersion : 컴파일 시에 사용할 버전을 일컫는다. 컴파일 시에 어느 버전의 android.jar을 사용할 지 정한다. 예로 소스코드에 API Level 21부터 추가된 메서드를 이용하고 compileSdkVersion을 19로 지정한 경우 컴파일 할 때 해당 메서드가 존재하지 않는다는 오류가 납니다. 


- targetSdkVersion : 앱 실행 시 이용되는 설정이다. 실제 API Level에 따른 분기를 코딩할 때 targetSdkVersion을 보고 처리를 나눈다. 따라서 targetSdkVersion이 바뀌면 앱의 동작이 달라질 수 있다. 만약 targetSdkversion을 지정하지 않으면 minSdkVersion과 동일한 값으로 지정된다. 그래서 반드시 지정해야 한다. 또한 단말 버전에 따라 최신 기능을 쓸 수 있기 때문에 높은 API 레벨을 쓰는 것을 추천한다.


if(targetSdkVersion이 19 이상인 경우){ //targetSdkVersion이 19이상일 때의 처리 } else { //targetSdkVersion이 19미만일 때의 처리 }


: 앱을 개발할 때 API 레벨에 따른 동작의 차이에 제대로 대처하는 게 중요하다. API 레벨에 따라 특정 함수에 동작하는 방식이 다르기도 하고 함수가 아예 존재하지 않을 수도 있다. 예로 ArrayAdapter의 addAll() 메서드는 허니콤부터 사용가능하다. 따라서 프로요에서는 addAll() 함수가 존재하지 않아 사용이 불가능하다. 또한 AsyncTask의 경우 원래는 병렬 실행이었지만 허니콤부터는 순차 실행으로 변경됬다. 따라서 targetSdkVersion을 10이하로 하면 병렬 실행으로 동작한다. API 레벨 11이상인 곳에서는 순차 실행으로 동작하기 때문에 속도가 느려진다. 따라서 코드를 다음과 같이 작성해야 한다.

if(Build.VERSION.SDK_INT) >= 11){
	task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params);
}else{
	task.execute(params);
}

하지만 위와 같이 코딩하면 번거롭다. 그래서 안드로이드에서는 support-v4의 ~Compat 클래스를 제공한다. AsyncTaskCompat를 사용하면 위와 같이 if문으로 분기할 필요 없다. 그렇지만 ~Compat 클래스를 제공하지 않는 클래스들도 많이 존재한다. 이럴 때는 if문 분기를 이용해야 하는 데 매번 함수를 호출할 때마다 if문 분기를 사용하기는 많이 번거롭고 번잡하다. 오류도 발견하기 힘들다. 그래서 다음에 볼 구조를 활용하면 좋다. 메서드 안에서 if문으로 버전을 체크하지 않고 정적 초기화 블록에서 if문으로 버전을 체크하고 클래스를 지정한다. 

package test;

public class ClassCompat {
	
	....
	
	interface ClassCompatImpl{
		public boolean fun1();
		public boolean fun2();
		public int fun3();
		public void fun4();
	}
	
	static class BaseClassCompatImpl implements ClassCompatImpl{
		public boolean fun1(){
			return false;
		}
		public boolean fun2(){
			return false;
		}
		public int fun3(){
			return 0;
		}
		public void fun4(){}
	}
	
	static class GBClassCompatImpl extends BaseClassCompatImpl{
		@Override
		public boolean fun1(){
			return ClassCompatGB.func1();
		}
		@Override
		public boolean fun2(){
			return ClassCompatGB.func2();
		}
	}
	
	static class HCClassCompatImpl extends GBClassCompatImpl{
		...
	}
	
	static class ICSClassCompatImpl extends HCClassCompatImpl{
		@Override
		public int fun3(){
			return ClassCompatICS.func3();
		}
		@Override
		public void fun4(){
			ClassCompatICS.func4();
		}
	}
	
	....
	static class KitKatClassCompatImpl extends JBClassCompatImpl{
		...
	}
	
	static final ClassCompatImpl IMPL;
	static{
		final int version = android.os.Build.VERSION.SDK_INT;
		if(version>=19){
			IMPL = new KitKatClassCompatImpl();
		}else if(version >= 17){
			IMPL = new JBClassCompatImpl();
		} ...
	}
	
	public static boolean fun1(){
		return IMPL.fun1();
	}
	public static boolean fun2(){
		return IMPL.fun2()
	}
	public static int fun3(){
		return IMPL.fun3();
	}
	public static void fun4(){
		IMPL.fun4();
	}
	
}
위 구조를 활용해서 작성하면 좋다. 위 코드에서 GBClassCompatImpl 클래스 안에 ClassCompatGB.func1();로 함수 내부를 구현했다. 이 뜻은 진저브레드부터 해당 함수가 지원되었다는 의미이다. 


+ Recent posts