I am generating documentation using KDoc/Dokka for an android library.
I have a custom view, which extends LinearLayout.
The problem is that LinearLayout contains hundreds of public methods. Dokka generates empty documentation for all of these methods, even though I did not use or override them in my own code.
This completely buries any of my own methods and makes the documentation near useless.
How can I prevent dokka from generating documentation for inherited methods?
Currently this is not supported, probably we will add some flag to turn it on/off.
You can follow this issue: https://github.com/Kotlin/dokka/issues/1501
From the answer by #andrzej-ratajczak the following can be used
pluginsMapConfiguration.set(
["org.jetbrains.dokka.base.DokkaBase": """{ "separateInheritedMembers": true}"""]
)
here an example of my own module
dokkaHtml {
moduleName = "${project.name}"
dokkaSourceSets {
configureEach {
// Suppress a package
perPackageOption {
// will match all packages and sub-packages
matchingRegex.set(".*\\.internal.*")
suppress.set(true)
}
// separate inherited members to avoid polluting our public API
// https://github.com/Kotlin/dokka/issues/1501
pluginsMapConfiguration.set(
["org.jetbrains.dokka.base.DokkaBase": """{ "separateInheritedMembers": true}"""]
)
}
}
}
Related
I'm using #RestrictTo annotation to denote that a function should be used in only in subclasses or tests.
To do that I use the following syntax:
#RestrictTo(value = [SUBCLASSES, TESTS])
public override fun onCleared() {
// Expose protected fun onCleared for tests
}
At first it seemed to be working but my teammates reported Android Studio showing this warning:
I could reproduce this after building the project again.
This error goes away if I remove the TESTS scope from the annotation as if the annotation does not support multiple scopes in values.
Do you think if this is the intended behavior of the annotation?
Can you think another way to restrict a function to the union of two different scopes?
Thanks in advance
I'm quite new to building a custom annotation processor,
I've followed some tutorials & guides over here on SO too but been stuck on adding a condition for the annotated method.
The problem:
I have a custom annotation directed only for methods,
say, #RUN(isDebug: Boolean) & the method would be:
#RUN(isDebug = true)
private fun runInDebugOnly() {
....
}
#RUN(isDebug = false)
private fun runInReleaseOnly() {
....
}
So in my Annotation Processor,
is it possible to execute these functions with a condition?
I know the concept of generating a custom class & methods inside it,
But how to exactly intercept the method & use the generated method instead.
Any guidance would be appreciated.
An annotation processor only runs at compile time, and is usually used to generate new classes or code.
Sounds to me like you want to generate a new method at compile time which will call the correct annotated method depending on the build type.
e.g. when you run a debug build you want to have
fun myNewMethod() {
runInDebugOnly()
}
but when you run a release build you want to have
fun myNewMethod() {
runInReleaseOnly()
}
The rest of your app will just call myNewMethod() and it won't care about the implementation.
You could achieve this another way without using an annotation processor
fun myNewMethod() {
if (Build.DEBUG) {
runInDebugOnly()
} else if (Build.RELEASE) {
runInReleaseOnly
}
}
Is this the kind of thing you're after?
I'm kinda new to Android development so my question might be weird or not even possible. I wouldn't know!
Anyway, I'm building multiple apps that will have a lot of shared elements, so I decided to build a library with those components and use it in all of the apps, rather than stupid copying and pasting code.
For example, the library handles the welcome screen and login/signup flow activities, among other things. So here are the problems this approach might cause:
While the behavior is the same across the apps, but the logo that I show at the welcome screen is different. Right now I populate it with an image resource from the library resources (R class) which will be the same for all apps and is obviously not correct.
The login/signup process is based on Firebase, which will require the app to have a key to be able to use them. Right now I also populate it with a dummy string resource from the library resources.
So my question really boils down to 3 parts:
Is there anyway I could pass this info from the app to the library? can I somehow modify the R class of the library? Or can I use the app's R class from the library? I can also call this part of the library as a function passing the parameters I need. But the first solution looks maybe more clean to me?
Whatever the answer to Q1 is. Where would I do this and how? The library has the welcome activity itself which is supposed to be the first activity in the app. How and where do I do this once the app starts and before the first activity starts?
If what I'm doing is wrong or impossible, is there any other way to achieve it?
Is there anyway I could pass this info from the app to the library?
can I somehow modify the R class of the library? Or can I use the
app's R class from the library? I can also call this part of the
library as a function passing the parameters I need. But the first
solution looks maybe more clean to me?
You don't need to modify the R class because you can override the resource file by creating a file with the same name. But it's not a clean solution because you constantly need to ensure your project and library resources name are the same.
Whatever the answer to Q1 is. Where would I do this and how? The
library has the welcome activity itself which is supposed to be the
first activity in the app. How and where do I do this once the app
starts and before the first activity starts?
Instead of overriding the resources name, you're better to modify your library to receive a configuration as a contract to use the library. Here the sample:
First, create the class for holding the configuration:
public class Configuration {
private int welcomeImageDrawableId;
private int logoDrawableId;
// constructor
public Configuration(int welcomeImageDrawableId, int logoDrawableId) {
this.welcomeImageDrawableId = welcomeImageDrawableId;
this.logoDrawableId = logoDrawableId;
}
// setter and getter.
public int getLogoDrawableId() {
return logoDrawableId;
}
}
Second, use the configuration class for the library by creating a Singleton class which will be used internally by the library:
public class MyLibrary {
private static MyLibrary myLibrary;
private Configuration configuration;
private MyLibrary(){}
private MyLibrary(Configuration configuration) {
this.configuration = configuration;
}
public static MyLibrary getInstance() {
if(myLibrary == null) {
throw new RuntimeException("Need call createInstanceWith method first!!");
}
return myLibrary;
}
public static MyLibrary createInstanceWith(Configuration configuration) {
if(myLibrary == null) {
synchronized(MyLibrary.class) {
if (myLibrary == null) {
myLibrary = new MyLibrary(configuration);
}
}
}
return test;
}
public Configuration getConfiguration() {
return configuration;
}
}
Third, use the configuration class in your library via the singleton class. something like this:
// assume imvLogo is an existing ImageView
Configuration configuration = MyLibrary.getInstance().getConfiguration();
imvLogo.setImageResource(configuration.getLogoDrawableId());
Last, register the contract when the library is used with:
Configuration configuration = new Configuration(R.drawable.welcome, R.drawable.logo);
MyLibrary.createInstanceWith(configuration);
Note: all the code isn't tested yet, error is to be expected.
Apart from the solution above, I also found another way to achieve this whole thing without having to initialize libraries and whatnot.
I think the correct way to do this is to use productFlavors in the library. This allows the library to share the one main set of source code, one main set of resources, then an extra set of resource per app/flavors. This is very sufficient for my purposes.
For more info about build variants and flavors:
https://developer.android.com/studio/build/build-variants
In my Kotlin Multiplatform project, I'm trying to access Kotlin types defined in kotlin-stdlib from Swift.
TL;DR: StdLib types/methods seem not to result in header definitions, I'd like a solution that doesn't involve writing lots of boilerplate code
My scenario
I have an interface defined in Kotlin ...
interface MyKotlinInterface {
fun run() : Sequence<String>
}
... and implemented this interface in Swift ...
class MySwiftClass : MyKotlinInterface {
func run() -> KotlinSequence {
// return sequenceOf("foo")
}
}
... there I'm trying to create a Sequence but there are no methods from the kotlin.sequences package available (e.g. generateSequence).
Is it actually possible to access Kotlin framework types or methods beyond what I define in my code -- if yes, how? Furthermore, how can this be achieved without writing boilerplate code?
Further details
Having a look into the generated Objective-C header file, I see definitions for my class (obviously) and basic Kotlin types. What's missing is basically everything from the standard library functionality (I care for everything Sequence-related).
My build.gradle.kts looks like:
plugins {
kotlin("multiplatform") version "1.3.0"
}
kotlin {
targets { /* ... */ }
sourceSets {
getByName("commonMain") {
dependencies {
api("org.jetbrains.kotlin:kotlin-stdlib-common")
}
}
// ...
getByName("iosMain") {
dependencies {
api("org.jetbrains.kotlin:kotlin-stdlib")
}
}
}
}
Having the kotlin-stdlib defined as a dependency for the iOS target, I would expect those to become actually available from Swift.
Minimal working example
https://github.com/panzerfahrer/so-mwe-kotlin-mpp-swift
Current solution approach
The only solution I came up with, is writing the desired function for the iOS target:
fun <T : kotlin.Any> generateSequence(nextFunction: () -> T?): kotlin.sequences.Sequence<T> = kotlin.sequences.generateSequence(nextFunction)
This works ok-ish but is highly unsatisfying as it requires lots of boilerplate code. Additionally, extension functions cannot be made available this way and would require more boilerplate code or even rewriting parts of the standard library.
Desired solution
I like to avoid writing boilerplate code as much as possible. What I actually only care about, is to have (in my case) Sequence fully accessible from Swift. My feeling is, it would be sufficient to make the compiler generate selected or all header definitions for the standard library functionality.
Do you really need lazy computation (aka Sequence) in your Kotlin code?
If no, I would recommend using List<T> instead (and it maps to Swift directly).
For Sequence implementation, a workaround could be to export a factory function from your Kotlin library, e.g. you may declare a function like
fun <T : kotlin.Any> generateSequence(nextFunction: () -> T?)
= kotlin.sequences.generateSequence(nextFunction)
You may select any other factory function for Sequence, that matches your use-case.
In general, there are too many functions in the Kotlin standard library. Exporting them all to Swift will create too many useless symbols in the binary and increase the compilation time.
I am trying to you use Android Annotations (https://github.com/excilys/androidannotations) in an existing project. I cannot convert the whole project to use Annotations. Can I have some activities that utilize annotations and some acitivites that doesn't use Annotations.
But When I did that, some functionalities stopped working. Like If I used only -
#ViewById(R.id.find)
public Button FIND;
...
...
#Override
protected void onCreate(Bundle savedInstanceState) {
...
if (FIND != null) {
FIND.setOnClickListener(this);
}
...
}
OnClick on the button doesn't work. Is it mandatory to use #Click annotation.
Can't I just use annotations only where I wish to have. And other parts of the code be the old code without annotations. Please guide me.
Thanks
Please read the doc more carefully. The injected views are first available in the #AfterViews annotated methods:
#AfterViews
void afterViews() {
// you can use injected views here
}
https://github.com/excilys/androidannotations/wiki/Injecting-Views#afterviews
First of all please respect coding convention, you can find ax explanation here
Then, for your question, you can use code of both types: native android and android annotations one.
If you inflate a view using #ViewById annotation, you must keep in mind that the injection of the view is done at a certain point of the execution, so before of that your variable will be null.
As WonderCsabo reccommended to you, use injected views inside of #AfterViews annotated method.
Otherwise, if you want to mantain android native syntax, you MUST instantiate your view manually with findViewById method. Obviously after that you have setted activity's layout