There are #Immutable and #Stable annotations available for developers to mark their classes with. But I'm not quite sure when you need to annotate your classes and when it is inferred automatically. E.g. deeply-immutable data classes seems to be recognized as immutable by default. But you cannot be quite sure unless you log all #Composable calls and see how it behaves. And not knowing what is actually going on is somewhat infuriating for me as a programmer.
I wonder if there are more reasonable ways to see what immutability/stability Compose compiler infers for custom classes?
And if there are no clever ways to check it, what would be the rule of thumb for using #Immutable and #Stable annotations?
You can enable the compose compiler metrics to see what the compiler considers is stable. https://github.com/androidx/androidx/blob/androidx-main/compose/compiler/design/compiler-metrics.md
Related
As MVI is getting more and more popular in Android development, the use of Sealed classes increases as well. And we know that we have to determine the actual type of the Sealed class in order to continue with a particular flow from our logic.
So does Kotlin use reflection when using the 'is' operator for type checks? Tried to go through the documentation, but couldn't find anything about that. https://kotlinlang.org/docs/typecasts.html
Depends on the definition of reflection you’re using. Often “reflection” in the JVM world is used to describe specifically the String-based code meta data inspection from the java.lang.reflect package (or Kotlin reflection dependency) that is considered to be inefficient. But a more general definition of “reflection” is any code introspection. is arguably fits the second definition, but it is fast/optimized and not part of the first definition.
The 'is' operator in Kotlin is used for type checks, for example to check if an object is an instance of a particular class or its subclasses. The 'is' operator does not use reflection to perform type checks. Instead, the type check is done at compile-time, and the generated bytecode contains an instanceof check, which is a standard JVM instruction for performing type checks.
In the case of sealed classes, the use of 'is' operator will not use reflection as well, it's a compile-time check, that's why when using the 'is' operator with a sealed class, the compiler is able to perform type checks and generate the appropriate bytecode at compile-time.
Using the 'is' operator is much more efficient than using reflection, as it is a compile-time check and it does not require any runtime overhead, while reflection can be relatively slow, as it requires the JVM to perform additional lookups and checks at runtime.
So, in summary, the 'is' operator in Kotlin does not use reflection for type checks. It's a compile-time check, which is much more efficient than using reflection.
In most of the samples regarding Android View Model and lazy init nobody refers to the parameters which can be used in by Lazy.
From the Kotlin docu:
If you're sure that the initialization will always happen in the same thread as the one where you use the property, you can use LazyThreadSafetyMode.NONE. It doesn't incur any thread-safety guarantees and related overhead.
I can not recall any cases in my project where I access ViewModel properties outside the MainUIThread, so I'm intending to now use LazyThreadSafetyMode.NONE everywhere in my ListFragmentViewModel, but I'm not seeing Google's samples doing this at all, am I missing some cons? The Google IO App 2022 uses LazyThreadSafetyMode.PUBLICATION in some part of the code, but could not find any usages of LazyThreadSafetyMode.NONE.
I am currently integrating architecture components into my app according to the official documentation and the sample apps provided by google (sunflower and todo-app). I realized that none of these use interfaces for ViewModels (the sunflower app does not even use interfaces for repositories).
My question is: is it reasonable to just omit the interfaces for ViewModels (including advantages and disadvantages)?
Is it reasonable to just omit the interfaces for ViewModels?
The below is quite general and applicable not just for ViewModels.
Advantages:
less code
Disadvantages:
won't be able to use most of the well-known design patterns;
won't be able to properly unit test classes (no mocking);
won't be able to properly use dependency injection frameworks;
code refactoring when using another concrete implementation.
The answer depends on the complexity of your ViewModel. If you are never going to create more than one implementation of an interface (including mocking), then there is no need to create the interface, so you can reduce the code and the overall maintenance burden.
That said the important things to consider are:
Can you unit test your view model, even without the interface (answer should be yes, otherwise you have some other problems IMO)
Can you still use a dependency injection framework (the answer is yes at least for some DI frameworks like Prism)
Are you only ever going to create one implementation of your ViewModel?
I believe that the mark of a well-designed ViewModel, should have a relatively simple implementation, and be easy to unit-test without having to resort to mocking.
Can any one suggest a proper order to define a custom annotation in JAVA(Android). So that if I annotate a method with #Background annotation, the method should work on background thread.
This might be of use for your need case Creating custom Annotations. It seems like you would need to do #Retention(RetentionPolicy.RUNTIME) and #Target(ElementType.METHOD) scope to achieve what you want. Then as you can see in the first example, you would go into the object and etc.
For a good example, look at what they do in Dagger
As a final note, this is old and you've probably designed what you wanted, but it probably isn't a good idea to do what you asked. There is cost to annotation usage and Runnable was built basically for what you seem to be trying to do.
Android's Annotation subtypes provide a wide variety of tools for what you are trying to do. In particular, take a look at the thread annotations; I suspect that the #WorkerThread annotation does just what you want. The code inspection tools in Android Studio recognize these annotations and will automatically flag any code that it recognizes as violating the threading requirements (e.g., calling a UI thread method from a method annotated as #WorkerThread).
The code inspection tools also allow you to define your own annotations, but these are somewhat limited in what they can do. This is discussed in the section Creating Enumerated Annotations.
You can't use a custom annotation in JAVA(Android), because the android compiler doesn't support it. But maybe the follwing site can be helpful for you: http://androidannotations.org/
My team has adopted Dagger for dependency injection within our Android app and I must say that we love it so far. However, we want to make sure that we are using it efficiently. I was wondering if anyone can explain or if there is any documentation explaining the cases in which Dagger falls back to reflection for injecting dependencies?
Dagger's fall-back logic is embedded in its FailoverLoader class. It used to failover when it could not load a ModuleAdapter for a given module, but most recent releases will fail with an error if it cannot load a ModuleAdapter.
Currently, Dagger will fail-over if it cannot find an InjectAdapter class for a given type that needs injecting. The most common case is when you have an abstract parent of an injectable type, that has no #Inject fields. In this case, no InjectAdapter will have been created for it, and so when the concrete injectable type is loaded, it tries to lookup an adapter for the parent, cannot find one, and a reflective stand-in is created.
Similarly, if one does not run code-generation against classes that are decorated with #Inject fields or constructors, Dagger will fall-back to reflection for those as well. It's really the same logic as with the inheritance case above, it's just that inheritance is the only case that doesn't stem from a failure to run the code-generation.
As an aside, the Google fork at http://github.com/google/dagger currently generates adapters that handle their parent types without looking up an adapter for the parent (hard coded parent adapters), so this fail-over does not occur in the google fork. We haven't released the google fork to maven, as it's been nearly identical up until recently, but if failover logic in parent classes is an issue, you may wish to file an issue and ask for a release.