I'm developing an application for APIs from v10 to v17.
My activity implements OnDragListener which is available only from API v14.
public class MyActivity extends Activity implements View.OnDragListener {
....
}
So, when application is installed on device with API v10 it fails to load activity with java.lang.NoClassDefFoundError.
I understand that this won't work on API v10, that's OK. I'm handling this inside the activity.
I just want to know What is the practice to handle different API versions when it comes to features like this?
First of all you can check API levels and depending on that to execute or not your code. For example :
if(Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB){
// don't use it.
} else {
// use the new API :
// myView.setOnDragListener(...);
}
You should not implement interfaces from new API's in Activity if you want to support old android versions too. Instead of that use the approach above.
In your case you should not declare the activity to implement View.OnDragListener. Just do the logic in another class and instantiate it only when you need it (I suppose you add the listener only for API >= 14).
Related
I get this error on crashlytics panel:
Fatal Exception: java.lang.NoSuchMethodError
android.support.v4.app.FragmentActivity.isChangingConfigurations
com.hannesdorfmann.mosby.mvp.MvpFragment.shouldInstanceBeRetained (MvpFragment.java:91)
com.hannesdorfmann.mosby.mvp.delegate.MvpInternalDelegate.detachView (MvpInternalDelegate.java:70)
com.hannesdorfmann.mosby.mvp.delegate.FragmentMvpDelegateImpl.onDestroyView (FragmentMvpDelegateImpl.java:73)
com.hannesdorfmann.mosby.mvp.MvpFragment.onDestroyView (MvpFragment.java:106)
com.hannesdorfmann.mosby.mvp.MvpFragment.shouldInstanceBeRetained (MvpFragment.java:91)
I override manifest for library to use it with api level 10 and I already test it on android 2.3.3 and it was working ok! but now I see this crash on crashlytics. Hi I can fix this for my version? is crash related to api 10? because the method is for support v4 library so I can't understand why this occurred.
yes the method isChangingConfigurations() has been introduced with API 11:
https://developer.android.com/reference/android/app/Activity.html#isChangingConfigurations()
as part of theandroid.app.Activity plattform class (and not as part android.support.v4.app.FragmentActivity, but FragmentActivity extends Activity).
Hence, this won't work on API < 11.
You could implement isChangingConfigurations() in your Activity and either call
super.isChangingConfigurations() if API >=11 or implement your own thing if (API < 11). You may want to take a look at Activities source code, but I'm not sure how this could be back ported. https://github.com/android/platform_frameworks_base/blob/master/core/java/android/app/Activity.java#L5152
You could try to just return false if API < 11 . That would mean that the View's state (and Presenter) will not survive screen orientation changes. DISCLAIMER: That might also cause some other unwanted side effects I'm not aware of right now and could break with any future release of Mosby or support library.
Previously, I'm using SherlockActionBar library. The following code will work, across Android 2.3 till Android 5.
this.searchMenuItem.collapseActionView();
However, after migrating to AppCompat, we need to migrate to the following code
MenuItemCompat.collapseActionView(JStockFragmentActivity.this.searchMenuItem);
When I look at the documentation http://developer.android.com/guide/topics/ui/actionbar.html#ActionView, it states that
On API level 11 or higher
Get the action view by calling getActionView() on the corresponding
MenuItem:
menu.findItem(R.id.action_search).getActionView()
I was wondering, is it necessary that I need to write my migrated code in the following way?
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
this.searchMenuItem.collapseActionView();
} else {
MenuItemCompat.collapseActionView(this.searchMenuItem);
}
I'm working on an app that is targeted for version 2.3 so that it will run on my sister's phone. However, I can run 4.0 on my phone. I want to add some swipe animations and such but I don't run the animations to run on her phone.
Is this even possible?
Yes, simply put the API specific code in a if/else block, so it is only called when the system supports it:
Like this:
if (currentapiVersion < android.os.Build.VERSION_CODES.JELLY_BEAN) {
//do things that are only supported on JellyBean
} else {
//do the other stuff
}
You can use a ViewPager and FragmentPagerAdapter to provide swipe functionality among various Fragments. All of which are available in the support library.
ViewPager(Note, don't do anything with the ActionBar, as they are not yet in the support library):
http://developer.android.com/reference/android/support/v4/view/ViewPager.html
FragmentPagerAdapter(pretty much the example code you will need):
http://developer.android.com/reference/android/support/v13/app/FragmentPagerAdapter.html
Fragment:
http://developer.android.com/reference/android/support/v4/app/Fragment.html
Is there any kind of conditional compiling for Android?
I had to make my project for Android 3 (API 11) just because ExifInterface has almost no useful attributes in Android 2.3 (API 10), despite the fact that it appeared in API 5 (!!??). I don't want to restrict my app to ICS users.
Thanks!
You can check dynamically the current API version of the device and do different stuff depending on that:
if(Build.VERSION.SDK_INT < 14) {
// Crappy stuff for old devices
}
else {
// Do awesome stuff on ICS
}
But be careful that if you need to instantiate classes that are not available for all APIs then you should do it in a runnable or in a separate wrapper class, e.g:
if(Build.VERSION.SDK_INT < 14) {
// Crappy stuff for old devices
}
else {
// Do awesome stuff on ICS
new Runnable() {
new AmazingClassAvailableOnICS();
(...)
}.run();
}
import android.annotation.TargetApi;
and then use annotations:
#TargetApi(11)
public void methodUsesAPI11()
{
...
Using this trick does a very simple thing: it allows compiling some code which contains API level 11 calls (classes, methods, etc) and still set android:minSdkVersion="8" in the manifest. Nothing more, nothing else.
The rest is up to you. You must check platform version before you call methodUsesAPI11() or you handle exceptions in order to prevent app crash and perform other action on older platforms.
Checking Build.VERSION.SDK_INT or using annotations should suffice, however, this link I'd bookmarked might be relevant to your case:
http://android-developers.blogspot.com/2010/07/how-to-have-your-cupcake-and-eat-it-too.html?m=1
You can use what they describe there to have classes that may not be compatible, but will never be loaded. It's not conditional compilation, but it may be what you need, however, it is a bit more complex.
So we've seen the preview sdk and the neat new stuff like ActionBar and Fragments. Making a lot of method calls will be unavoidable to make use of these, so what strategies are there for maintaining 1 version of the app, which will let me use all the snazzy new stuff but also work on devices running 2.3 or below? My app targets 1.5 - 2.3 at the moment.
The same fragment APIs are now available as a static library for use with older versions of Android; it's compatible right back to Android 1.6.
There are a few tricks you can use to see if the various new APIs are available to your app. Generally speaking, you'll probably want to create two alternative sets of Activities, one that uses the fancy new APIs (ActionBar, Animators, etc.) -- and another set that don't.
The following code shows how you can use reflection and exception catching to determine the availability of the Fragment APIs, and version checking to confirm if the other Honeycomb APIs are available.
private static boolean shinyNewAPIsSupported = android.os.Build.VERSION.SDK_INT > 10;
private static boolean fragmentsSupported = false;
private static void checkFragmentsSupported() throws NoClassDefFoundError {
fragmentsSupported = android.app.Fragment.class != null;
}
static {
try {
checkFragmentsSupported();
} catch (NoClassDefFoundError e) {
fragmentsSupported = false;
}
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent startActivityIntent = null;
if (!shinyNewAPIsSupported)
startActivityIntent = new Intent(this, MainNonActionBarActivity.class);
else
startActivityIntent = new Intent(this, MainActionActivity.class);
startActivity(startActivityIntent);
finish();
}
Generally speaking you can use the same layout definitions. Where Fragments are available you'll inflate each layout within a different Fragment, where they aren't you'll probably want to use <include> tags to embed several of them into a more complex Activity layout.
A more detailed work through of how to write the code to support backwards compatibility on Honeycomb can be found here: http://blog.radioactiveyak.com/2011/02/strategies-for-honeycomb-and-backwards.html
Conveniently, Google's Dianne Hackborne has posted a blog entry covering this exact topic. Google say they'll be providing static libraries so older versions of Android will also be able to use fragments.
You might find Reto Meier's article on backwards-compatibility useful, specifically the section headed "Dealing with missing classes".
I've yet to look at the Honeycomb SDK myself but I, like you, am hoping it's pretty easy and hassle-free to make use the new features without jeopardising compatibility with older devices.
Well google just announced honeycomb will be tablet only: http://www.pcmag.com/article2/0,2817,2379271,00.asp
So if your device is meant for mobile only this may not even be an issue.
Official Android sample that will help you achieve ActionBar from 1.6 to 4.x