How is #NonNull or #Nullable function? - android

like :
public TestBean check(#NonNull TestBean abc) {
System.out.println();
return abc;
}
#NonNull api doc say:
Denotes that a parameter, field or method return value can never be null
I have a question: if abc is null, why it executes this method?

These annotations may used by code analysis tools (and IDEs) and documentation. They aren't enforced by the runtime.
An example is given here in the android support kit documentation: http://tools.android.com/tech-docs/support-annotations
The new Android Studio supports these annotations, screenshot in the link.
Java 8 introduced similar annotations and this documentation goes into a little more detail about how these annotations work with tools and IDEs to help developers detect problems earlier. In plain Java, you can use the Bean Validation API to enforce null checking declaratively at runtime, I don't know if there's any similar capability in Android.

They just make it more easier to check underlying NULL point exception in your code time.

Related

How to cast String to Input<String> - Kotlin

I am using GraphQL Apollo client call and it generates files. So as a result I got this
val storeNumber: Input<String> = Input.absent()
Instead of regular string. So how can I cast parameter to Input<String> to avoid this error
I don't use Apollo, but found the source code of Input. It depends what version of this library you're using. If you're using an older version, to wrap (not "cast"!) a String as an Input, use Input.Present:
storeNumber = Input.Present(storeNumber)
Note, the term "cast" means promising the compiler that your existing instance is also an instance of something else. That is very different from converting or wrapping an instance of something.
If you're using a newer version of the library, you shouldn't be using the Input class at all. It's been replaced with the Optional class, in which case you would use Optional.Present(storeNumber).
If you want to figure this kind of thing out on your own in the future, try Ctrl+Clicking the function you're working with to jump to its source code. In turn you can Ctrl+Click the types of the function parameters. That would take you to the source code of Input so you could see how to create an instance.

Is it safe to use #SuppressLint("RestrictedApi") with AndroidX libraries?

I would like to now whether it is safe or not to use #SuppressLint("RestrictedApi") annotation. I am pretty sure that the answer is NO, so I want to ask why as well.
I guess that the development team wanted to hide such restricted code from the API users. Probably due to changes in the future or because the code is intended to work as internal functionality
Example code with androidx.preference:preference:1.1.1:
public abstract class CustomAdapterPreferenceFragment extends PreferenceFragmentCompat {
#Override
protected PreferenceGroupAdapter onCreateAdapter(PreferenceScreen preferenceScreen) {
// this annotation removes warning that says PreferenceGroupAdapter can only be called from package names that start with androidx.preference
#SuppressLint("RestrictedApi")
final PreferenceGroupAdapter adapter = new PreferenceGroupAdapter(preferenceScreen) {
#Override
public void onBindViewHolder(PreferenceViewHolder holder, int position) {
super.onBindViewHolder(holder, position);
}
};
return adapter;
}
Link to annotation that restricts code usage in this example: AOSP AndroidX
You're correct: this is not safe. Symbols marked with #RestrictTo are not considered public API, and may change behavior or signature arbitrarily between releases. The only guarantee is that they won't break behavior that other AndroidX libraries rely on internally, and what that behavior is is not defined.
This is especially true for symbols that restrict to a single library or a library group that requires all libraries within the group to be pinned to the same version, as there is no need to maintain compatibility with different versions of other AndroidX libraries.
I guess that the development team wanted to hide such restricted code from the API users. Probably due to changes in the future or because the code is intended to work as internal functionality
This is exactly correct. There is sometimes a need to expose functionality internally that would not make sense as public API, though we try to avoid it in general, because it makes it harder to copy a part of the code out and customize your own version of it. This is especially true with Java code, which doesn't have Kotlin's internal modifier to expose classes to the entire library (package-private doesn't really cut it).

LifecycleObserver produce exception with methods that use newer APIs

My ViewModel class implements LifecycleObserver.
When I call fragment.lifecycle.addObserver(this) it produces exception.
Caused by: java.lang.IllegalArgumentException: The observer class has some methods that use newer APIs which are not available in the current OS version. Lifecycles cannot access even other methods so you should make sure that your observer classes only access framework classes that are available in your min API level OR use lifecycle:compiler annotation processor.
Strange, that firstly it was working fine, but not long ago this exception has appeared. I've found, that audioFocusRequest is cause of this bug.
private val audioFocusRequest by lazy {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN)
.setOnAudioFocusChangeListener(this)
.build() else throw RuntimeException("Can't be done for Android API lower than 26")
}
Does anybody know how it can be fixed?
UPD
Tried to use annotationProcessor "androidx.lifecycle:lifecycle-compiler:$lifecycle_version", but got compilation error:
(decided to paste screenshot, because whole logs are quite big)
UPD 2
At the end I've decided to delete audioFocusRequest field and to use old deprecated method - requestAudioFocus(OnAudioFocusChangeListener l, int streamType, int durationHint) instead of recommended requestAudioFocus(#NonNull AudioFocusRequest focusRequest)
It helped me to make code working again, so it can be solution. But I didn't find answer - why this problem had appeared. It strange because code used to be working before.
So problem has been solved but question still stays unanswered
Try to use kapt "androidx.lifecycle:lifecycle-compiler:2.0.0"
The class which implements LifecycleObserver has some method, which has parameters with type that only exist for higher APIs.
Your variables (i guess) and function parameters must exist on all APIs even function is not called (maybe this is requirement for classes who implement LifecycleObserver).
A possible solution is to change function parameter type to Any (kotlin) or Object (Java) and cast it to appropriate type inside function.
I have to remove this set method on SpinnerView: lifecycleOwner = viewLifecycleOwner
I was able to fix this by moving the offending methods into another class, but still called from my LifecycleObserver. After reading the error message again:
Caused by: java.lang.IllegalArgumentException: The observer class has some methods that use newer APIs which are not available in the current OS version. Lifecycles cannot access even other methods so you should make sure that your observer classes only access framework classes that are available in your min API level OR use lifecycle:compiler annotation processor.
It seems as though no methods or objects are allowed in the class extending LifecycleObserver if they don't exist in the device's OS, even if they are wrapped in an SDK version check and never accessed.

Has MatrixCursor implementation within Android P changed?

Recently I have observed a large number of crashes for an app that I maintain when the Android P developer preview is used.
Diving (deep) into the project's code, I have found the problem method to be the following:
public static <T> T get(MatrixCursor cursor, int column) {
try {
cursor.moveToFirst();
Method get = MatrixCursor.class.getDeclaredMethod("get", int.class);
get.setAccessible(true);
return (T) get.invoke(cursor, column);
} catch (Exception e) {
throw new IllegalArgumentException("Android has changed the implementation of MatrixCursor?!");
}
}
From what I understand, this code is used to retrieve a custom object from the MatrixCursor directly, rather than a primitive type, byte array or String. There has previously been a private method within MatrixCursor that performs this internally, and it is this method that we access through reflection.
Needless to say, there's a number of issues with this approach. As far as I am aware, reflection to access private APIs is a feature that Android advises heavily against. Nevertheless, until the Android P preview, this seems to have been working as expected.
This leads me to raise the following questions:
Has MatrixCursor's implementation changed or is reflection totally deprecated as of Android P?
Sadly, I am not 100% clued up on what alternatives I have to avoid this issue. Any suggestions for that are greatly appreciated, is there a Cursor that can be used to store custom objects?
Yes, something has changed.
No, the underlying implementation of MatrixCursor has likely not changed.
What has changed is that Android P is introducing restrictions on non-public members of SDK classes. Attempting to use private fields or methods on SDK classes (whether by direct invocation, reflection, or JNI) will result in a crash.
If you run the code in question on a device running P and look at the logcat output, you should see a message similar to this:
Accessing hidden field Landroid/os/Message;->flags:I (light greylist, JNI)
I highly encourage you to fully read the linked documentation on these restrictions for the full context and for more information on how you can handle it.
One option (which you should do ASAP if needed!) is to file a bug so the Android team knows that this is a method you use and does not have a public alternative. If you do this before the release of Android P, there is a much better likelihood that the team will either create a public alternative for this method or allow you to continue to access that method in P.

Native crash programmatically

Is there an easy way to crash an app with a native crash, in order to test native crash reporting?
note that I'm looking for a general solution for all devices, and not device specific. I thought about using the Unsafe class (writing illegal addresses into the stuck), but it looks like it's not supported
If you want to cause a crash from Java code, use dalvik.system.VMDebug.crash(). This is not part of the public API, so you will need to access it through reflection. This worked for Dalvik; I don't know if it still works for Art.
Some of the sun.misc.Unsafe methods are supported, so you may be able to cause a crash by selecting an appropriate value for offset in calls like putIntVolatile(). If the offset is the negation of the Object pointer you'll dereference address zero and crash.
The most reliable way is to create a trivial native library with the NDK. I personally favor storing a value in a "named" address, like 0xdeadd00d, because they let you know that it was your code crashing deliberately, but null pointer derefs work too.
As #fadden pointed out the use of dalvik.system.VMDebug.crash(), here is a helper method to access it via reflection.
public void crashNatively() {
try {
Class.forName("dalvik.system.VMDebug")
.getMethod("crash")
.invoke(null);
} catch (Exception e) {
e.printStackTrace();
}
}

Categories

Resources