Giter VIP home page Giter VIP logo

bolts-android's Issues

AppLink never navigated, Task never returns

W/art﹕ Attempt to remove local SIRT entry from IRT, ignoring
W/art﹕ Attempt to remove local SIRT entry from IRT, ignoring
W/art﹕ Attempt to remove local SIRT entry from IRT, ignoring
W/art﹕ Thread[67,tid=25805,Native,Thread*=0x4f3ef2d8,peer=0x651ab6f8,"Thread-19480"] attached without supplying a name
I/chromium﹕ [INFO:CONSOLE(1)] "Uncaught TypeError: Object [object Object] has no method 'setValue'", source:  (1)

Ultimately resolver#getAppLinkFromUrlInBackground(Uri) gives these logs and the task never returns. Not with an exception, no nothing.

Separate Bolts into 2 Modules for Tasks and AppLinks

I'd like to use the Task pattern in projects where I don't need AppLinks.

e.g. split Bolts into 2 modules:

Bolts/Tasks
Bolts/AppLinks // Depends on Tasks

Publish Bolts/AppLinks with the same Maven identifiers as currently used.

If desired AppLinks could further be split, into a part which does not rely on tasks and another that does:

Bolts/AppLinks
Bolts/Tasks
Bolts/AppLinksTasks // Depends on Tasks and AppLinks

With Bolts/AppLinks containing the core model, and Bolts/AppLinksTasks (or Bolts/AppLinksResolver).
Publish Bolts/AppLinksTasks with the same Maven identifiers as currently used.

If you're open to the idea I can submit a PR.

Add "unobserved" exception handling

An “unobserved” exception is one that’s stored into the task but then never looked at in any way by the consuming code. There are many ways of observing the exception, including Wait()’ing on the Task, accessing a Task’s Result, looking at the Task’s Exception property, and so on. If code never observes a Task’s exception, then when the Task goes away, the TaskScheduler.UnobservedTaskException gets raised, giving the application one more opportunity to “observe” the exception. And if the exception still remains unobserved, the exception escalation policy is then enabled by the exception going unhandled on the finalizer thread.

...exceptions indicate something has gone wrong, and crashing helps developers to immediately identify that the application has entered an unreliable state.

(Source: http://blogs.msdn.com/b/pfxteam/archive/2011/09/28/task-exception-handling-in-net-4-5.aspx)

In .NET, "unobserved" exceptions will bubble up and intentionally crash the application. This would be a useful feature to allow developers to be notified (via a crash) of an "unobserved" exception since it means their application has entered an unreliable state.

Since this would be a breaking change, it might be worthwhile to disable this feature by default and require it to be explicitly turned on by developers.

Basic Use of This Library in Android Studio

I have followed the instructions on the page regarding setting up the compile declarations in Android Studio. Whenever I try to use the sample code listed on the main Readme, all calls with findAsync, saveAsync, and many more are continually popping up with cannot resolve method.

Is there another dependency this library needs to run?
Is there another step to setup this other than the gradle commands?

getting bolts to compile under eclipse

I cloned the bolts android repository to my development machine, and imported the Bolts directory into eclipse (Luna, IIMAD) as an Android project.

In order to get it to compile cleanly, I had to make the following changes:

  • in the android manifest, change the package name from "bolts" to "com.bolts"
  • change the target android level from 8 to 21 (lesser levels may also work; I haven't tried them)
  • in the eclipse propertied for the project, change the java compiler potential null pointer reporting level from "Error" to "Warning"

If these changes are of interest and should be pulled into the github repository (I think they should.), I would be most happy to create a pull request for them.

FWIW, I have read all about github pull requests, but never yet done one. :-( So it might take a bit to get the process right. I have done a gazillion branches / merges / pushes to repo's at the companies I have worked for, but never a github pull request.

Thanks in advance,

Jim Renkel
[email protected]

AppLinkTest#testWebViewAppLinkParsingFailure fails on android-19

It consistently fails on android-19, but not on android-21.

bolts.AppLinkTest > testWebViewAppLinkParsingFailure[Google Nexus 5 - 5.0.0 - API 21 - 1080x1920 - 5.0] SUCCESS 

bolts.AppLinkTest > testWebViewAppLinkParsingFailure[Motorola Moto X - 4.4.4 - API 19 - 720x1280 - 4.4.4] FAILED 
    junit.framework.AssertionFailedError
    at bolts.AppLinkTest.testWebViewAppLinkParsingFailure(AppLinkTest.java:230)

Full output: https://gist.github.com/grantland/7756822e6912f8021202

Exceptions

Hi, do you have any suggestions on how to manage exceptions? I end up getting very short stacktraces that start in Bolts code, and I lose all my context.

What i've started doing is adding ContinueWith calls that look for exceptions, and wrap them.

continueWhile

This is more of a performance or memory leak/resource management item but as far as I can tell the way continueWhile is written will effectively create a chain of tasks that will keep growing each iteration until the loop completes. In a small loop this probably does not matter but in a long running or infinite loop this grows indefinitely until failure.
I believe this can be prevented by using a completion source to manage reporting loop completion and avoiding continueWithTask or related anything that chains the .then's together. The continuation could be rewritten as a Task returning method so returning false ends the loop. the result of each iteration would use continueWith and proxy the error to the task completion source or dispatch the next iteration if result is good.

confusion with creating of async methods

public Task fetchAsync(ParseObject obj) {
final Task.TaskCompletionSource tcs = Task.create();
obj.fetchInBackground(new GetCallback() {
public void done(ParseObject object, ParseException e) {
if (e == null) {
tcs.setResult(object);
} else {
tcs.setError(e);
}
}
});
return tcs.getTask();
}

i'm a bit confused with this code.. how come the tcs is type of Task can be used as return type for the method with return type of Task...i also tried to run this part of code..and it gives me incompatible types error..any explanation will be much appreciated. thanks :)

com.parse.ParseException: bolts.ExecutorException: An exception was thrown by an Executor

Below is my code.
dependencies {
compile 'com.facebook.android:facebook-android-sdk:[4,5)'
compile 'com.parse:parse-android:1.15.7'
compile 'com.parse.bolts:bolts-tasks:1.4.0'
compile 'com.parse.bolts:bolts-applinks:1.4.0'
}
private void appLevel_Lang(final Context cntxt) {

    if (db == null) {
        db = new DataBaseHelper(cntxt);
    }
    try {
        final ParseQuery<ParseObject> query = ParseQuery.getQuery("appSupportedLanguages");
        query.setLimit(100);
      
        Date dbLastUpdatedDate = db.getLastUpdateDateOfTable("appSupportedLanguages");

        if (dbLastUpdatedDate != null) {
            query.whereGreaterThan("updatedAt", dbLastUpdatedDate);
        }
        query.orderByAscending("updatedAt");
        query.findInBackground(new FindCallback<ParseObject>() {
            @Override
            public void done(List<ParseObject> applvl_LangList, ParseException e) {

                if (e == null) {

                    if (applvl_LangList.size() > 0) {
                        String lastUpdatedDate = ParseQueries.getNSDateFormatterUpdateAtForParse().format(applvl_LangList.get(applvl_LangList.size() - 1).getUpdatedAt());

                        for (ParseObject p : applvl_LangList) {
                            AppLevelLanguage appLevelLanguage = new AppLevelLanguage();
                            appLevelLanguage.objectID = p.getObjectId();
                            appLevelLanguage.key = p.getString("key");
                            appLevelLanguage.updatedAt = lastUpdatedDate;
                            ArrayList<String> arrLangColNames = (ArrayList<String>) ParseConfig.getCurrentConfig().get("supportedLanguages");
                            for (String strLangCode : arrLangColNames) {
                                p.getString(strLangCode);
                                appLevelLanguage.langHashMap.put(strLangCode, p.getString(strLangCode));
                            }
                             db.insertOrUpdateAppSupportedLanguageTable(appLevelLanguage);
                        }
                    }
                    if (applvl_LangList.size() == query.getLimit()) {
                        appLevel_Lang(cntxt);
                    } else {
                        Log.d("", "AppSupportedLanguages is not equal to limit");
                    }

                } else {
                    Log.d("AppSupportedLanguages", "Error: " + e.getMessage());
                }
            }
        });
    } catch (Exception e) {
        e.printStackTrace();
    }

}

This is my new Project.The above similar code is running my older project.

Publish releases on maven central

To make it easier for users of the library please publish builds of each release on maven central. This makes it easy to integrate bolts in Android projects with the new gradle-based build system. Maven central then contains also a jar that can be downloaded and directly put into libs directory for older Android projects.

The stacktrace of a wrapped AggregateException excludes the inner exceptions

Printing the stacktrace of a wrapped AggregateException does not include the inner exceptions:

Exception e1 = new RuntimeException("Failure 1");
Exception e2 = new RuntimeException("Failure 2");

Exception aggregate = new AggregateException(Arrays.asList(e1, e2));

aggregate.printStackTrace();
// bolts.AggregateException: There were multiple errors.
//     at bolts.TaskTest.testThing(TaskTest.java:1160)
//     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
//     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
//     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
//     at java.lang.reflect.Method.invoke(Method.java:606)
//     at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
//     at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
//     at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
//     at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
//     at org.junit.rules.ExpectedException$ExpectedExceptionStatement.evaluate(ExpectedException.java:239)
//     at org.junit.rules.RunRules.evaluate(RunRules.java:20)
//     at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
//     at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
//     at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
//     at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
//     at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
//     at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
//     at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
//     at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
//     at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
//     at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
//     at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
//     at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:234)
//     at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:74)
//     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
//     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
//     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
//     at java.lang.reflect.Method.invoke(Method.java:606)
//     at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
// Caused by: java.lang.RuntimeException: Failure 1
//     at bolts.TaskTest.testThing(TaskTest.java:1157)
//     ... 28 more
// 
//   Inner throwable #0: java.lang.RuntimeException: Failure 1
//     at bolts.TaskTest.testThing(TaskTest.java:1157)
//     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
//     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
//     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
//     at java.lang.reflect.Method.invoke(Method.java:606)
//     at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
//     at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
//     at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
//     at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
//     at org.junit.rules.ExpectedException$ExpectedExceptionStatement.evaluate(ExpectedException.java:239)
//     at org.junit.rules.RunRules.evaluate(RunRules.java:20)
//     at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
//     at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
//     at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
//     at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
//     at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
//     at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
//     at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
//     at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
//     at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
//     at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
//     at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
//     at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:234)
//     at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:74)
//     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
//     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
//     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
//     at java.lang.reflect.Method.invoke(Method.java:606)
//     at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
// 
// 
//   Inner throwable #1: java.lang.RuntimeException: Failure 2
//     at bolts.TaskTest.testThing(TaskTest.java:1158)
//     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
//     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
//     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
//     at java.lang.reflect.Method.invoke(Method.java:606)
//     at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
//     at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
//     at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
//     at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
//     at org.junit.rules.ExpectedException$ExpectedExceptionStatement.evaluate(ExpectedException.java:239)
//     at org.junit.rules.RunRules.evaluate(RunRules.java:20)
//     at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
//     at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
//     at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
//     at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
//     at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
//     at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
//     at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
//     at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
//     at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
//     at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
//     at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
//     at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:234)
//     at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:74)
//     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
//     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
//     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
//     at java.lang.reflect.Method.invoke(Method.java:606)
//     at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)

new Exception(aggregate).printStackTrace();
// java.lang.Exception: bolts.AggregateException: There were multiple errors.
//     at bolts.TaskTest.testThing(TaskTest.java:1164)
//     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
//     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
//     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
//     at java.lang.reflect.Method.invoke(Method.java:606)
//     at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
//     at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
//     at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
//     at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
//     at org.junit.rules.ExpectedException$ExpectedExceptionStatement.evaluate(ExpectedException.java:239)
//     at org.junit.rules.RunRules.evaluate(RunRules.java:20)
//     at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
//     at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
//     at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
//     at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
//     at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
//     at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
//     at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
//     at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
//     at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
//     at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
//     at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
//     at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:234)
//     at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:74)
//     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
//     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
//     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
//     at java.lang.reflect.Method.invoke(Method.java:606)
//     at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
// Caused by: bolts.AggregateException: There were multiple errors.
//     at bolts.TaskTest.testThing(TaskTest.java:1160)
//     ... 28 more
// Caused by: java.lang.RuntimeException: Failure 1
//     at bolts.TaskTest.testThing(TaskTest.java:1157)
//     ... 28 more

It seems like the proper way to handle this would be to utilize Throwable#addSuppressed(throwable) instead, but this requires android-19 :(

Return a immutable singleton for `Task.forResult(null)` and `Task.cancelled()`

Currently each call to Task.forResult(null) and Task.cancelled() create new instances of Task and TaskCompletionSource, which are exactly the same for each execution.

These methods can be extremely common in codebases, especially Task.forResult(null), which is used internally in Bolts-Android and Parse-SDK-Android from converting null return values in continuations to stubbing non-asynchronous methods with an asynchronous method signature.

We can optimize these calls by reusing the same value and reduce the amount of memory allocated in applications relying on Bolts and we can do this since each return value is equivalent and essentially immutable.

/cc @nlutsenko

Does anyone have a demo project available?

I'm trying to play around with Bolts-Android and it would be very helpful if someone could direct me towards a demo or a project that uses Bolts-Android.

Thank you! :D

onSuccessInUi() shortcut for onSuccess(..., Task.UI_THREAD_EXECUTOR)?

We often use yours lib for some async operations and after that we inform user about status operation. So almost every time we write something like:

Task.callInBackground(() -> {
    // do something extra heavy
    return someReturnObject;
})
    .onSuccess(new Continuation<SomeReturnObject, Void>() {
        @Override
        public Void then(Task<SomeReturnObject> task) throws Exception {
            Toast.makeText(context, task.getResult().getSomethingNicely(), Toast.LENGTH_SHORT).show();
            return null;
        }
    }, Task.UI_THREAD_EXECUTOR);

As many people we're lazy, forgetful and will be in ecstasy if we can write this in simpler form:

...
.onSuccessInUi(new Continuation<SomeReturnObject, Void>() {
    @Override
    public Void then(Task<SomeReturnObject> task) throws Exception {
        Toast.makeText(context, task.getResult().getSomethingNicely(), Toast.LENGTH_SHORT).show();
        return null;
    }
});

Any thoughts about this idea? 😉

How to stop

I use Boits run asyncMethod like this

Task.callInBackground(new Callable<AuthData>() {
            @Override
            public AuthData call() throws Exception {
                // TODO  network   do  login 
                AuthData data = new AuthData("121212", "23423423");
                Thread.sleep(5000);
                return data;
            }
        }).onSuccess(new Continuation<AuthData, String>() {
            @Override
            public String then(Task<AuthData> result) throws Exception {
                // TODO something other 
                return "success";
            }
        });

But if I dropped out of Activity or want to stop task, what should I do

Bolts conflict with Facebook SDK?

Hi, I'm trying to add the latest Facebook Android SDK from Gradle:

    compile 'com.facebook.android:facebook-android-sdk:4.5.0'

And I get this error:

UNEXPECTED TOP-LEVEL EXCEPTION:
com.android.dex.DexException: Multiple dex files define Lbolts/AggregateException;

Error:Execution failed for task ':app:dexFreeArmeabi-v7aDebug'.
> com.android.ide.common.process.ProcessException: org.gradle.process.internal.ExecException: Process 'command '/Library/Java/JavaVirtualMachines/jdk1.7.0_71.jdk/Contents/Home/bin/java'' finished with non-zero exit value 2

Task.continueWithTask(task) is not supported?

Task<A, B> task0;
Task<B, C> task1;
Task<C, D> task2;
callInChain(task0, task1, task2)
is it more graceful?

if Task.continueWithTask(task) is supported, i can call TaskCompletionSource.setResult() asynchronously

Task.whenAll should return AggregateException on multiple cancelled task

Currently we set the whole Task.whenAll result as cancelled when one of the task is cancelled and there's no error https://github.com/BoltsFramework/Bolts-Android/blob/master/Bolts/src/main/java/bolts/Task.java#L474. This is incorrect since when we consider this scenario

  1. There're 4 Tasks in Task.whenAll.
  2. Two of them are cancelled, two of them succeed.
  3. Task.whenAll will return cancelled.

The correct result should be an AggregateException that contains 2 TaskCancelledException or something similar.

How do I invoke a task on an executor?

If I have some function like this:

Task<Void> doAsync() { // do stuff }}

How do I execute it on an executor? I tried using Call:

return Task.Call(new Callable<Void>() {
      public Void call() throws Exception {
         return doAsync();
     }
});

but obviously that doesn't work, the return type of Call is Task (what I want), but the return type of Callable is Void (not Task).

Thanks! Alex

Are you still updating?

See if you haven't submitted it for a long time. Would you like to ask if you will continue to update this library?

[Nativescript] Plugin Development Help Please

Hello! I just started getting into native app development using NativeScript and I'm attempting to develop a plugin for this repository.

Here are the TypeScript declarations file generated for Bolts-Android:
(Sorry, I would make a gist but there's no TypeScript syntax support 😭 )

/// <reference path="./java.io.PrintStream.d.ts" />
/// <reference path="./java.io.PrintWriter.d.ts" />
/// <reference path="./java.lang.String.d.ts" />
/// <reference path="./java.lang.Throwable.d.ts" />
/// <reference path="./java.util.List.d.ts" />
declare module bolts {
    export class AggregateException exports java.lang.Exception {
        public constructor();
        public constructor(param0: string);
        public constructor(param0: string, param1: java.lang.Throwable);
        public constructor(param0: java.lang.Throwable);
        public constructor(param0: string, param1: native.Array<java.lang.Throwable>);
        public constructor();
        public constructor(param0: string);
        public constructor(param0: string, param1: java.lang.Throwable);
        public constructor(param0: java.lang.Throwable);
        public constructor(param0: string, param1: java.util.List);
        public constructor();
        public constructor(param0: string);
        public constructor(param0: string, param1: java.lang.Throwable);
        public constructor(param0: java.lang.Throwable);
        public constructor(param0: java.util.List);
        public getInnerThrowables(): java.util.List;
        public printStackTrace(): void;
        public printStackTrace(param0: java.io.PrintWriter): void;
        public printStackTrace(param0: java.io.PrintStream): void;
        public printStackTrace(): void;
        public printStackTrace(param0: java.io.PrintStream): void;
        public printStackTrace(param0: java.io.PrintWriter): void;
        public getErrors(): java.util.List;
        public getCauses(): native.Array<java.lang.Throwable>;
    }
}

/// <reference path="./java.lang.Runnable.d.ts" />
/// <reference path="./java.util.concurrent.Executor.d.ts" />
/// <reference path="./java.util.concurrent.ExecutorService.d.ts" />
/// <reference path="./java.util.concurrent.ThreadFactory.d.ts" />
/// <reference path="./java.util.concurrent.ThreadPoolExecutor.d.ts" />
declare module bolts {
    export class AndroidExecutors exports java.lang.Object {
        public static newCachedThreadPool(): java.util.concurrent.ExecutorService;
        public static newCachedThreadPool(param0: java.util.concurrent.ThreadFactory): java.util.concurrent.ExecutorService;
        public static allowCoreThreadTimeout(param0: java.util.concurrent.ThreadPoolExecutor, param1: boolean): void;
        public static uiThread(): java.util.concurrent.Executor;
    }
    export module AndroidExecutors {
        export class UIThreadExecutor exports java.lang.Object {
            public execute(param0: java.lang.Runnable): void;
        }
    }
}

/// <reference path="./java.lang.Runnable.d.ts" />
/// <reference path="./java.util.concurrent.ExecutorService.d.ts" />
declare module bolts {
    export class BoltsExecutors exports java.lang.Object {
        public static background(): java.util.concurrent.ExecutorService;
    }
    export module BoltsExecutors {
        export class ImmediateExecutor exports java.lang.Object {
            public execute(param0: java.lang.Runnable): void;
        }
    }
}

/// <reference path="./bolts.CancellationTokenRegistration.d.ts" />
/// <reference path="./java.lang.Runnable.d.ts" />
declare module bolts {
    export class CancellationToken exports java.lang.Object {
        public isCancellationRequested(): boolean;
        public register(param0: java.lang.Runnable): bolts.CancellationTokenRegistration;
        public throwIfCancellationRequested(): void;
        public toString(): string;
    }
}

declare module bolts {
    export class CancellationTokenRegistration exports java.lang.Object {
        public close(): void;
    }
}

/// <reference path="./bolts.CancellationToken.d.ts" />
declare module bolts {
    export class CancellationTokenSource exports java.lang.Object {
        public constructor();
        public isCancellationRequested(): boolean;
        public getToken(): bolts.CancellationToken;
        public cancel(): void;
        public cancelAfter(param0: number): void;
        public close(): void;
        public toString(): string;
    }
}

/// <reference path="./java.lang.Object.d.ts" />
declare module bolts {
    export class Capture exports java.lang.Object {
        public constructor();
        public constructor();
        public constructor(param0: java.lang.Object);
        public get(): java.lang.Object;
        public set(param0: java.lang.Object): void;
    }
}

/// <reference path="./bolts.Task.d.ts" />
/// <reference path="./java.lang.Object.d.ts" />
declare module bolts {
    export class Continuation exports java.lang.Object {
        public then(param0: bolts.Task): java.lang.Object;
    }
}

/// <reference path="./java.lang.Exception.d.ts" />
/// <reference path="./java.lang.String.d.ts" />
/// <reference path="./java.lang.Throwable.d.ts" />
declare module bolts {
    export class ExecutorException exports java.lang.RuntimeException {
        public constructor();
        public constructor(param0: string);
        public constructor(param0: string, param1: java.lang.Throwable);
        public constructor(param0: java.lang.Throwable);
        public constructor(param0: java.lang.Exception);
    }
}

/// <reference path="./bolts.CancellationToken.d.ts" />
/// <reference path="./bolts.Continuation.d.ts" />
/// <reference path="./bolts.Task.d.ts" />
/// <reference path="./bolts.UnobservedTaskException.d.ts" />
/// <reference path="./java.lang.Exception.d.ts" />
/// <reference path="./java.lang.Object.d.ts" />
/// <reference path="./java.util.Collection.d.ts" />
/// <reference path="./java.util.concurrent.Callable.d.ts" />
/// <reference path="./java.util.concurrent.Executor.d.ts" />
/// <reference path="./java.util.concurrent.ExecutorService.d.ts" />
/// <reference path="./java.util.concurrent.TimeUnit.d.ts" />
declare module bolts {
    export class Task exports java.lang.Object {
        public static getUnobservedExceptionHandler(): bolts.Task.UnobservedExceptionHandler;
        public static setUnobservedExceptionHandler(param0: bolts.Task.UnobservedExceptionHandler): void;
        public static create(): bolts.Task.TaskCompletionSource;
        public isCompleted(): boolean;
        public isCancelled(): boolean;
        public isFaulted(): boolean;
        public getResult(): java.lang.Object;
        public getError(): java.lang.Exception;
        public waitForCompletion(): void;
        public waitForCompletion(param0: number, param1: java.util.concurrent.TimeUnit): boolean;
        public static forResult(param0: java.lang.Object): bolts.Task;
        public static forError(param0: java.lang.Exception): bolts.Task;
        public static cancelled(): bolts.Task;
        public static delay(param0: number): bolts.Task;
        public static delay(param0: number, param1: bolts.CancellationToken): bolts.Task;
        public cast(): bolts.Task;
        public makeVoid(): bolts.Task;
        public static callInBackground(param0: java.util.concurrent.Callable): bolts.Task;
        public static callInBackground(param0: java.util.concurrent.Callable, param1: bolts.CancellationToken): bolts.Task;
        public static call(param0: java.util.concurrent.Callable, param1: java.util.concurrent.Executor): bolts.Task;
        public static call(param0: java.util.concurrent.Callable, param1: java.util.concurrent.Executor, param2: bolts.CancellationToken): bolts.Task;
        public static call(param0: java.util.concurrent.Callable): bolts.Task;
        public static call(param0: java.util.concurrent.Callable, param1: bolts.CancellationToken): bolts.Task;
        public static whenAnyResult(param0: java.util.Collection): bolts.Task;
        public static whenAny(param0: java.util.Collection): bolts.Task;
        public static whenAllResult(param0: java.util.Collection): bolts.Task;
        public static whenAll(param0: java.util.Collection): bolts.Task;
        public continueWhile(param0: java.util.concurrent.Callable, param1: bolts.Continuation): bolts.Task;
        public continueWhile(param0: java.util.concurrent.Callable, param1: bolts.Continuation, param2: bolts.CancellationToken): bolts.Task;
        public continueWhile(param0: java.util.concurrent.Callable, param1: bolts.Continuation, param2: java.util.concurrent.Executor): bolts.Task;
        public continueWhile(param0: java.util.concurrent.Callable, param1: bolts.Continuation, param2: java.util.concurrent.Executor, param3: bolts.CancellationToken): bolts.Task;
        public continueWith(param0: bolts.Continuation, param1: java.util.concurrent.Executor): bolts.Task;
        public continueWith(param0: bolts.Continuation, param1: java.util.concurrent.Executor, param2: bolts.CancellationToken): bolts.Task;
        public continueWith(param0: bolts.Continuation): bolts.Task;
        public continueWith(param0: bolts.Continuation, param1: bolts.CancellationToken): bolts.Task;
        public continueWithTask(param0: bolts.Continuation, param1: java.util.concurrent.Executor): bolts.Task;
        public continueWithTask(param0: bolts.Continuation, param1: java.util.concurrent.Executor, param2: bolts.CancellationToken): bolts.Task;
        public continueWithTask(param0: bolts.Continuation): bolts.Task;
        public continueWithTask(param0: bolts.Continuation, param1: bolts.CancellationToken): bolts.Task;
        public onSuccess(param0: bolts.Continuation, param1: java.util.concurrent.Executor): bolts.Task;
        public onSuccess(param0: bolts.Continuation, param1: java.util.concurrent.Executor, param2: bolts.CancellationToken): bolts.Task;
        public onSuccess(param0: bolts.Continuation): bolts.Task;
        public onSuccess(param0: bolts.Continuation, param1: bolts.CancellationToken): bolts.Task;
        public onSuccessTask(param0: bolts.Continuation, param1: java.util.concurrent.Executor): bolts.Task;
        public onSuccessTask(param0: bolts.Continuation, param1: java.util.concurrent.Executor, param2: bolts.CancellationToken): bolts.Task;
        public onSuccessTask(param0: bolts.Continuation): bolts.Task;
        public onSuccessTask(param0: bolts.Continuation, param1: bolts.CancellationToken): bolts.Task;
        public static BACKGROUND_EXECUTOR: java.util.concurrent.ExecutorService;
        public static UI_THREAD_EXECUTOR: java.util.concurrent.Executor;
    }
    export module Task {
        export class TaskCompletionSource exports bolts.TaskCompletionSource {
        }
        export class UnobservedExceptionHandler exports java.lang.Object {
            public unobservedException(param0: bolts.Task, param1: bolts.UnobservedTaskException): void;
        }
    }
}

/// <reference path="./bolts.Task.d.ts" />
/// <reference path="./java.lang.Exception.d.ts" />
/// <reference path="./java.lang.Object.d.ts" />
declare module bolts {
    export class TaskCompletionSource exports java.lang.Object {
        public constructor();
        public getTask(): bolts.Task;
        public trySetCancelled(): boolean;
        public trySetResult(param0: java.lang.Object): boolean;
        public trySetError(param0: java.lang.Exception): boolean;
        public setCancelled(): void;
        public setResult(param0: java.lang.Object): void;
        public setError(param0: java.lang.Exception): void;
    }
}

/// <reference path="./bolts.Task.d.ts" />
declare module bolts {
    export class UnobservedErrorNotifier exports java.lang.Object {
        public constructor();
        public constructor(param0: bolts.Task);
        public finalize(): void;
        public setObserved(): void;
    }
}

/// <reference path="./java.lang.String.d.ts" />
/// <reference path="./java.lang.Throwable.d.ts" />
declare module bolts {
    export class UnobservedTaskException exports java.lang.RuntimeException {
        public constructor();
        public constructor(param0: string);
        public constructor(param0: string, param1: java.lang.Throwable);
        public constructor(param0: java.lang.Throwable);
    }
}

I'm following the README.md in an attempt to create a Task on a background thread. In the part on creating-async-methods, what class is the new GetCallback() method in?

My basic Task looks like this:

doSomethingAsync() {
    return bolts.Task.call(new bolts.Continuation(class {
        done(t) {
            console.dump(t);
            return t
        }
    }), bolts.Task.BACKGROUND_EXECUTOR)
}

But I get an error, could not resolve method bolts.Task.call.

Does anyone have an experience with TypeScript that can point me in the right direction?

AppLinks.getTargetUrlFromInboundIntent never return targetUrl after app installed

As follow by this doc
https://developers.facebook.com/docs/applinks/android

Application should receive data from deep link, after app has been installed.
But native FB application send to GooglePlay only :
market://details?id=my.app.package&referrer=utm_source=apps.facebook.com&utm_campaign=fb4a&utm_content=%7B%22app%22%3A0%2C%22t%22%3A1436879844%7D
There is no info from deep link

And one first launch I try use in my launch screen next methods
AppLinks.getTargetUrlFromInboundIntent
and AppLinkData.fetchDeferredAppLinkData
but they get me null.

Block of code passed to continueWithTask never gets executed

I've got a small set of users who are encountering and issue where ParseUser.fetchInBackground() appears to never call the subsequent code block passed to continueWithTask. (I realize thats a Parse method, but I think this is Bolts related).

My code looks like this:

  public static Task<Void> check() {
    final Task<Void> timeout = Async.delay(timeoutMs);
    final Task<Void> checkUser = checkUser();

    final ArrayList<Task<?>> tasks = new ArrayList<>();
    tasks.add(timeout);
    tasks.add(checkUser);

    return Task.whenAny(tasks).continueWithTask(new Continuation<Task<?>, Task<SubscriptionCheckerResult>>() {
      @Override
      public Task<SubscriptionCheckerResult> then(Task<Task<?>> wrapperTask) throws Exception {
         // ...
      }
    }, Task.BACKGROUND_EXECUTOR);
  }

  public static Task<Void> checkUser() {
    final ParseUser user = ParseUser.getCurrentUser();
    return user.fetchInBackground().onSuccessTask(new Continuation<ParseObject, Task<Void>>() {
      @Override
      public Task<Void> then(Task<ParseObject> task) throws Exception {
         // ...   
      }
    }, Task.BACKGROUND_EXECUTOR);
  }

And for a small percentage of users the code seems to never return from user.fetchInBackground.

(Related: a number of months back I adopted the practice of always specifying an executor, and changed a bunch of code to use the BACKGROUND_EXECUTOR, and caused a similar issue, and was unable to figure it out, so I reverted the change).

I've also added code which in the case of a timeout, adds a .continueWith call to the checkUser variable, and logs when it ultimately fails or succeeds, and in most cases it doesn't do either.

JetBrains kotlin problems

Tris simple code does not work in kotlin language

Task.create<String>().setResult("ggg")

IDE says:

Type mismatch.
Required: TResult 
Found: kotlin.String

May be you should declare TaskCompletionSource as non-internal class?

RejectedExecutionException

Perhaps I have misunderstood the documentation for Tasks, but I am having an issue with a maximum number of Tasks. In the doc it says:

They are independent of threading model, so you don't have to worry about reaching the maximum number of allowed threads, as can happen with AsyncTask.

I assumed this meant I could start as many Tasks as I wanted and the queue would be dealt with. Is that incorrect?

One user has a large (414) backlog of operations that need to be run. I have a service that processes each of these using Tasks. When starting all of these Tasks, I get the following exception:

java.util.concurrent.RejectedExecutionException: Task a.e@44efb458 rejected from java.util.concurrent.ThreadPoolExecutor@45252e88[Running, pool size = 9, active threads = 9, queued tasks = 128, completed tasks = 1]
    at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2011)
    at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:793)
    at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1339)
    at a.c.a(SourceFile:194)
    at a.c.a(SourceFile:186)
    at com.example.uploader.DataUploadService.getUploadTask(SourceFile:304)
    at com.example.uploader.DataUploadService.uploadData(SourceFile:264)
    at com.example.uploader.DataUploadService.dataUpload(SourceFile:182)
    at com.example.uploader.DataUploadService.onAPIServiceResponse(SourceFile:115)
    at com.example.api.d.a(SourceFile:157)
    at com.c.a.a.a.b.b.a(SourceFile:74)
    at com.c.a.a.a.b.b.onPostExecute(SourceFile:1)
    at android.os.AsyncTask.finish(AsyncTask.java:632)
    at android.os.AsyncTask.access$600(AsyncTask.java:177)
    at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:645)
    at android.os.Handler.dispatchMessage(Handler.java:102)
    at android.os.Looper.loop(Looper.java:212)
    at android.app.ActivityThread.main(ActivityThread.java:5151)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:515)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:878)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
    at dalvik.system.NativeStart.main(Native Method)

Where the function "uploadData" is:

private void uploadData(fileName) {
    getUploadTask(fileName).continueWith(new Continuation<Boolean, Void>() {
        @Override
        public Void then(Task<Boolean> task) throws Exception {
            boolean success = task.getResult();
            ...
            return null;
        }
    });
}

and "getUploadTask" is:

public static Task<Boolean> getUploadTask(final String fileName) {
    return Task.callInBackground(new Callable<Boolean>() {
        @Override
        public Boolean call() throws IOException {
            File f = new File(fileName);

            Boolean success = false;
            if (f.isFile()) {
                success = uploadFile(f);
            }
            return success;
        }
    });
}

Should I just implement my own queue around the Tasks?
Thanks.

Execute Bacground Task in parallel.

In Task
I want to run the Task.callInBackground in parallel manner(like in Async,pasrse.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR))). after that continueWithTask in serial manner((like in Async,pasrse.executeOnExecutor(AsyncTask.SerialExecutor)))).

i am changing the executor to achive the above behavoiour
Executors.newCachedThreadPool(),Executors.newFixedThreadPool(15),Executors.newSingleThreadExecutor().
Both the task are run in serial manner(Task and then continueWithTask and then Task......).

Task<String> task = Task.callInBackground(new Callable<String>()
        {
            @Override
            public String call() throws Exception
            {
                String response = null;
                try {
                    System.out.println("Bolt url send " + request.url);
                    response = singleton.load(request);
                } catch (IOException e) {
                    if (request.callback != null && request.handler == null)
                        singleton.handler.onLoadFailed(request.callback);
                    else if (request.callback != null)
                        request.handler.onLoadFailed(request.callback);
                } 
                return response;
            }
        }).continueWithTask(new Continuation<String, Task<String>>()
        {
            @Override
            public Task<String> then(final Task<String> task) throws Exception
            {
                System.out.println("Bolt url recieved " + task.getResult());
                parse(request, task.getResult());
                return null;
            }
        },Executors.newSingleThreadExecutor());

How to achive the above behaviour using Bolt FrameWork.
Thanks.

Easier way to unit test background Tasks

This is a suggestion:
It'd be great to be able, in unit tests, to run all the tasks on the UI thread, even the ones that were set up to run on a background thread. This would make testing code with Tasks easier.

Right now, the solution to unit test some code where a background Task is to set up a custom background executor and change it during tests. See https://medium.com/@trionkidnapper/unit-testing-asynchronous-tasks-from-bolts-android-e780f02bf1be#88c7

API 19 DUPLICATE ENTRY

When I change API 23 to 19 send this Error

Error:Execution failed for task ':app:transformClassesWithJarMergingForDebug'.

com.android.build.api.transform.TransformException: java.util.zip.ZipException: duplicate entry: com/parse/AbstractQueryController$1.class

compile 'com.parse:parse-android:1.13.1'
compile 'com.parse.bolts:bolts-android:1.3.0'

Getting OOM

Fatal Exception: java.lang.OutOfMemoryError: Could not allocate JNI Env at java.lang.Thread.nativeCreate(Thread.java) at java.lang.Thread.start(Thread.java:731) at java.util.concurrent.ThreadPoolExecutor.addWorker(ThreadPoolExecutor.java:941) at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1348) at bolts.Task.call(SourceFile:348) at bolts.Task.callInBackground(SourceFile:321) at com.touchtalent.bobbleapp.services.BobbleKeyboard.refreshStickerSuggestionCache(SourceFile:1122) at com.touchtalent.bobbleapp.services.BobbleKeyboard.onCodeInput(SourceFile:2629) at com.android.inputmethod.keyboard.PointerTracker.callListenerOnCodeInput(SourceFile:423) at com.android.inputmethod.keyboard.PointerTracker.detectAndSendKey(SourceFile:1421) at com.android.inputmethod.keyboard.PointerTracker.onUpEventInternal(SourceFile:1294) at com.android.inputmethod.keyboard.PointerTracker.onUpEvent(SourceFile:1234) at com.android.inputmethod.keyboard.PointerTracker.processMotionEvent(SourceFile:778) at com.android.inputmethod.keyboard.MainKeyboardView.processMotionEvent(SourceFile:845) at com.android.inputmethod.keyboard.MainKeyboardView.onTouchEvent(SourceFile:832) at android.view.View.dispatchTouchEvent(View.java:10723) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2865) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2550) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2865) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2550) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2865) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2550) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2865) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2550) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2865) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2550) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2865) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2550) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2865) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2550) at com.android.internal.policy.DecorView.superDispatchTouchEvent(DecorView.java:559) at com.android.internal.policy.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1870) at android.app.Dialog.dispatchTouchEvent(Dialog.java:1057) at android.inputmethodservice.SoftInputWindow.dispatchTouchEvent(SoftInputWindow.java:147) at com.android.internal.policy.DecorView.dispatchTouchEvent(DecorView.java:521) at android.view.View.dispatchPointerEvent(View.java:10952) at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:5117) at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:4969) at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4500) at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:4553) at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4519) at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:4652) at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4527) at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:4709) at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4500) at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:4553) at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4519) at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4527) at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4500) at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:7007) at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:6936) at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:6897) at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:7117) at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:185) at android.view.InputEventReceiver.nativeConsumeBatchedInputEvents(InputEventReceiver.java) at android.view.InputEventReceiver.consumeBatchedInputEvents(InputEventReceiver.java:176) at android.view.ViewRootImpl.doConsumeBatchedInput(ViewRootImpl.java:7081) at android.view.ViewRootImpl$ConsumeBatchedInputRunnable.run(ViewRootImpl.java:7144) at android.view.Choreographer$CallbackRecord.run(Choreographer.java:927) at android.view.Choreographer.doCallbacks(Choreographer.java:702) at android.view.Choreographer.doFrame(Choreographer.java:632) at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:913) at android.os.Handler.handleCallback(Handler.java:751) at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Looper.loop(Looper.java:154) at android.app.ActivityThread.main(ActivityThread.java:6682) at java.lang.reflect.Method.invoke(Method.java) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1520) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1410)

Task.BACKGROUND_EXECUTOR is badly defined and prone to lockups

This follows parse-community/Parse-SDK-Android#646 where we found a possible bug in the executor, and would also propose some changes.

Bug?

It is told in comments that

Creates a proper Cached Thread Pool. Tasks will reuse cached threads if available or create new threads until the core pool is full. tasks will then be queued. If an task cannot be queued, a new thread will be created unless this would exceed max pool size, then the task will be rejected. Threads will time out after 1 second.

This is strictly true but practically not with the blocking queue that is being used (LinkedBlockingQueue with infinite capacity). If I got this correctly, with that queue tasks can always be queued, so the max number of threads you’ll have is the core pool. maxPoolSize has no effect. So this

ThreadPoolExecutor executor =  new ThreadPoolExecutor(
       CORE_POOL_SIZE,
       MAX_POOL_SIZE,
       KEEP_ALIVE_TIME, TimeUnit.SECONDS,
       new LinkedBlockingQueue<Runnable>());

should become

ThreadPoolExecutor executor =  new ThreadPoolExecutor(
       CORE_POOL_SIZE,
       MAX_POOL_SIZE,
       KEEP_ALIVE_TIME, TimeUnit.SECONDS,
       new LinkedBlockingQueue<Runnable>(SOME_NUMBER));

also official docs from ThreadPoolExecutor about queues:

Using an unbounded queue (for example a LinkedBlockingQueue without a predefined capacity) will cause new tasks to wait in the queue when all corePoolSize threads are busy. Thus, no more than corePoolSize threads will ever be created. (And the value of the maximumPoolSize therefore doesn't have any effect.) This may be appropriate when each task is completely independent of others, so tasks cannot affect each others execution.

Queue strategy

Using the terminology from oracle site, the current strategy (despite the comments) is the unbounded queue, which fits the case of tasks completely independent of others. You will agree this is not bolts case. Can we move to the first strategy?

I can read in comments that the bolts executor was designed trying to emulate the AsyncTask executor. But AsyncTasks are independent by design, can afford a big queue.
Bolts Task are dependent, chained, nested, and the docs suggest a different strategy for this design. We are experiencing lockups in the Parse SDK that you can read in the linked issue (there’s a huge comment explaining the internals). We can block the Task.BACKGROUND_EXECUTOR forever very easily, in situations like the following, when running concurrently the same action:

BACKGROUND_EXECUTOR pool (max 7 threads for 6 processors)
|- background-executor-thread-1 (needs another background thread to complete)
|- background-executor-thread-2 (needs another background thread to complete)
|- background-executor-thread-3 (needs another background thread to complete)
|- background-executor-thread-4 (needs another background thread to complete)
|- background-executor-thread-5 (needs another background thread to complete)
|- background-executor-thread-6 (needs another background thread to complete)
|- background-executor-thread-7 (needs another background thread to complete)

With 2 processors, this takes 3 concurrent actions to have the executor hang. I don’t think this is fixable from outside bolts, because

  • Tasks promote chaining, nesting and dependencies and that’s how you build upon them
  • It’s impossible to get rid of the BACKGROUND_EXECUTOR and use another, because the background executor is the fallback executor of ImmediateExecutor. You can mention a custom executor in every task call, but that’s bad performance wise because you lose the simplicity of ImmediateExecutor and don’t reuse threads.

I propose to move the queuing strategy towards the direct handoffs strategy:

Direct handoffs. A good default choice for a work queue is a SynchronousQueue that hands off tasks to threads without otherwise holding them. Here, an attempt to queue a task will fail if no threads are immediately available to run it, so a new thread will be constructed. This policy avoids lockups when handling sets of requests that might have internal dependencies.

Proposals:

// direct handoff with limited max pool size
// this fits better bolts design
ThreadPoolExecutor executor =  new ThreadPoolExecutor(
       CORE_POOL_SIZE,
       BIG_NUMBER, // 64?
       KEEP_ALIVE_TIME, TimeUnit.SECONDS,
       new SynchronousQueue<Runnable>());

or

// bounded queue with a small value
ThreadPoolExecutor executor =  new ThreadPoolExecutor(
       CORE_POOL_SIZE,
       BIG_NUMBER, // 32?
       KEEP_ALIVE_TIME, TimeUnit.SECONDS,
       new LinkedBlockingQueue<Runnable>(VERY_SMALL_NUMBER));

Using a big queue would have no effect on lockups. If there are 7 core threads needing other 7 threads to complete (as in my example), and the queue can hold 128 commands, this won’t be solved. We would have to wait for 128 requests to hang before having the first resolved. Ideally, VERY_SMALL_NUMBER < CORE_POOL_SIZE to ensure at least a request is fulfilled.

Parallel execution with different tasks types

In the example provided for parallel execution, all tasks are the same type. Is there a way to do this with different tasks types and check the results for those tasks on the continuation?

ParseQuery<ParseObject> query = ParseQuery.getQuery("Comments");
query.whereEqualTo("post", 123);

findAsync(query).continueWithTask(new Continuation<List<ParseObject>, Void>() {
  public Task<Void> then(List<ParseObject> results) throws Exception {
    // Collect one task for each delete into an array.
    ArrayList<Task<Void>> tasks = new ArrayList<Task<Void>>();
    for (ParseObject result : results) {
      // Start this delete immediately and add its task to the list.
      tasks.add(deleteAsync(result));
    }
    // Return a new task that will be marked as completed when all of the deletes are
    // finished.
    return Task.whenAll(tasks);
  }
}).onSuccess(new Continuation<Void, Void>() {
  public Void then(Void ignored) throws Exception {
    // Every comment was deleted.
    return null;
  }
});

Progress in whenAll() and whenAllResult()

HELLo moto ;)

Is there any possibility to have a "progress listener" to completion of whenAll() and whenAllResult() methods? For now we have only onSuccess(new Continuation<TTaskResult, TContinuationResult>()) listener that is indicated when all tasks are completed. But I want to show progress indicator to user and can't get the idea how to do that.

edit:
Ok, we can do that in that way

tasksList.add(
    Task.callInBackground(() -> {
        // do something extra heavy
        return someDoubleResult;
    }));
...

final Capture<Integer> currentProgress = new Capture<>(0);
final int progressCount = tasksList.size();

for (Task<Double> taskWithFinish : tasksList) {
    taskWithFinish.onSuccess(task -> {
        currentProgress.set(currentProgress.get() + 1);
        updateProgress((float) currentProgress.get() / progressCount);
        return task.getResult();
    });
}

Task.whenAllResult(tasksList)
    .onSuccess(new Continuation<List<Double>, Void>() {
        @Override
        public Void then(Task<List<Double>> task) throws Exception {
            // close progress indicator
            return null;
        }
    }, Task.UI_THREAD_EXECUTOR);

Will be nice to do that in simpler way, eg.

tasksList.add(
    Task.callInBackground(() -> {
        // do something extra heavy
        return someDoubleResult;
    }));
...

Task.whenAllResult(tasksList)
    .onProgress(new Progress<Double>() {
        @Override
        public void onProgress(Task<Double> task, int finishedTaskNr, int tasksSumCount) {
            updateProgressBar((float) finishedTaskNr /  tasksSumCount);
        }
    })
    .onSuccess(new Continuation<List<Double>, Void>() {
        @Override
        public Void then(Task<List<Double>> task) throws Exception {
            // close progress indicator
            return null;
        }
    }, Task.UI_THREAD_EXECUTOR);

Application context

Hi all, but if initialized from application context, the uri web intent not start.
Add Flag intent for new task?

Question: how to handle activity rotation / re-creation lifecycle with Tasks?

Hi,

This is not a bug, nor a feature request. This is a question.

Bolts seems a very nice library, but I do not really understand how you pictured its usage along with the Android lifecycle.

Suppose I do obtain a Task:

Task<MyResult> myTask = ....;

Now I want to somehow link that task to my UI (show a spinner before showing the result or things like this).

I have to maintain that task across activity recreation.

  • Placing it in static variable is bad practice.
  • I can create a Loader, but then why do I need a task? My loader will just wait for the result and give me it
  • I can associate my task to the ApplicationContext (instead of the activity) and modify the database or a shared preference and update the UI: it's a lot more work then with a loader that does the thing

I'm sure you considered this while developing bolts, how am I supposed to retain the Task, or at least a callback to it across activity instances (destroy/recreate cycle)?

Thanks

README needs to be updated

Although bolts.Task.TaskCompletionSource is now deprecated on the newest release version, if you follow the way the README tells you to declare it using the older version of the library, it makes IDE warn you just like the screenshot below. (using bolts version 1.1.2.)

tcs

I will use the latest version of the library so it is not a huge problem for me, but I guess README either needs to state what classes are deprecated from now on, or temporarily explain how to declare tcs with the newest version of the library and maybe with older versions as well?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.