Search code examples
androidtaskbolts-framework

Android Bolts Task: Complex Task in separate class with TaskCompletionSource


I am having issues understanding the documentation about Bolts Task framework. I am heavily using this in a complex Android project which requires writing more complex tasks. How can I achieve this along with TaskCompletionSource so I can set the result of the task? Where to put the code that is to be executed in background?

One draft of an example of a task that I am using:

public class CheckInternetConnectionTask {
    private static final String  TAG                   = "CheckInternetConnReq";
    private static       Date    mLastCheckDate        = null;
    private static       Boolean mLastConnectionStatus = null;
    private static       int     mConnectionAttempts   = 0;

    private Context mContext;

    public CheckInternetConnectionTask(Context context) {
        this.mContext = context;
    }

    public void resetConnectionStatus() {
        mLastCheckDate = null;
        mLastConnectionStatus = null;
        mConnectionAttempts = 0;
    }

    public Task<Boolean> getTask() {
        return Task.callInBackground(new Callable<Boolean>() {
            @Override
            public Boolean call() throws Exception {
                Log.i(TAG, "Checking for internet connection...");
                Calendar calendar = Calendar.getInstance();

                Date currentDate = calendar.getTime();

                if (mLastCheckDate == null) {
                    mLastCheckDate = calendar.getTime();
                }

                if (mLastConnectionStatus != null && getDifferenceInSeconds(currentDate, mLastCheckDate) < 5) {
                    Log.i(TAG, "Last checked < 5 seconds, returning previous value: " + mLastConnectionStatus);
                    if (mConnectionAttempts < 10) {
                        mConnectionAttempts ++;

                        return mLastConnectionStatus;
                    }

                    Log.i(TAG, "Resetting connection check attempt counter to 0, checking for internet connection...");
                    mConnectionAttempts = 0;
                }

                ConnectionDetector connectionDetector = new ConnectionDetector(mContext);

                mLastCheckDate = currentDate;
                mLastConnectionStatus = connectionDetector.isConnected();

                return mLastConnectionStatus;
            }
        });
    }

    private long getDifferenceInSeconds(Date currentDate, Date savedDate) {
        long diffInMillisec = currentDate.getTime() - savedDate.getTime();

        return TimeUnit.MILLISECONDS.toSeconds(diffInMillisec) % 60;
    }
}

Assuming that the class above is used in my code, then the call is:

final CheckInternetConnectionTask checkConectionTask = new CheckInternetConnectionTask(this);
checkConectionTask.getTask().onSuccess(new Continuation<Boolean, Object>() {
    @Override
    public Object then(Task<Boolean> task) throws Exception {
        // This can never be used:
        if (task.isFaulted()) {
            // TODO: Notify user that something went wrong
        } else {        
            mCardNoConnection.setVisibility(task.getResult() ? View.GONE : View.VISIBLE);
        }
        return null;
    }
}, Task.UI_THREAD_EXECUTOR);

In this way there is no way for me to access the task.getError() method because there is no completion source defined. How can I properly use this framework if I have complex objects in their own classes?

Another option is to completely avoid the TaskCompletionSource object and return some kind of custom Task State object that will contain the task result along with custom isError and Exception properties. But this is not as elegant as using TaskCompletionSource.


Solution

  • It seems like the problem you're experiencing is that you're using #onSuccess(Continuation) instead of #continueWith(Continuation). onSuccess's Continuation will only be called when the source task resolves successfully. If you change it to continueWith, the Continuation will be called when the source task resolves to success, failure, or cancelled.