I'm trying to understand android plugin, when I look at "defaultConfig", I find the method is
public void defaultConfig(Action<ProductFlavor> action) {
this.checkWritability();
action.execute(this.defaultConfig);
}
and calling action.execute(this.defaultConfit) invokes the closure against this.defaultConfig.
This is confusing, so I looked at doc of interface Action to see what magic it has.
According to doc of Action interface, when calling action.execute(obj), it actually "Performs this action against the given object", and the given object here is obj.
How does this work?
ASAIK, if I wish to call a method against obj, I use "it" to reference to the obj: it.doSth(), otherwise the method will be invoked against "this".
But when using Action interface, "it" is no more necessary and method calls within this interface will just be invoked against "it".
I also write some code to test it:
class Main {
Test test = new Test()
test.actionReceiver {
// actionName "test ok"
it.actionName "test ok"
}
}
static interface MyAction<T> {
void execute(T)
}
static class MyActionReceiver {
void actionName(String name) {
println name
}
}
static class Test {
MyActionReceiver actionReceiver = new MyActionReceiver()
void actionReceiver(MyAction<MyActionReceiver> action) {
action.execute(actionReceiver)
}
}
}
If my interface MyAction had the magic that Action interface has, then calling actionName without "it" should just work, however it didn't.
My question is: how Action interface works and how can I make my interface work the same way?
Gradle tasks can contain one or more Actions. You can find more about Actions here:
https://docs.gradle.org/current/javadoc/org/gradle/api/Action.html#execute(T)
Actions are typically defined in the
doFirst{...}
or
doLast{...}
block of a task definition. See:
task hello {
doLast {
println 'Hello world!'
}
}
When writing custom tasks you can simply annotate your main action with the #TaskAction annotation:
task hello(type: GreetingTask)
class GreetingTask extends DefaultTask {
#TaskAction
def greet() {
println 'hello from GreetingTask'
}
}
Some more helpful links:
https://docs.gradle.org/current/userguide/tutorial_using_tasks.html
https://docs.gradle.org/current/javadoc/org/gradle/api/Task.html
Related
I'm so beginner in koin.
I have a method that named "MesheRepoImpl" that get an interface as parameter.
I know that I can't pass an interface to a method in Koin, so I created a class and extends that from the interface then I added that class in koin module, so I use the class as parameter for MesheRepoImpl.
But android studio gives me this error:
Caused by: org.koin.core.error.NoBeanDefFoundException: |- No definition found for class:'com.app.meshe.data.repo.MesheRepo'. Check your definitions!
This is my Di module:
val mesheModule =
module {
single { getInstance(androidContext()) }
single { MesheLocalDataSource() } //*
single { MesheRepoImpl(get()) } //**
factory { TaskViewModelFactory(get()) }
viewModel { TaskViewModel(get()) }
viewModel { RewardViewModel(get()) }
viewModel {MainViewModel()}
}
The 1 star line is my class that extends from the interface and the 2 stars line is the class that get interface as parameter.
How can I pass the interface as parameter, if I can't use a class?
Since there's still no answer, I'd advise you to consider going with
interface MesheRepo
class MeshoRepoImpl(): MeshoRepo
over your
interface MesheRepo
class MeshoRepoImpl(val IRepo: MeshoRepo)
So, just implement MeshoRepo over passing it as an argument to MeshoRepoImpl.
Trying to answer directly your question, you are able to define interfaces in Koin module and pass them, but you have to provide their implementations, as well:
val mesheModule = module {
single<MeshoRepo> { MeshoRepoImpl() }
single { MeshoRepoImpl(get()) } // <-- it's like a deadlock, so I still do not see any sense to pass an interface over implementing it
}
And, please, do not forget that an interface is not an object.
I am currently implementing an app that uses a printer from Hoin. They provided an SDK that I can integrate in Android Studio (done) and tell me to instantiate the instance like this:
val mHoinPrinter = HoinPrinter.getInstance(context, mode, callback)
For context and mode, no biggies. For the callback I am having troubles.
In their documentation they specify that the callback is of interface PrinterCallback which is composed like so:
Public interface PrinterCallback {
Public void onState(int state); //state callback, parameter is status code, refer to status code definition
Public void onError(int errorCode); //Error callback, parameter is error code, refer to error code definition
Public void onEvent(PrinterEvent event); //Event callback, parameter is PrinterEvent event, refer to PrinterEvent definition
}
Which is great because it gives me 4 events that should be triggered at some point.
My issue is that I have no clue how to actually instantiate it. I know that I need to do it like so val mHoinPrinter = HoinPrinter.getInstance(this.context, 2, callback) but where I have troubles is in defining the callback. Should I write a function? should I setup something extra? How can I define logics for this callback?
It's very confusing when reading the docs online.
You have to create an implementation of the PrinterCallback interface and then pass that implementation as a parameter to getInstance method. The implementation can be created as so
val callback = object: PrinterCallback{
override fun onState(state: Int) {
// DO SOMETHING
}
override fun onError(errorCode: Int) {
// DO SOMETHING
}
override fun onEvent(event: Int) {
// DO SOMETHING
}
}
If you do everything else as specified in the documentation then these three functions will be invoked on their respective events
I am trying to build a custom Gradle Task to perform some app maintenance operations. I would like to pass argument(s) to the task to control operations. To illustrate my dilemma, consider to following two trivial custom task classes:
// Custom task with no arguments
public class HelloClassA extends DefaultTask {
#TaskAction
public void printHello()
{
println "Hello, World!"
}
}
// Custom task with one argument
public class HelloClassB extends DefaultTask {
#TaskAction
public void printMsg(String msg)
{
println msg
}
}
They are identical except that "A" prints a hard-coded string while "B" accepts a string as an argument.
Class A is used in the following task:
task helloA(type:HelloClassA) { }
and is invoked by, e.g.,
gradlew.bat helloA
It works fine and prints "Hello, World!" to the Build window. However, I can't figure out the syntax is for a task to invoke Class B.
How do I do that? (or am I just way off base trying to do it this way?)
Some rather Strange Things I've noticed...
The name of the method in the classes (e.g., "printHello") seems to be irrelevant: any reasonable name produces identical output (?).
When invoking by gradlew.bat, any unambiguous substring of the task name works the same, e.g., "GRADLEW helloA" or "GRADLEW hell". I guess this is just GRADLE trying to be helpful (?).
You can't directly pass it as an argument to the method. But, if you wish there is a way using #Input annotation.
Following is the example for you use case:
abstract class HelloClassB extends DefaultTask {
#Input
abstract Property<String> getMsg()//this is an abstract method to get values
#TaskAction
def printMsg() {
println msg.get() // here we get the value set from task.register
}
}
// printB is the task name
tasks.register('printB',HelloClassB) {
msg = 'Hello B' // here we set the Input value
}
Now in your terminal run: gradlew -q printB
If you want to read more about this then please have a look here: https://docs.gradle.org/current/userguide/custom_tasks.html
You can pass an argument(s) directly to a method without using properties. Here's how:
apply plugin: 'com.android.application'
import javax.inject.Inject
abstract class CustomTask extends DefaultTask {
#Inject
CustomTask(String message,int number) {
println "Processing \""+message+"\", "+number // process args
}
}
Create task 'mytask' as follows in the android section appending the arguments (which must agree in count and format with the task definitions):
tasks.register( 'mytask', CustomTask, 'Hello, World!', 123 )
Execute 'mytask' by
gradlew.bat mytask
which produces the output
Processing "Hello, World!", 123
I'm a bit kotlin newbie and I'm trying to remove the callback instance inside the callback itself.
What I'm trying to achieve it's something similar to the following code.
private val myCallback = SomeInterfaceType {
if(it.something) {
someObject.removeListener(this#SomeInterfaceType)
}
}
Of course it doesn't compile or else I wouldn't be asking here. So I ask, how to remove the callback from inside the instance of the interface?
edit:
the error is "inferred type is X but Y was expected.
edit 2: I just realized I've asked the wrong question, it's similar to it but not exactly a Interface.
The object I'm using have the following constructor/interface
public open class Watcher<T> public constructor(call: (T) -> kotlin.Unit)
so in reality I'm trying to reference the Watcher from inside the call: (T) -> kotlin.Unit to remove the listener.
Is that possible?
You need to use a full object expression syntax to refer to be able to refer to the instance itself:
private val myCallback = object: SomeInterfaceType() {
override fun onSomeEvent() {
if (it.something) {
someObject.removeListener(this)
}
}
}
There's also a workaround: wrap the reference to myCallback into a lambda passed to a function that calls it (e.g. run { ... }):
private val myCallback: SomeInterfaceType = SomeInterfaceType {
if (it.something) {
someObject.removeListener(run { myCallback })
}
}
Recently I saw an RxJavaarticle explaining Transformers and highlighting how they could be used to reuse Schedulers. I tried to use this and inside the same class, this method works fine:
<T>Observable.Transformer<T, T> applySchedulers() {
return new Observable.Transformer<T, T>() {
#Override
public Observable<T> call(Observable<T> observable) {
return observable
.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
}
};
}
I want to move this into a helper class with a static method so I can use it in my whole Androidapp. But when I try to use the method of this class
public class RxFunctions {
public static <T>Observable.Transformer<T, T> applySchedulers() {
return new Observable.Transformer<T, T>() {
#Override
public Observable<T> call(Observable<T> observable) {
return observable
.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
}
};
}
}
inside another class
public void requestLoginState() {
restClient.requestLoginState()
.compose(RxFunctions.applySchedulers())
.subscribe(new TimberErrorSubscriber<LoginStateResponse>() {
#Override
public void onCompleted() {
}
...
it will no longer recognise my Subscriber, error: Cannot resolve method 'subscribe(anonymous com.example.util.rx.TimberErrorSubscriber<com.example.network.retrofit.response.login.LoginStateResponse>)'
I'm using Java8without Retrolambda.
Changing the compose line to
.compose(this.<LoginStateResponse> RxFunctions.applySchedulers())
results in an error for the LoginState type saying Reference parameters are not allowed here
I'm fairly new to RxJava and grateful for any advice.
Edit: now Android does support java 8
You say you are using Java8 on android, but android does not support Java8 without plugins like retrolambda, so I'll asume that you are actually compiling with Java6 (since Java7 only works for KitKat and above).
In that scenario, you might need to make explicit the parametric type of your applySchedulers. I believe you tried to do that when you wrote this.<LoginStateResponse>, but that would only work if your generic method is inside your current class.
In your case what you actually need is to specify the type on the static method call:
.compose(RxFunctions.<LoginStateResponse>applySchedulers())