Button setTextAppearance(Context context, int resid) is deprecated
and setTextAppearance(int resid) - only available for API level 23
What should I use instead?
Deprecated means that support will be dropped for it sometimes in the future, but it is still working as expected. On older APIs, there is no alternative, since the new setTextAppearance(int resid) got only released with API level 23.
If you want to be safe for a long time, you can use the following code:
if (Build.VERSION.SDK_INT < 23) {
yourButton.setTextAppearance(context, resid);
} else {
yourButton.setTextAppearance(resid);
}
This code prefers the new version on phones with API level 23 or higher, but uses the old one when the API level 23 one isn't available.
I am going to say the same this as #Daniel Zolnai. But do not make the check Build.VERSION>SDK_INT < 23 in all the places in your code. Put this in one place, so it will be easy for you to remove this in the future or make changes to it. So how to do it? I will do this for the yourButton case.
Never use Button or any other view provided by android just like that. I say this, because in the future you will need to tweak something and hence it's better to have your own MyButton or something of that sort. So create MyButton extends Button.
Inside MyButton, put the below code:
public void setTextAppearance(Context context, int resId) {
if (Build.VERSION.SDK_INT < 23) {
super.setTextAppearance(context, resId);
} else {
super.setTextAppearance(resId);
}
}
This way you can always use setTextAppearance without needing to worry about checking for BUILD versions. If in future, you plan to remove this whole thing, then you have to refactor in just one place. This is a bit of work, but in the long run, this will help you a lot and will reduce some maintanance nightmares.
Related
I want to change the background of my framelayout (which holds all my pages!) by:
FrameLayout fl = (FrameLayout)findViewById(R.id.container);
fl.setBackground(getResources().getDrawable(R.drawable.juraquiz_app_background));
but apparently I cant. Is there a way to do it, so its compatible with APIs lower than 16?
for API's lower that 16 you can use setBackgroundDrawable
Use different methods for different APIs:
final Drawable drw = getResources().getDrawable(R.drawable.juraquiz_app_background);
if(android.os.Build.VERSION.SDK_INT < 16)
{
fl.setBackgroundDrawable(drw);
}
else
{
fl.setBackground(drw);
}
You will need to add an annotation to your method (or to your class, if you prefer) to get rid of Lint warnings:
#SuppressLint("NewApi")
I have a button that I want to set the background of using a png file from internal storage. For android api 16 and up, this works fine:
filePath = getActivity().getFileStreamPath(colorCodes.get(i-1));
temp.setBackground(Drawable.createFromPath(filePath.toString()));
When running on an android tablet with 4.0.4, this part crashes the app with a nosuchmethod error (setBackground). After a little research, I see that setBackground is only available for api 16+. After looking around on SO and a few other places, it looks like I need to use setBackgroundDrawable (deprecated) or setBackgroundResource. I tried this:
filePath = getActivity().getFileStreamPath(colorCodes.get(i-1));
if (android.os.Build.VERSION.SDK_INT < 16) {
temp.setBackgroundDrawable(Drawable.createFromPath(filePath.toString()));
} else {
temp.setBackground(Drawable.createFromPath(filePath.toString()));
}
When logging it out, it shows that setBackgroundDrawable is running and not setBackground, but I get the same nosuchmethod error (setBackground).
The other option is setBackgroundResource, but it accepts an int and not a drawable. Can I convert from drawable to int for this purpose?
What can I do here to set the background of the button to a file in internal storage for APIs < 16?
Thanks.
***EDIT - ok, this is working. just missed a little part elsewhere in the code that had the same problem. However, is using a deprecated method really the only way?
Deprecation is a status applied to a computer software feature,
characteristic, or practice indicating it should be avoided, typically
because of it being superseded. The term is also sometimes used for a
feature, design, or practice that is permitted but no longer
recommended in other areas, such as hardware design or compliance to
building codes. (source link)
Now we can answer your question.
Before API level 16 there is a method named setBackgroundDrawable. After API Level 16 google decided to write a new method setBackground for same purpose and recommend us to use new method. (Reason of this may be found by googling.)
You can use setBackgroundDrawable method for all api levels. There aren't any constraint for this. But using new method setBackground is recommended after API Level 16.
But you can only use setBackground method for devices which is running on API Level 16 or higher. So if you only implement setBackground method in your code, you are going to get MethodNotFoundException for devices which run below API Level 16.
To sum up; it is a best practice(for me it is a must) to use new methods then deprecated ones with supportted api version check such as;
if (android.os.Build.VERSION.SDK_INT < 16) {
temp.setBackgroundDrawable(Drawable.createFromPath(filePath.toString()));
} else {
temp.setBackground(Drawable.createFromPath(filePath.toString()));
}
I am not quite sure whether it is the only way to achieve this but in my opinion it is the correct one. Because the annotation #Deprecated defines the method to be superseded (in most cases) it automatically implies you can (I would even say should) use it to address older versions which are the targeted versions of this method.
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.
I want to set background drawable of a view. There are two methods for this (as far as I see): setBackground and setBackgroundDrawable.
When I use setBackground, it says it has been added in API level 16 but my project's min SDK version is 7. I assume it's not going to work on anything below 16, am I right? But when I use setBackgroundDrawable, it says it's deprecated.
What am I supposed to use?
It's deprecated but it still works so you could just use it. But if you want to be completly correct, just for the completeness of it... You'd do something like following:
int sdk = android.os.Build.VERSION.SDK_INT;
if(sdk < android.os.Build.VERSION_CODES.JELLY_BEAN) {
setBackgroundDrawable();
} else {
setBackground();
}
For this to work you need to set buildTarget api 16 and min build to 7 or something similar.
You can use setBackgroundResource() instead which is in API level 1.
seems that currently there is no difference between the 2 functions, as shown on the source code (credit to this post) :
public void setBackground(Drawable background) {
//noinspection deprecation
setBackgroundDrawable(background);
}
#Deprecated
public void setBackgroundDrawable(Drawable background) { ... }
so it's just a naming decision, similar to the one with fill-parent vs match-parent .
i know this is an old question but i have a similar situation ,and my solution was
button.setBackgroundResource( R.drawable.ic_button );
Drawable d = button.getBackground();
and then you can play with the "Drawable", applying color filters, etc
Use ViewCompat.setBackground(view, background);
you could use setBackgroundResource() instead i.e. relativeLayout.setBackgroundResource(R.drawable.back);
this works for me.
Using Android studio 1.5.1 i got the following warnings:
Call requires API level 16 (current min is 9): android.view.View#setBackground
and the complaints about deprecation
'setBackgroundDrawable(android.graphics.drawable.Drawable)' is deprecated
Using this format, i got rid of both:
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.JELLY_BEAN) {
//noinspection deprecation
layout.setBackgroundDrawable(drawable);
} else {
layout.setBackground(drawable);
}
Now you can use either of those options. And it is going to work in any case.
Your color can be a HEX code, like this:
myView.setBackgroundResource(ContextCompat.getColor(context, Color.parseColor("#FFFFFF")));
A color resource, like this:
myView.setBackgroundResource(ContextCompat.getColor(context,R.color.blue_background));
Or a custom xml resource, like so:
myView.setBackgroundResource(R.drawable.my_custom_background);
Hope it helps!
This works for me: View view is your editText, spinner...etc. And int drawable is your drawable route example (R.drawable.yourDrawable)
public void verifyDrawable (View view, int drawable){
int sdk = Build.VERSION.SDK_INT;
if(sdk < Build.VERSION_CODES.JELLY_BEAN) {
view.setBackgroundDrawable(
ContextCompat.getDrawable(getContext(),drawable));
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
view.setBackground(getResources().getDrawable(drawable));
}
}
Use setBackgroundResource(R.drawable.xml/png)
I also had this problem, but I made a workaround using a ImageView.
Try using a RelativeLayout and add a ImageView inside it (width and height: fill_parent, scaleType: center).
Also make sure the imageview is the first element inside the RelativeLayout, so it will act as background.
You can also do this:
try {
myView.getClass().getMethod(android.os.Build.VERSION.SDK_INT >= 16 ? "setBackground" : "setBackgroundDrawable", Drawable.class).invoke(myView, myBackgroundDrawable);
} catch (Exception ex) {
// do nothing
}
EDIT: Just as pointed out by #BlazejCzapp it is preferable to avoid using reflection if you can manage to solve the problem without it. I had a use case where I was unable to solve without reflection but that is not case above. For more information please take a look at http://docs.oracle.com/javase/tutorial/reflect/index.html
On my settings screen I have a date picker widget. In the designer in Eclipse, it shows as I want (3 spinners for D-M-Y) but when I test on my device, I get a rather odd view with a side spinner on the left and a calendar on the right. Never seen this before(!) but doing some research I think I'm seeing the "CalendarView".
I found that I should be able to set a "calendarViewShown" property to false- but my XML throws an error with this. I found another question on here that suggested the API level was to blame (my minSDKLevel is 7, but I'm targetting 11 so I can get the action bar button rather than the oldskool menu).
So I thought I'd try setting it in code:
int currentapiVersion = android.os.Build.VERSION.SDK_INT;
if (currentapiVersion >= 11)
minDateSelector.setCalendarViewShown = false;
But again, this fails- setCalendarViewShown isn't found. But the docs here say it should exist.
Any ideas?!
If you are targeting a later version of the API, you can use the following XML (no need to write Java code) in your <DatePicker>:
android:calendarViewShown="false"
The method in DatePicker
public void setCalendarViewShown (boolean shown)
exists starting with API 11. If you minSdkLevel = 7 the compiler does not recognize this as a valid method - the method does not exist on android 2.3 or 2.2. The best way is to solve this is using reflection. Something like this should work properly:
int currentapiVersion = android.os.Build.VERSION.SDK_INT;
if (currentapiVersion >= 11) {
try {
Method m = minDateSelector.getClass().getMethod("setCalendarViewShown", boolean.class);
m.invoke(minDateSelector, false);
}
catch (Exception e) {} // eat exception in our case
}
I made it work with the following XML configuration:
android:datePickerMode="spinner"
android:calendarViewShown="false"
Only the following configuration didn't work for me:
android:calendarViewShown="false"
In those cases I use
import android.os.Build;
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
public void someThing() {
[...]
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
minDateSelector.setCalendarViewShown(false);
}
}
I think the readability is better than using reflection and the style is better than catch and ignore exceptions. Of course the reflection thing is also working.
I had the same problem as you, I couldn't make the change appear via XML.
You are on the right track, try changing your last line to:
minDateSelector.setCalendarViewShown(false);