Pass parameter to gradle Exec task - android

I have defined a simple Gradle task of type Exec and I'm trying to pass a parameter to that task when calling it from another task.
How does one do that ?

It isn't possible to call a task from another task. Instead, declare two tasks and make one depend on the other. (Calling the internal task.execute() method is unsupported, and its behavior is undefined.) For cases where having a second task isn't feasible, there is a project.exec {} method, which has exactly the same API as the task.

As it has been pointed out my initial approach was flawed and not "the gradle way". So after carefully rethinking the problem I turned everything upside down and now I "just" loop through my arguments and in turn execute the code for each argument.
Case here is a list of languages that each will be used as an argument in a command line.
task multiCommands << {
def lang = languages.split()
lang.each { locale ->
def output = exec {
commandLine "my command that takes an argument", locale
}
}
}

Related

onSuccessTask vs addOnSuccessListener?

I'm using Google Firestore for by Android database and want to know the different between onSuccessTask and addOnSuccessListener.
For example, here is me updating a Firestore document:
val doc = db.collection("books").document(book).update(data)
For the above, to take action when the update completes, I can do either:
.onSuccessTask { } or .addOnSuccessListener { }
which to me, yields the exact same result.
Can someone clear up what the difference is and which one should be used?
There are three flavours of Task's addOnSuccessListener() method which are:
addOnSuccessListener(Executor executor, OnSuccessListener listener):
Adds a listener that is called if the Task completes successfully.
addOnSuccessListener(OnSuccessListener listener):
Adds a listener that is called if the Task completes successfully.
addOnSuccessListener(Activity activity, OnSuccessListener listener):
Adds an Activity-scoped listener that is called if the Task completes successfully.
And two flavours of Task's onSuccessTask() method whic are:
onSuccessTask(Executor executor, SuccessContinuation successContinuation):
Returns a new Task that will be completed with the result of applying the specified SuccessContinuation to this Task when this Task completes successfully.
onSuccessTask(SuccessContinuation successContinuation):
Returns a new Task that will be completed with the result of applying the specified SuccessContinuation to this Task when this Task completes successfully.
As you can probably see, the main difference is that, in case of addOnSuccessListener() the object that is returned is of type abstract Task<TResult>, so everytime you use it, you'll need to provide an implementation for that while when using onSuccessTask() method, the type of object that is returned is <TContinuationResult> Task<TContinuationResult> (which is not abstract).
Basically, you would use addOnSuccessListener when you just want to work with the result, while onSuccessTask can be used with other methods such as continueWith or continueWithTask in order to chain tasks.
Here's an article about chaining tasks.

Can I always merge two conditions into one row in Kotlin?

The Code A is good, I hope to optimize it, so I write the Code B.
I'm not sure whether the Code B is always correct.
It will be OK if Kotlin check clipboard.hasPrimaryClip() first, then check clipboard.primaryClipDescription.hasMimeType(MIMETYPE_TEXT_PLAIN) next.
It maybe crash if Kotlin check clipboard.primaryClipDescription.hasMimeType(MIMETYPE_TEXT_PLAIN) first, the check clipboard.hasPrimaryClip() next, right?
Code A
clipboard.addPrimaryClipChangedListener {
if (clipboard.hasPrimaryClip() ) {
if (clipboard.primaryClipDescription.hasMimeType(MIMETYPE_TEXT_PLAIN)) {
}
}
}
Code B
clipboard.addPrimaryClipChangedListener {
if (clipboard.hasPrimaryClip() && clipboard.primaryClipDescription.hasMimeType(MIMETYPE_TEXT_PLAIN) ) {
}
}
if conditions run sequentially. That means it will first check the left condition and if the operator is AND and left condition return false then it won't check the right condition. So yes, you can merge two conditions.
As mentioned in the comments, the principle behind this is described as "short circuiting":
Short-circuit evaluation [...] is the semantics of some Boolean operators in some programming languages in which the second argument is executed or evaluated only if the first argument does not suffice to determine the value of the expression.
That means clipboard.hasPrimaryClip() will always be evaluated. If it's false
, the condition fails without looking any further. If it is true though, clipboard.primaryClipDescription.hasMimeType(MIMETYPE_TEXT_PLAIN) will be evaluated as well.

Pass parameter to gradle task

I have multiple tasks. I run a task from command line via : gradle tasks.gradle TaskA -Pparam1=value1 -Pparam2=value2
TaskA calls TaskB via : tasks.TaskB.execute().
How can I pass parameters to this task programatically?
As in this comment, please do not call execute on task directly. Not only it may spoil the task dependency graph but this is also not the case that task action is always mapped to execute method.
To read the properties in the task, use:
project.findProperty("<PROPERTY_NAME>")
It returns null if property is missing or value if it was passed.

How to create custom tasks for Firebase using the Google Play services Task API

I'd like to create custom tasks like these ones in firebase in order to chain my API async calls. How can I achieve that?
There are a few ways to create a custom task using the Play services Task API.
First, there is Tasks.call(Callable). The Callable you pass is scheduled for immediate execution on the main thread, and you get a Task in return, with a generic parameter of the return type of the Callable. This Task resolves successfully with that return value, or an error if the Callable throws an exception.
The other method is Tasks.call(Executor, Callable), which is exactly like the other method, except the given callable is scheduled for immediate execution on a thread managed by the given Executor. It's up to you to find or create an Executor that's appropriate for your work.
Lastly, there is also TaskCompletionSource, which lets you create a Task and manually resolve it to success or failure from the result of some other item of work not directly related to a Task.
For more details, check out my blog series on Tasks. I cover these methods in part three and part four.
Suppose you have a Document class, you could do as follow:
Create successfuly resolved task
Tasks.<Document>forResult(document);
Create a failed task
Tasks.forException(new RuntimeException("Cool message"));
Create from Callable
interface CreateDocument extends Callable<Document> {
#Override
Document call();
}
Tasks.call(new CreateDocument());
Create using task completion source
Task<Document> createDocument() {
TaskCompletionSource<Document> tcs = new TaskCompletionSource();
if (this.someThingGoesWrong()) {
tcs.setException(new RuntimeException("Cooler message"));
} else {
tcs.setResult(Document.factory());
}
tcs.getTask();
}

Google Play services Task API: continueWith vs continueWithTask

This is about Task.
What's the difference between task.continueWith() and task.continueWithTask(), can you provide an example for each one?
The primary difference between continueWith and continueWithTask is one of the generic types of the Continuation you pass to it.
You can think of a Continuation as something that converts some input type to some output type. If you define a Continuation<IN, OUT>, where IN is the input type passed to its then method via a Task<IN>, and OUT is the type that method returns.
When calling continueWith, you pass a Continuation<IN, OUT>, and the then method is expected to compute and return the OUT value given a Task<IN> value as input. You might choose to do this if you don't have any blocking work to do for the conversion, such as reducing an integer array to the sum of its elements or counting the number of words in a String.
When calling continueWithTask, you pass a Continuation<IN, Task<OUT>>, and the then method is expected to return a Task<OUT> that eventually generates the OUT value, given the IN value as input. You might choose this if you are able to delegate the conversion work to an existing reusable Task.
Practically speaking, you aren't required to choose one or the other to do your work. It's a matter of preferred style, or if you have a nice Task ready to delegate your conversation rather than a Continuation. Typically you only use a Continuations if you have a pipeline of conversions to chain together.
The javadoc links here show some examples of Continuations. Also, to learn more, you can read about them in part three of my blog series. To be fair, continueWithTask is the only part of the Task API I don't directly discuss anywhere in that series, mostly because conceptually it doesn't differ very much from continueWith.
Just to add to what Doug said, I would put it like this:
continueWith will wrap the result of the then method in a Task. continueWithTask will not; it expects the then method to return a Task, and thus avoids the double wrapping of a task within a task.
continueWithTask is perfect when you want to use a Continuation and a TaskCompletionSource together.
I'd like to add, that continueWith and continueWithTask really got me into trouble, obviously because I did not truly understand the API, but also did the naming confuse me. Maybe an example of my failure can prevent others from doing the same.
tl;dr
When to use which method:
Use continueWith if you want to use the result of the previous task and return a new result within your Continuation's then method. And you need to hand it over to some other continuation or use it afterwards in listeners. The return value of continueWith is a Task that just WRAPS your return value of the then method.
Use continueWithTask if you want to use the result of the previous task,
and somewhat use it in a new task, that you create within your Continuation's then method. The return value of continueWithTask is a task that YOU create inside of then and has an own generic result.
Do NOT return a task in your continuation's then and use it with continueWith. It might compile and execute for years without a warning, but also without doing it's job.
IF you directly append a listener after continueWith, this listener
will give you a task THAT ONLY WRAPS the result of your then return
value. If this return value is a task itself, do not expect it to be
executed(!!!).
Long story!
I had a calling chain like this:
private Task<SomeResult> getTask() {
PreloadingTask.create().continueWith(additionalTask()).addOnCompleteListener(task -> {
if (task.isSuccessful()) {
source.setResult(someResult);
} else {
source.setException(new Exception());
}
});
return source.getTask();
}
So as you can see, additionalTask() must return some sort of Continuation<IN, OUT>, that implements the method then as
#Override
public OUT then(Task<IN> task){ ... }};
In my case I did not need to check for OUT, because I just wanted to do some additional computations AFTER the PreloadingTask was done and forwards it's result to my additionalTask() continuation.
I wanted to execute the task from additionalTask(), and afterwards the onCompleteListener should have been called.
private Continuation<PreviousResult, Task<Void>> additionalTask() {
return task -> {
PreviousResult r = task.getResult();
simpleResultModification(r);
return new AdditionalTask(r);
);
};
}
What happend? The onCompleteListener was called directly, because my then method got executed and returned it's result, which was an instance of AdditionalTask.
This AdditionalTask then got wrapped into another task and handed over for the onCompleteListener as the result.
And my AdditionalTask got never executed.
That's why you should use continueWithTask if you return a task, within then.
There's a big difference between continueWith() and continueWithTask() related to task cancellation.
More info here - Task API docs.
continueWith() : If the previous Task is canceled, the returned Task will also be canceled and the Continuation would not execute.
continueWithTask() : If the previous Task is canceled, the Continuation would still execute and task.isCanceled() is true can be observed in the Continuation.

Categories

Resources