How do I call Kotlin functions with lambdas in the parameter from a Java class.
Example
fun getToken(
tokenUrl: String,
onSuccess: (String) -> Unit,
onError: (Error) -> Unit
): Provider {
//Implementation
}
You can do this
value.getToken("url",
new Function1<String, Unit>() {
#Override
public Unit invoke(String s) {
/* TODO */
return Unit.INSTANCE;
}
}, new Function1<Throwable, Unit>() {
#Override
public Unit invoke(Throwable throwable) {
/* TODO */
return Unit.INSTANCE;
}
});
You can call it with normal Java 8 lambdas, since Kotlin is actually using a single-method interface on the backend.
myFoo.getToken(tokenUrl, successString -> { ... }, error -> { ... });
This is for calling it within Kotlin, the question was edited to say "from Java" after I provided my answer. Leaving it here anyway in hope that it is useful.
You can call it like this
fun test() {
getToken("asdf", { print(it) }, { println(it) })
getToken("asdf", { print(it) }) { err -> println(err) }
getToken("asdf", ::println, ::println)
getToken("asdf", ::println) { println(it) }
}
Related
In scala, there is a trait like
trait Client {
def get(requests: Seq[Request]): Future[Seq[Response]]
}
How to implement the class in Java with some fake implementation like return Future.successful(List.empty())?
I tried
class KVClient implements Client {
#Override
public Future<Seq<Response>> get(Seq<Request> requests) {
return Future.successful(List.empty());
}
But it didn't compile. Error is "KVClient is not abstract and does not override abstract method get(Seq) in Client"
if i understood you correctly you are trying to return result or error of response future.
Simple solution would be:
public CompletableFuture<Optional<?>> send() throws ExecutionException, InterruptedException {
final CompletableFuture<Optional<?>> optionalCompletableFuture = CompletableFuture.supplyAsync(() -> "")
.thenApplyAsync(f -> {
if (isError(f)) {
return Optional.empty();
}
return Optional.of(f);
});
return optionalCompletableFuture;
}
Unfortunately, my REST Delete operation work only for one item. So what I was trying to do is,
Observable.just(items).flatMapIterable { items -> items }.flatMap {
//call REST DELETE for every item
}.flatMap {
// call REST GET
}
The problem is the GET call is being called for every item. How can I wait for finishing all the delete done and then perform the GET call?
Thanks in Advance.
In your case, you can apply toList() like this
fun doTask(items: List<String>):Observable<Boolean>{
return Observable.fromIterable(items)
.flatMap { processItem(it) }
.toList()
.toObservable()
.flatMap { finalTask() }
}
The problem can be solved with zip. In case any wants this
fun doTask(items: ArrayList<String>): Observable<Boolean> {
val list = arrayListOf<Observable<String>>()
items.forEach {
list.add(processItem(it))
}
return Observable.zip(list) {
}.flatMap {
finalTask()
}
}
fun processItem(s: String): Observable<String> {
print(s)
return Observable.just(s.toUpperCase())
}
fun finalTask(): Observable<Boolean> {
print("final")
return Observable.fromCallable { true }
}
Observable.just("one", "two", "three", "four", "five").subscribe(new Consumer<String>() {
#Override
public void accept(String s) throws Exception {
Log.d("ffff", s);//print: one, two, three, four, five
}
}, new Consumer<Throwable>() {
#Override
public void accept(Throwable throwable) throws Exception {
}
}, new Action() {
#Override
public void run() throws Exception {
Log.d("ffff", "complete");//print: complete
}
});
I had the following Java code:
public class DatabaseManager {
public interface Predicate<T> {
boolean test(T t);
}
private interface Consumer<T> {
void apply(T t);
}
private void updateLiveLists() {
updateLiveLists(liveList -> true);
}
private void updateLiveLists(Predicate<MutableLiveList<?>> predicate) {
forEachLiveList(liveList -> {
if (predicate.test(liveList)) {
refresh(liveList);
}
});
}
private void forEachLiveList(Consumer<MutableLiveList<?>> consumer) {
...
}
Then I used Java -> Kotlin conversion in Android Studio:
class DatabaseManager {
interface Predicate<T> {
fun test(t: T): Boolean
}
private interface Consumer<T> {
fun apply(t: T)
}
private fun updateLiveLists(predicate: Predicate<MutableLiveList<*>> = { liveList -> true }) {
forEachLiveList({ liveList ->
if (predicate.test(liveList)) {
refresh(liveList)
}
})
}
private fun forEachLiveList(consumer: Consumer<MutableLiveList<*>>) {
...
}
Fails with the following error:
Type mismatch
Required: DatabaseManager.Consumer<MutableLiveList<*>>
Found: (???) -> Unit
Now I had to change code to following:
private fun updateLiveLists(predicate: Predicate<MutableLiveList<*>> = object : Predicate<MutableLiveList<*>> {
override fun test(t: MutableLiveList<*>): Boolean {
return true;
}
}) {
forEachLiveList(object : DatabaseManager.Consumer<MutableLiveList<*>> { // <--- !!
override fun apply(t: MutableLiveList<*>) {
if (predicate.test(t)) {
refresh(t)
}
}
})
}
Okay, so I had to explicitly declare this anonymous interface as an explicit subclass of object, as for whatever reason Kotlin couldn't figure out the lambda.
If it helps, I have the same problem occurring in a function below it:
fun refresh(vararg tables: Table) {
updateLiveLists({ liveList ->
for (table in tables) {
if (liveList.getTable() === table) {
return#updateLiveLists true
}
}
false
})
}
Which says:
Type Mismatch:
Required: DatabaseManager.Predicate<MutableLiveList<*>>
Found: ??? -> Boolean
And I have to do this instead
fun refresh(vararg tables: Table) {
updateLiveLists(object: DatabaseManager.Predicate<MutableLiveList<*>> { // <--
override fun test(t: MutableLiveList<*>): Boolean {
for (table in tables) {
if (t.getTable() === table) {
return true
}
}
return false
}
})
}
Why, and how can I avoid this? How can I use my own Predicate/Consumer without Kotlin getting confused about the lambda type?
Thanks to /u/lupajz I now know that the problem is that interfaces defined in Kotlin are not converted by the SAM conversion because of https://discuss.kotlinlang.org/t/kotlin-and-sam-interface-with-two-parameters/293/5
Basically it boils down to
"why would you do it this way when you can use Kotlin's functional interfaces and type-aliases instead; if you need this then define the interfaces in Java".
There are a few workarounds:
1.) inline objects (which is what I showed above as part of the question)
2.) type aliases + exposing overloaded methods
private typealias KotlinPredicate<T> = (T) -> Boolean;
private typealias KotlinConsumer<T> = (T) -> Unit;
class DatabaseManager {
private interface Consumer<T> {
fun apply(t : T) : Unit;
}
private fun forEachLiveList(consumer: Consumer<MutableLiveList<*>>) {
forEachLiveList({
consumer.apply(it)
})
}
private fun forEachLiveList(consumer: KotlinConsumer<MutableLiveList<*>>) {
...
}
and
interface Predicate<T> {
fun test(t : T) : Boolean;
}
fun updateLiveLists(predicate: Predicate<MutableLiveList<*>>) {
updateLiveLists({
predicate.test(it)
})
}
fun updateLiveLists(predicate: KotlinPredicate<MutableLiveList<*>> = { liveList -> true }) {
forEachLiveList({ liveList ->
if (predicate.invoke(liveList)) {
refresh(liveList)
}
})
}
how do i write in Kotlin like java?
Callback callback= new Callback()
{
#Override
public void getCallback(ServerResponse serverResponse) {
}
}
var callback:Callback = object:Callback() {
override fun getCallback(serverResponse:ServerResponse) {
}
}
var callback:Callback says that the variable type is a Callback
object:Callback() { } is an anonymous class. It has no name when created, before being assigned to var callback. It's similar to the new Callback() code.
override replaces #Override
fun indicates that it is a function
You can use following code in Kotlin.
var callback:Callback = object:Callback() {
fun getCallback(serverResponse:ServerResponse) {
}
}
You can use this link to convert your Java code to kotlin.
https://try.kotlinlang.org
I want to wrap retrofit api call in another method where I can additionally show/hide loader, check for network etc. As my api returns observable, the way I ended up is below:
private <T> Observable<T> request(final Observable<T> apiCall, final ViewManager viewManager) {
return Observable.create(new Action1<Emitter<T>>() {
#Override
public void call(final Emitter<T> emitter) {
if (!NetworkUtils.isConnected(context)) {
emitter.onError(new ConnectException("network not connected"));
return;
}
viewManager.showLoader();
apiCall.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<T>() {
#Override
public void onCompleted() {
viewManager.hideLoader();
emitter.onCompleted();
}
#Override
public void onError(Throwable e) {
viewManager.hideLoader();
emitter.onError(e);
}
#Override
public void onNext(T response) {
emitter.onNext(response);
}
});
}
}, Emitter.BackpressureMode.BUFFER);
}
Is this a standard way of dealing with the problem? How do you wrap an observable inside another observable? Can anyone guide?
the idiomatic way with reactive extensions is to use composition, and this is one of the great powers of RX.
first let's define the desired behaviors using operators, what you want is something like this:
apiCall
.observeOn(AndroidSchedulers.mainThread())
.startWith(Observable.defer(() -> {
if (!NetworkUtils.isConnected(context)) {
return Observable.error(new ConnectException("network not connected"));
} else {
return Observable.empty();
}
}))
.doOnSubscribe(() -> viewManager.showLoader())
.doOnCompleted(() -> viewManager.hideLoader())
.doOnError(throwable -> viewManager.hideLoader());
now, for composing it to any network apiCall Observable, you can use compose() operator and encapsulate this logic into Transformer for that:
class CustomTransformer<T> implements Observable.Transformer<T, T> {
private final ViewManager viewManager;
private final Context context;
CustomTransformer(ViewManager viewManager, Context context) {
this.viewManager = viewManager;
this.context = context;
}
#Override
public Observable<T> call(Observable<T> apiCall) {
return apiCall
.observeOn(AndroidSchedulers.mainThread())
.startWith(Observable.defer(() -> {
if (!NetworkUtils.isConnected(context)) {
return Observable.error(new ConnectException("network not connected"));
} else {
return Observable.empty();
}
}))
.doOnSubscribe(() -> viewManager.showLoader())
.doOnCompleted(() -> viewManager.hideLoader())
.doOnError(throwable -> viewManager.hideLoader());
;
}
}
then you can compose it with any network Observable:
someRetrofitQuery
.compose(new CustomTransformer<>(viewManager, context))
...
.subscribe();