I downloaded the ActionBarSherlock version 4.1.0.0, and added a the Android Project library into Eclipse 4.2 on my Win7 java 1.6 update 24 machine. I used an Eclipse Project Build Target of Android 4.1 in Project | Properties | Project Build Target. I want to incorporate the ActionBar functionality into an existing app that has minSdkVersion="7". I noted the code from the ActionBarSherlock library appears to have some deprecated methods, and an error:
Example 1: ActionBarContainer.java, ActionBarContextView.java, ScrollingTabContainerView.java - uses setBackgroundDrawable - The method setBackgroundDrawable(Drawable) from the type View is deprecated
public ActionBarContainer(Context context, AttributeSet attrs) {
super(context, attrs);
setBackgroundDrawable(null);
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.SherlockActionBar);
mBackground = a.getDrawable(R.styleable.SherlockActionBar_background);
mStackedBackground = a.getDrawable(
R.styleable.SherlockActionBar_backgroundStacked);
if (getId() == R.id.abs__split_action_bar) {
mIsSplit = true;
mSplitBackground = a.getDrawable(
R.styleable.SherlockActionBar_backgroundSplit);
}
a.recycle();
setWillNotDraw(mIsSplit ? mSplitBackground == null :
mBackground == null && mStackedBackground == null);
}
Quick fix shows as Add #SupressWarnings 'deprecation' for ActionBarContainer
Example 2:
IcsProgressBar.java uses animationResolution which shows as deprecated, same quick fix as above
private static final int[] ProgressBar = new int[] {
...
android.R.attr.animationResolution
Also, I have an error in ActivityChooserView.java:
private static class SetActivated {
public static void invoke(View view, boolean activated) {
view.setActivated(activated);
}
}
Error is on SetActivated - Call requires API 11 (current min is 7). This makes sense based on the manifest:
<uses-sdk android:minSdkVersion="7" android:targetSdkVersion="15"/>
Shouldn't API 7 be fine, since Action Bar Sherlock should work at at Andriod 2.x? Have others experienced this, and if so, what is the recommended action? Supress/ignore the deprecation? What about the error on SetActivated? I reviewed the readme and did some net searches but did not come up with anything on this. Thanks for any suggestions.
Thanks!
It is just fine. The code is 2.x compatible and even some methods are deprecated as of 4.x, they are still there. It also do not mean on 4.x these deprecated methods will be used. The source is 2.x-4.x so there's no other way (not to mention reflection, but that'd hurt performance, and is for now not necessary). So it is safe to just ignore this. It would probably be better to turn depreciation off for certain files but it is not there. So do not worry.
This is doesn't really answer the question but I ran into the same issue when I had to have a minSdkVersion 9 and I wanted to have ActionBarSherlock but I was getting the same error of the actionBar requires minSdkVersion 11.
Apparently in ADT 21.1 you make a values-v11/styles.xml and put the actionBar in there.
https://code.google.com/p/android/issues/detail?id=48283
Related
I know there are several similar questions regarding this has been asked here, however none of the solutions worked for me.
I have just transferred my application from Ecilpse(juno) to Android Studio 1.5.1; and from API 19 to API 23(compileSdkVersion).
Currently I encountered this error whereby "getResources().getColor(R.color.my_color)" is depreciated and cannot be used.
After searching online, I tried to use "ContextCompat.getColor(context, R.color.my_color)" instead. The error lies at the "getColor" part as it says that it cannot be resolved:
The method "ContextCompat" however allow me to use "getDrawable", "getExternalCacheDirs", "getExternalFilesDirs" and "getObbDirs"; just except for "getColor"
I have also ensure that I have these 2 in my app build.gradle (under dependencies{}):
compile 'com.android.support:appcompat-v7:23.1.1'
compile 'com.android.support:support-v4:23.1.1'
Below are my imports for this class (DetailsActivity):
Additionally, I have also tried using "ResourcesCompat" other than "ContextCompat"; and it still did not work out for me.
I am still a beginner at Android Development, working on a school project.
Can anyone kindly provide some suggestions as of what I am doing wrong and point me towards the right direction? Thanks a lot in advance!
You can use this method.
This is the ContextCompat Developer Link from the Support Library:
public static final int getColor(Context context, int id) {
final int version = Build.VERSION.SDK_INT;
if (version >= 23) {
return ContextCompat.getColor(context, id);
} else {
return context.getResources().getColor(id);
}
}
You don't have to use ContextCompat there if you are compiling with an API level greater than 24 as this is only a compatibility feature for early versions. You can also still use Context.getColor() But notice the method signature! If you just want a color in the default theme you only have to provide the int value of its reference: http://developer.android.com/reference/android/content/Context.html#getColor(int)
You are currently trying to access getColor() with two parameters (Color and Theme) which cannot work there as there is no method who supports these parameters. If you remove the 2nd parameter your current solution will work.
But it would be more convenient to use Context or Resources directly and drop the v4 Appcompat reference if you don't need it.
Before to use this method, fist of all add the Dependencies in build.gradle script. Which is as follows:
dependencies {
// other stuff here
compile 'com.android.support:support-v4:23.0.0'
}
As part of an app I'm working on, I'm attempting to obtain a reference to the ActionBar's container view. I used the answer from this question, and it's working nicely for me as long as the Android device in question is running API level 11 or up. However, the app needs to work as far back as API level 9 (the target API level is 19), and Gingerbread devices are giving me problems. I was originally using Sherlock for the project, but recently made the switch over to the v7 compat library instead. I can see and interact with the action bar in normal ways on Gingerbread devices (buttons work, etc.), but it fails when I attempt to get the container. The code I'm using is this (note - it's running inside a subclass of ActionBarActivity):
private FrameLayout getActionBarContainer() {
FrameLayout result = null;
int resId = getResources().getIdentifier("action_bar_container", "id", "android");
try {
result = (FrameLayout)getWindow().getDecorView().findViewById(resId);
}
catch (Exception e) {
// If we get an exception, just eat it
}
return result;
}
To answer a few questions before they get asked:
resId resolves to a proper ID value on v11 devices and up, but resolves to 0 on pre-v11 devices.
The code that uses this has proper checks to handle a null result, which is why I'm just eating the exceptions. The try/catch block is mostly just there in case, by some freak occurrence, a ClassCastException manages to get thrown (which it never should, since the container is a subclass of FrameLayout).
I've checked and re-checked my imports; all of my ActionBar references (and all things related, like the ActionBarActivity superclass I'm extending) are the v7 compat library versions, not the standard library versions.
The action_bar_container ID should exist within the v7 compat library, if this is any indication.
I'm about out of ideas at this point. Is there something simple I'm missing? Any suggestions will be appreciated, and if you need more context/clarification, let me know.
I think your error is on the last parameter of
int resId = getResources().getIdentifier("action_bar_container", "id", "android");
For api level <11 the package should be your application's package and not the plataform's package "android"
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.
Running the following (note: target > 3.0)
ActionBar actionBar = getActionBar();
on Android with version < 3.0 (SDK 11) results in a NoSuchMethodError.
There are several ways to get around this, including reflection and class lazy loading. However, the following seems to work across all the devices I've tested (2.3.6, 3.0, 3.1, 4.0):
boolean hasActionBar = android.os.Build.VERSION.SDK_INT >= 11;
if (hasActionBar) {
ActionBar actionBar = getActionBar();
} else {
// create custom actionbar
}
Note the SDK_INT parameter is static final, which appears to be why this works.
Is this a valid way to deal with compatibility?
I believe so, as long as everything is setup correctly.
From Reto Meier's blog:
http://blog.radioactiveyak.com/2011/02/strategies-for-honeycomb-and-backwards.html
It looks like this works due to the JIT compiler. This code fails on SDK < 2.1, which supports this theory. Regardless, this probably isn't a reliable way to avoid reflection.
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