When it comes to developing applications for Android, what is the difference between Min and Target SDK version? Eclipse won\'t let me create a new project unless Min and Ta
A concept can be better delivered with examples, always. I had trouble in comprehending these concept until I dig into Android framework source code, and do some experiments, even after reading all documents in Android developer sites & related stackoverflow threads. I'm gonna share two examples that helped me a lot to fully understand these concepts.
A DatePickerDialog will look different based on level that you put in AndroidManifest.xml file's targetSDKversion(<uses-sdk android:targetSdkVersion="INTEGER_VALUE"/>
). If you set the value 10 or lower, your DatePickerDialog will look like left. On the other hand, if you set the value 11 or higher, a DatePickerDialog will look like right, with the very same code.
The code that I used to create this sample is super-simple. MainActivity.java
looks :
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void onClickButton(View v) {
DatePickerDialog d = new DatePickerDialog(this, null, 2014, 5, 4);
d.show();
}
}
And activity_main.xml
looks :
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="onClickButton"
android:text="Button" />
</RelativeLayout>
That's it. That's really every code that I need to test this.
And this change in look is crystal clear when you see the Android framework source code. It goes like :
public DatePickerDialog(Context context,
OnDateSetListener callBack,
int year,
int monthOfYear,
int dayOfMonth,
boolean yearOptional) {
this(context, context.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.HONEYCOMB
? com.android.internal.R.style.Theme_Holo_Light_Dialog_Alert
: com.android.internal.R.style.Theme_Dialog_Alert,
callBack, year, monthOfYear, dayOfMonth, yearOptional);
}
As you can see, the framework gets current targetSDKversion and set different theme. This kind of code snippet(getApplicationInfo().targetSdkVersion >= SOME_VERSION
) can be found here and there in Android framework.
Another example is about WebView class. Webview class's public methods should be called on main thread, and if not, runtime system throws a RuntimeException
, when you set targetSDKversion 18 or higher. This behavior can be clearly delivered with its source code. It's just written like that.
sEnforceThreadChecking = context.getApplicationInfo().targetSdkVersion >=
Build.VERSION_CODES.JELLY_BEAN_MR2;
if (sEnforceThreadChecking) {
throw new RuntimeException(throwable);
}
The Android doc says, "As Android evolves with each new version, some behaviors and even appearances might change." So, we've looked behavior and appearance change, and how that change is accomplished.
In summary, the Android doc says "This attribute(targetSdkVersion) informs the system that you have tested against the target version and the system should not enable any compatibility behaviors to maintain your app's forward-compatibility with the target version.". This is really clear with WebView case. It was OK until JELLY_BEAN_MR2 released to call WebView class's public method on not-main thread. It is nonsense if Android framework throws a RuntimeException on JELLY_BEAN_MR2 devices. It just should not enable newly introduced behaviors for its interest, which cause fatal result. So, what we have to do is to check whether everything is OK on certain targetSDKversions. We get benefit like appearance enhancement with setting higher targetSDKversion, but it comes with responsibility.
EDIT : disclaimer. The DatePickerDialog constructor that set different themes based on current targetSDKversion(that I showed above) actually has been changed in later commit. Nevertheless I used that example, because logic has not been changed, and those code snippet clearly shows targetSDKversion concept.
If you get some compile errors for example:
<uses-sdk
android:minSdkVersion="10"
android:targetSdkVersion="15" />
.
private void methodThatRequiresAPI11() {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Config.ARGB_8888; // API Level 1
options.inSampleSize = 8; // API Level 1
options.inBitmap = bitmap; // **API Level 11**
//...
}
You get compile error:
Field requires API level 11 (current min is 10): android.graphics.BitmapFactory$Options#inBitmap
Since version 17 of Android Development Tools (ADT) there is one new and very useful annotation @TargetApi
that can fix this very easily. Add it before the method that is enclosing the problematic declaration:
@TargetApi
private void methodThatRequiresAPI11() {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Config.ARGB_8888; // API Level 1
options.inSampleSize = 8; // API Level 1
// This will avoid exception NoSuchFieldError (or NoSuchMethodError) at runtime.
if (Integer.valueOf(android.os.Build.VERSION.SDK) >= android.os.Build.VERSION_CODES.HONEYCOMB) {
options.inBitmap = bitmap; // **API Level 11**
//...
}
}
No compile errors now and it will run !
EDIT: This will result in runtime error on API level lower than 11. On 11 or higher it will run without problems. So you must be sure you call this method on an execution path guarded by version check. TargetApi just allows you to compile it but you run it on your own risk.
If you are making apps that require dangerous permissions and set targetSDK to 23 or above you should be careful. If you do not check permissions on runtime you will get a SecurityException and if you are using code inside a try block, for example open camera, it can be hard to detect error if you do not check logcat.