I have a FileObserver(File dir) that works perfectly in Android11, but crashes badly in Android10 with the following LogCat even when I try to access the own APP private folder (external sdcard):
E/AndroidRuntime(24651): java.lang.NoSuchMethodError: No direct method <init>(Ljava/io/File;)V
in class Landroid/os/FileObserver; or its super classes (declaration of
'android.os.FileObserver' appears in /system/framework/framework.jar!classes2.dex)
E/AndroidRuntime(24651): at com.floritfoto.apps.xvf.FileChooser$1.<init>(FileChooser.java:570)
E/AndroidRuntime(24651): at com.floritfoto.apps.xvf.FileChooser.watchdir(FileChooser.java:570)
E/AndroidRuntime(24651): at com.floritfoto.apps.xvf.FileChooser.access$500(FileChooser.java:53)
My code is pretty simple:
private void watchdir(final File dir) {
if (observer != null) {
observer.stopWatching();
observer = null;
}
observer = new FileObserver(dir) { // <===== CRASHES HERE
#Override
public void onEvent(int event, String path) {
event &= FileObserver.ALL_EVENTS;
....
}
};
observer.startWatching();
}
Changing observer = new FileObserver(dir) with observer = new FileObserver(dir.getAbsolutePath()) works fine, but FileObserver(String path) is deprecated.
My app has compileSdkVersion 31, targetSdkVersion 31, and minSdkVersion 14.
At least to some extent this error has been reported before, but no solution has been provided yet.
EDIT: The crash is in Android 9, not 10.
FileObserver(File) is new to API Level 29. Your minSdkVersion is 14. Your code will crash with this error on API Level 28 and lower. You should be getting Lint warnings and the like warning you that FileObserver(File) is newer than your minSdkVersion.
Your options are:
Use FileObserver(String) on all API levels, despite the deprecation warning.
Use FileObserver(String) on API Levels 14-28 and use FileObserver(File) on API Level 29+, using Build.VERSION.SDK_INT to determine the API level of the device your app is running on.
Set your minSdkVersion to 29.
Only use FileObserver on API Level 29+, and skip whatever features depend on it on older devices.
Related
I am working on a project with minSdkVersion set to 25 (aka Android 7.1).
Since this version is quite high, there are a lot of methods I can use without worrying about backward compatibility.
For example, retrieving a drawable, from a Fragment, should be as simple as:
context?.getDrawable(R.drawable.my_drawable)
In the source code, what it does is:
return getResources().getDrawable(id, getTheme());
As far as I am concerned, such a method was introduced in API 21 (Android 5.0).
However, I get the following warning:
Looking at the source code of ContextCompat.getDrawable(...):
if (Build.VERSION.SDK_INT >= 21) {
return context.getDrawable(id);
} else if (Build.VERSION.SDK_INT >= 16) {
return context.getResources().getDrawable(id);
} else { ... }
Since the min SDK is set to 25, the first if will always be called, which then the same code I have written. So why the warning?
I could suppress it with the #SuppressLint("UseCompatLoadingForDrawables") but it kinds of defeat the purpose... or I could follow it...
Is this normal? Should I really use ContextCompat and its affiliates or is there a setting somewhere to remove such a false warning?
PS: the project is also using Android X.
Ran into the same issue. I would say it is a false positive when you have a minSdk >= 21. Since as you say you will always enter the if branch which calls getDrawable.
So suppressing/ignoring it is the way to go until someone can make the lint rule smart enough to detect that you are on minSdkVersion higher than 21. You can ignore it globally by doing this in your build.gradle:
android {
...
lintOptions {
ignore("UseCompatLoadingForDrawables")
}
}
Interestingly context.getColor(R.color.something) does not give a similar warning even though it has similar code in ContextCompat.getColor.
According google suggestion i am using getLongVersionCode to get version code like this:
private long getCurrentCode() {
try {
return context.getPackageManager()
.getPackageInfo(context.getPackageName(), 0).getLongVersionCode();
} catch (Exception e) {
e.printStackTrace();
}
return -1;
}
but when i run my app, my app force closed and i got this error:
Process: com.xxxxx.debug, PID: 25754
java.lang.NoSuchMethodError: No virtual method getLongVersionCode()J in class Landroid/content/pm/PackageInfo; or its super classes (declaration of 'android.content.pm.PackageInfo' appears in /system/framework/framework.jar)
at com.xxxxx.common.ApplicationUpdateTask.getCurrentCode(ApplicationUpdateTask.java:329)
at com.xxxxx.common.ApplicationUpdateTask.<init>(ApplicationUpdateTask.java:84)
So i decided to use:
String versionName = BuildConfig.VERSION_NAME;
but now this commend return -1 !!!!!
This is my gradle config:
compileSdkVersion 28
buildToolsVersion '28.0.3'
defaultConfig {
minSdkVersion 15
targetSdkVersion 28
versionCode 66
versionName '2.0.66'
applicationId 'com.xxxxxx.yyyyy'
multiDexEnabled true
}
I recommend you to use PackageInfoCompat:
PackageInfoCompat.getLongVersionCode();
It automatically checks the sdk version greater than 28 and returns appropriately versionCode or LongVersionCode. It is included in androidx.
The method long getLongVersionCode() was added to Android in version 28; see javadoc
It is clearly present in the APIs you are compiling against, otherwise you would get a compilation error.
But the exception says that it is not present at runtime, so you must have been running on an older platform.
I don't know what you mean when you say that you used this:
String versionName = BuildConfig.VERSION_NAME;
The version name and code are different things. Maybe you used BuildConfig.VERSION_CODE?
And I don't know what you mean by this:
but now this commend return -1 !!!!!
My guess is that there is something wrong with way you are using the version name or code attributes. But that's just a guess. You haven't shown us the code.
The other thing to note is that prior to API version 28, you could use the PackageInfo.versionCode attribute (javadoc). This was deprecated in API version 28. So it should be possible to use reflection to call the getLongVersionCode() method if available, and fall back to using reflection to access the versionCode attribute. (Or test the value of Build.VERSION.SDK_INT at runtime to find out what API version the platform supports.)
Or you could just set the minimum supported Android version for your app to 28.
Just a note for those looking here. Although this says that it was added in 28, I can say for sure it does not work in Android 8.1. Same runtime error. Changing my code to check for Android.os.Build.VERSION_SDK_INT >= Build.VERSION_CODES.P before trying to use getLongVersionCode() avoided the error.
I'm working in API 22, but I want to compile my project in Android M 6.0, I have this code:
Declared at the top:
private static final String[] REQUIRED_PERMISSIONS = new String[]{"READ_EXTERNAL_STORAGE"};
private static final int REQUEST_PERMISSIONS = (Integer) null;
And on my onCreate():
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
LinkedList<String> missingPermissions = new LinkedList<>();
for(String p : REQUIRED_PERMISSIONS){
if(checkCallingOrSelfPermission(p) != PackageManager.PERMISSION_GRANTED){
missingPermissions.add(p);
}
}
if(!missingPermissions.isEmpty()){
String[] mpArray = new String[missingPermissions.size()];
missingPermissions.toArray(mpArray);
requestPermissions(mpArray, REQUEST_PERMISSIONS);
}
}
I was inspired here for checking my problem
and in Eclipse is giving me an error on Build.VERSION_CODES.M(M not found), and then, the callback method requestPermissions(mpArray, REQUEST_PERMISSIONS) isn't found too, any suggestion?
If I'm working on API 22, and I'm compiling with Android 6.0 M. How I can solve the issue for the dangerous permissions like READ_EXTERNAL_STORAGE correctly on API 22?
As per the documentation, Build.VERSION_CODES.M and requestPermissions() were added in API level 23.
Since you are compiling with API level 22, those simply do not exist.
To access APIs introduced in API level 23, you need to compile with API 23. You cannot access these APIs if you continue to compile with API 22.
Note that simply compiling with API 23 will not affect the way your application behaves on any devices, it simply opens up the newer APIs for your use on devices running at least API 23.
if I'm working on API 22, and I'm compiling with Android 6.0 M, how i can do for solve the issue for the dangerous permissions like READ_EXTERNAL_STORAGE correctly on API 22?
Devices running API 22 will continue to use the old install-time model for permissions. Nothing has changed for devices running API 22 and below. Only devices running API 23 use the new runtime permissions model.
I use D3SView library in my app in payment process. It uses #javascriptinterface in one of functions. Can I use it on Android >= 2.3 ? link to required class.
code:
addJavascriptInterface(new D3SJSInterface(), JavaScriptNS);
...
class D3SJSInterface {
D3SJSInterface(){}
#android.webkit.JavascriptInterface
public void processHTML(final String paramString) {
completeAuthorization(paramString);
}
}
How to make this code allowable for >= 2.3 android version?
Can I use it on Android >= 2.3 ?
Yes, though your compileSdkVersion (a.k.a., "build target" in Eclipse) will need to be API Level 17 or higher. On the older devices, the annotation is ignored.
I have a project which is compatible with Android versions from 10(GINGERBREAD_MR1) to 17(JELLY_BEAN_MR1).
So, I would like to use setBackgroundDrawable for versions lower to 16 and setBackground from version 16 or upper.
I've tried this:
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
subMessageFromToLinearLayout.setBackgroundDrawable(null);
} else {
subMessageFromToLinearLayout.setBackground(null);
}
But, Eclipse gives me:
A warning for subMessageFromToLinearLayout.setBackgroundDrawable(null);:
"The method setBackgroundDrawable(Drawable) from the type View is deprecated"
And an error for subMessageFromToLinearLayout.setBackground(null);:
"Call requires API level 16 (current min is 10): android.widget.LinearLayout#setBackground"
How can I fix this errors in order I can use both lines depending of the running Android version?
Thanks in advance.
In general the most robust way makes use of class lazy loading:
static boolean isSDK17()
{
return android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1;
}
if (isSDK17())
xyMode_SDK17.setXyMode(context, mode);
else
xyMode_SDK8.setXyMode(context, mode);
#TargetApi(17)
public class xyMode_SDK17
{
static void setXyMode(Context context, boolean mode)
{...}
}
public class xyMode_SDK8
{
#SuppressWarnings("deprecation")
static void setXyMode(Context context, boolean mode)
{...}
}
Have you seen
ActionBarSherlock gives tons of "Call requires API level 11 (current min is 7)" errors
Android - set layout background programmatically
You can mark it with #TargetApi(16) and #SuppressWarnings("deprecated").
If the error still there, try cleaning the project or restart eclipse.
"ah I know of the .setBackgroundDrawable(Drawable) method but to me the IDE had the same error with api 16 requirement. I am using Eclipse and it seemed to be a bug after reopening the ide and cleaning the code a bit it worked. Than you very much and sorry for trouble".