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

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).

Related

Package Level Protection in Kotlin [duplicate]

In Java, we have the package protected (default) modifier for classes, which allows us to have many classes in a single package but exposes only a few and keeps the logic encapsulated.
With Kotlin this doesn't seem to be the case. If I want a few classes to be visible to each other but no further, I have to use a private modifier which limits visibility to a single file.
So if you want 10 classes in a package but only one of them to be public, you'd have to have one huge file with all the classes in it (and private all over the place).
Is this normal practice or there is a way to achieve some similar modularity in Kotlin?
I don't understand: if they have the notion of a package, why did they get rid of package protected access?
Update: We might have package protected visibility after all
see the discussion here
Update: If you read through the discussion and still think this is a must-have feature for the language, please vote here
Kotlin, compared to Java, seems to rely on packages model to a lesser degree (e.g. directories structure is not bound to packages). Instead, Kotlin offers internal visibility, which is designed for modular project architecture. Using it, you can encapsulate a part of your code inside a separate module.
So, on top level declarations you can use
private to restrict visibility to the file
internal to restrict visibility to the module
At this point, there is no other option for visibility restriction.
As a workaround for me on android I've created #PackagePrivate annotation and lint checks to control access. Here you can find the project.
Lint checks are obviously not that strict as compiler checks and some setup needed to fail the build on errors. But android studio picks up lint checks automatically and shows error immediately while typing. Unfortunately I don't know a way to exclude annotated members from autocomplete.
Also, as lint is a purely compile-time tool, no checks at runtime performed.
As #hotkeys points out, you can use the internal keyword in a module or you can put all classes that would otherwise belong in a package inside a single file, but sticking several classes in a file may be a questionable design decision.
For me, the package visibility is helpful for its documenting value. I want to know what public interface some package is presenting to the rest of the project, hide factory implementation classes and so on.
So even if it's possible to access package-private classes and methods in Java, I still choose to use the package modifier.
For this I created a project with a single annotation:
package com.mycompany.libraries.kotlinannotations;
import static java.lang.annotation.ElementType.CONSTRUCTOR;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.SOURCE;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
#Documented
#Retention(SOURCE)
#Target({ TYPE, METHOD, CONSTRUCTOR })
/**
* Use in Kotlin code for documentation purposes.
*
* Whenever a Kotlin class or method is intended to be accesible at package level only.
*
*/
public #interface PackagePrivate {
}
Then I can use this annotation in any Kotlin project.
The second step, which I haven't done yet, is creating a PMD rule to enforce this with maven (or any other build tool for that matter) and also be able to see violations of the rule in my IDE with the pmd plugin.
There no is full Kotlin support in pmd at this moment but it seems to be expected at some point.
A near-replacement for package private visibility is available using the opt-in requirements feature (credit to pdvrieze on Kotlin discussions). This is the annotation syntax typically used to flag experimental features in an API.
To use it, create an annotation denoting package private declarations:
#RequiresOptIn(message = "Only to be used in MyPackage")
#Retention(AnnotationRetention.BINARY)
annotation class MyPackagePrivate
Then annotate any methods you want to be package private with it:
#MyPackagePrivate
fun aPackagePrivateMethod() {
// do something private within a package
}
In this way a warning will be generated on any method that calls the annotated method unless the calling method is itself annotated with the corresponding #OptIn annotation, here shown at class level:
#OptIn(MyPackagePrivate::class)
class AClassInThePackage {
fun userOfPackagePrivateMethod() {
aPackagePrivateMethod()
}
}
This, then, produces a similar effect to Java's package private, except that calling methods need to explicitly opt in to using a package private declaration.
If it is desired to generate an error rather than a warning, the level parameter of #RequiresOptIn can be specified:
#RequiresOptIn(level = RequiresOptIn.Level.ERROR, message = "Only to be used in MyPackage")
// annotation declaration as before
Package-based protection is pointless in Kotlin because packages themselves are unprotected
In Java, package was tied to directory structure. So if you put your classes in com\example\yoursecretengine, any attempt (deliberate or accidental) to add a rogue class there would be easily noticeable. This is the kind of security we've depended on.
Kotlin removes the ties between directory and package, so I can put my class in "my" directory (eg.src\java\pl\agent_l\illegalaccess) yet declare its package as com.example.yoursecretengine - and gain access to all the properties you've meant as package private.
In fact, a Kotlin project works perfectly without ANY package declarations. This only highlights that packages are "more what you'd call guidelines than actual rules". They're a convenience feature, useful only to unclutter namespace and nothing more.
Relevant quotes from kotlinlang:
unlike many other languages, Kotlin packages do not require files to have any specific locations w.r.t. itself; the connection between a file and its package is established only via a package header.
And:
an absence of a package header in a file means it belongs to the special root package.

Generate Dagger components using Annotation Processor

I'm working on an Android App which follows the MVP architecture pattern. In all my fragments I'm injecting a Presenter. Therefore my Fragments (Views) need to have a Component in which I declare the injects. For example:
#ActivityScope
#Component(
dependencies = AppComponent.class,
modules = {
PresenterModule.class,
InteractorModule.class
}
)
public interface ViewInjectorComponent {
void inject(SelectEventOccurrenceFragment fragment);
void inject(CreateOpponentFragment fragment);
void inject(SelectOpponentFragment fragment);
void inject(TeammatesInvitedFragment fragment);
...
}
Every new View that I add into my App (Fragment) needs to have its entry declared here. I was wondering if It's possible to generate this code automatically with some kind of annotation processor. The App has already several fragments, this component file has easily more than 300 entries. It'd be awesome if I could do something like:
#Injectable
public class MyNewFragment implements MyNewView {
...
}
And then automatically generate the entry in the ViewInjectorComponent file. It's possible? Where should I look at?
The situation you are experiencing may be a consequence of organising your Modules and Components in an unusual way. In particular, grouping laterally (one Component injects all the Presenters) rather than vertically (one component injects the functionality related to SelectOpponentActivity) is problematic.
A good example to follow is in the Google Android Architecture Blueprints GitHub repo. If you peruse the code there, you will see that they have organised functionality related to Tasks inside one Java package together with a separate Component, Module, Presenter etc. This has the nice advantage of being able to restrict accessibility of the constructors of the classes contained therein and fulfilling Effective Java Item 13: Minimize the accesibility of classes and members.
Likewise, you've grouped all your modules together into a Presenter Module and an Interactor Module. The advice from the Dagger 2 official documentation is to organise Modules first for testability and then along functional lines. Again, you can refer to the Blueprint example for how to do this.
Finally, note that there is unavoidably some boilerplate involved in using most DI frameworks like Dagger 2. In a sense, you are exchanging a bigger problem ("how do I deal with all of these constructors?") with much smaller and more manageable problems ("how do I group my Components" etc.).
Update
There is a library called Auto Dagger2 that can generate components for you. See this Github repo. Here is an example of an annotation:
#AutoComponent
#Singleton
public class ExampleApplication extends Application {
}
Which generates the following code:
#Component
#Singleton
public interface ExampleApplicationComponent {
}
Also check out Google Auto if you are interested in code generation tools.
I'm not entirely sure that what I'm going to say is appropriate for an answer, but I'll take a chance here.
Even if you find a way to do what you want, don't do this in production (it is fine if you just want to learn code generation techniques).
The benefits you get from such an approach are small (not writing several lines of trivial code), but consider the drawbacks:
The logic for code generation needs to be written/debugged/maintained
Such an approach will be a violation of "principle of least astonishment"
Code generation is BAD
Note the third point - I really mean it. Usage of code generation always leads to maintenance overhead, therefore it should be used only as a last resort.
Dagger by itself uses code generation, but for a good reason - performance. However, performance is not an issue in your case.
To summarize: your idea is very interesting, but approaches like this should not be used for production applications (unless this functionality is added to Dagger natively).

How does Dagger 2 make testing easier on Android?

One of the best advantages of using DI is it makes testing a lot easier (What is dependency injection? backs it too). Most of DI frameworks I've worked with on other programming languages (MEF on .NET, Typhoon on Obj-C/Swift, Laravel's IoC Container on PHP, and some others) allows the developer do register dependencies on a single entry point for each component, thus preventing the "creation" of dependency on the object itself.
After I read Dagger 2 documentation, it sounds great the whole "no reflection" business, but I fail to see how it makes testing easier as objects are still kind of creating their own dependencies.
For instance, in the CoffeMaker example:
public class CoffeeApp {
public static void main(String[] args) {
// THIS LINE
CoffeeShop coffeeShop = DaggerCoffeeShop.create();
coffeeShop.maker().brew();
}
}
Even though you're not explicitly calling new, you still have to create your dependency.
Now for a more detailed example, let's go to an Android Example.
If you open up DemoActivity class, you will notice the onCreate implementation goes like this:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Perform injection so that when this call returns all dependencies will be available for use.
((DemoApplication) getApplication()).component().inject(this);
}
You can clearly see there is no decoupling from the DI component, to the actual code. In summary, you'd need to mock/stub ((DemoApplication) getApplication()).component().inject(this); on a test case (if that's even possible).
Up to this point, I am aware Dagger 2 is pretty popular, so there is got to be something I am not seeing. So how does Dagger 2 makes testing classes easier? How would I mock, let's say a network service class that my Activity depends on? I would like the answer to be as simple as possible as I'm only interested in testing.
Dagger 2 doesn't make testing easier
...beyond encouraging you to inject dependencies in the first place, which naturally makes individual classes more testable.
The last I heard, the Dagger 2 team were still considering potential approaches to improving support for testing - though whatever discussions are going on, they don't seem to be very public.
So how do I test now?
You're correct to point out that classes which want to make explicit use of a Component have a dependency on it. So... inject that dependency! You'll have to inject the Component 'by hand', but that shouldn't be too much trouble.
The official way
Currently, the officially-recommended approach to swapping dependencies for testing is to create a test Component which extends your production one, then have that use custom modules where necessary. Something like this:
public class CoffeeApp {
public static CoffeeShop sCoffeeShop;
public static void main(String[] args) {
if (sCoffeeShop == null) {
sCoffeeShop = DaggerCoffeeShop.create();
}
coffeeShop.maker().brew();
}
}
// Then, in your test code you inject your test Component.
CoffeeApp.sCoffeeShop = DaggerTestCoffeeShop.create();
This approach works well for the things you always want to replace when you are running tests - e.g. Networking code where you want to run against a mock server instead, or IdlingResource implementations of things for running Espresso tests.
The unofficial way
Unfortunately, it the official way can involve a lot of boilerplate code - fine as a one-off, but a real pain if you only want to swap out a single dependency for one particular set of tests.
My favourite hack for this is to simply extend whichever Module has the dependency you want to replace, then override the #Provides method. Like so:
CoffeeApp.sCoffeeShop = DaggerCoffeeShop.builder()
.networkModule(new NetworkModule() {
// Do not add any #Provides or #Scope annotations here or you'll get an error from Dagger at compile time.
#Override
public RequestFactory provideRequestFactory() {
return new MockRequestFactory();
}
})
.build();
Check this gist for a full example.
"allows the developer do register dependencies on a single entry point for
each component" - analogues in Dagger 2 are the Modules and Components where you define the dependencies. The advantage is that you don't define the dependencies directly in your component thus decoupling it so later when writing unit tests you may switch the Dagger 2 component with a test one.
"it sounds great the whole "no reflection" business" - the "no reflection" thing is not the "big deal" about dagger. The "big deal" is the full dependency graph validation at compile time. Others DI frameworks don't have this feature and if you fail to define how some dependency is satisfied you will get an error late at runtime. If the error is located in some rarely used codepath your program may look like it is correct but it will fail at some point in the future.
"Even though you're not explicitly calling new, you still have to create your dependency." - well, you always have to somehow initiate dependency injection. Other DI may "hide"/automate this activity but at the end somewhere building of the graph is performed. For dagger 1&2 this is done at app start. For "normal" apps (as you shown in the example) in the main(), For android apps - in the Application class.
"You can clearly see there is no decoupling from the DI component, to the actual code" - Yes, you are 100% correct. That arises from the fact that you don't control directly the lifecycle of the activities, fragments and services in Android, i.e. the OS creates these objects for you and the OS is not aware that you are using DI. You need manually to inject your activities, fragments and services. At first this seem seems awkward but in real life the only problem is that sometimes you may forget to inject your activity in onCreate() and get NPE at runtime.

What does the annotations do exactly in Android at compile time?

#SuppressWarnings("unsued")
#Override
#SuppressLint({ "InflateParams", "SimpleDateFormat" })
I don't get why we need to declare annotations.
We want to facilitate the writing and the maintenance of Android applications.
We believe that simple code with clear intents is the best way to achieve those goals.
Robert C. Martin wrote:
The ratio of time spent reading [code] versus writing is well over 10 to 1 [therefore] making it easy to read makes it easier to write.
While we all enjoy developing Android applications, we often wonder: Why do we always need to write the same code over and over? Why are our apps harder and harder to maintain? Context and Activity god objects, complexity of juggling with threads, hard to discover API, loads of anonymous listener classes, tons of unneeded casts... can't we improve that?
How?
Using Java annotations, developers can show their intent and let AndroidAnnotations generate the plumbing code at compile time.
Features
Dependency injection: inject views, extras, system services, resources, ...
Simplified threading model: annotate your methods so that they execute on the UI thread or on a background thread.
Event binding: annotate methods to handle events on views, no more ugly anonymous listener classes!
REST client: create a client interface, AndroidAnnotations generates the implementation.
No magic: As AndroidAnnotations generate subclasses at compile time, you can check the code to see how it works.
AndroidAnnotations provide those good things and even more for less than 50kb, without any runtime perf impact!
Is your Android code easy to write, read, and maintain?
Look at that:
#EActivity(R.layout.translate) // Sets content view to R.layout.translate
public class TranslateActivity extends Activity {
#ViewById // Injects R.id.textInput
EditText textInput;
#ViewById(R.id.myTextView) // Injects R.id.myTextView
TextView result;
#AnimationRes // Injects android.R.anim.fade_in
Animation fadeIn;
#Click // When R.id.doTranslate button is clicked
void doTranslate() {
translateInBackground(textInput.getText().toString());
}
#Background // Executed in a background thread
void translateInBackground(String textToTranslate) {
String translatedText = callGoogleTranslate(textToTranslate);
showResult(translatedText);
}
#UiThread // Executed in the ui thread
void showResult(String translatedText) {
result.setText(translatedText);
result.startAnimation(fadeIn);
}
// [...]
}
Java annotations bind specific conditions to be satisfied with code. Consider a scenario where we think we are overriding a method from anther class and we implemented code that (we think) is overriding the method. But if we somehow missed to exactly override one (e.g. we misspelled name. In superclass it was "mMethodOverridden" and we typed "mMethodoverridden"). The method will still compile and execute but it will not be doing what it should do.
So #Override is our way of telling Java to let us know if we are doing right thing. If we annotate a method with #override and it is not overriding anything, compiler will give us an error.
Other annotations work in a very similar way.
For more information, read docs Lesson: annotations
Annotations are basically syntactic metadata that can be added to Java source code.Classes, methods, variables, parameters and packages may be annotated .
Metadata is data about data
Why Were Annotations Introduced?
Prior to annotation (and even after) XML were extensively used for metadata and somehow a particular set of Application Developers and Architects thought XML maintenance was getting troublesome. They wanted something which could be coupled closely with code instead of XML which is very loosely coupled (in some cases almost separate) from code. If you google “XML vs. annotations”, you will find a lot of interesting debates. Interesting point is XML configurations were introduced to separate configuration from code. Last two statements might create a doubt in your mind that these two are creating a cycle, but both have their pros and cons.
For eg:
#Override
It instructs the compiler to check parent classes for matching methods.

Android free/paid app using compiler trick

I was wondering whether you could use a trick of the compiler to include different functions for a free and paid version of the app. For instance:
public static final boolean paid = false;
if (paid){
runPaidMethod();
}
else {
runFreeMethod();
}
The compiler will look at that and say that it doesn't need the first branch of the if statement so it won't compile it. Furthermore, it should look at the program and see that runPaidMethod() is no longer referenced from anywhere and remove it.
Therefore the question is: is it feasible to just have this flag, compile it once for free, swap the flag then compile it again for paid?
Using a final boolean variable is good because the Java compiler is smart enough to see that your condition is always false. If you decompile the compiled class (you can try it, with the javap -c command) you will see that your code :
public static final boolean paid = false;
if (paid) {
runPaidMethod();
}
else {
runFreeMethod();
}
will be compiled to a single call to :
runFreeMethod();
The compiler removes any unreachable code, so nobody will be able to reverse engineer your app. But be careful, you have to declare runPaidMethod() as a private method, or its content will still appear in the compiled class.
However from a maintenance point of view, it is still better to use Library Projects to handle multiple app versions.
The concept you are trying to express is known as conditional compilation. In a language like C or C++ you would accomplish this with a combination of preprocessor directives and compiler flags. A rather crude example:
#ifdef PAID
runPaidMethod();
#else
runFreeMethod();
#endif
Good, bad or indifferent, this sort of conditional compilation does not exist in Java. But thats not too say what you are trying to do cannot be accomplished, you just need to think in a more object oriented fashion. One such way of implementing what you are seeking would be to define your major service providers as interfaces, and provide implementations for the paid and free versions. Something like:
public interface UsefulService {
public void someMethod();
public void otherMethod();
}
public class BaseUsefulService {
// Common functionality here
public void otherMethod() {
}
}
public class FreeUsefulService {
public void someMethod() {
}
}
public class PaidUsefulService {
public void someMethod() {
}
}
With this kind of breakdown you can actually build the paid version of the application into an entirely separate application (by putting all its service providers in a separate project).

Categories

Resources