Blocking API

The Thing-IF SDK only provides blocking APIs. We encourage you to execute the APIs through some framework like JDeferred or feature in the Android SDK provided for asynchronous processing.

Some methods of the Kii SDKs require network communication with Thing Interaction Framework and cause some delay. Such methods include those for registering a new user and sending a command to a thing. Generally, Kii provides these methods in two ways: as blocking APIs and as non-blocking APIs. For the difference between the two types of API designs, see Blocking vs. Non-Blocking API.

The following summarizes the APIs supported by each SDK.

  • The Thing-IF SDK provides only blocking APIs.

  • The Kii Cloud SDK provides both blocking and non-blocking APIs.

Executing a blocking API in the main thread will cause the user interface to freeze, so you need to either use any asynchronous processing technology including the ones discussed in this topic or create a working thread and execute the blocking API from this thread.

Using JDeferred

You can operate Promise-based asynchronous processing on Android by using JDeferred. Using JDeferred will prevent the main thread from freezing. It will also make your codes clearer by freeing it from so-called "callback hell".

In this section, we will present how you can use JDeferred in the sample code shown in the guide.

This guide just briefly explains the basics of the JDeferred since it is used in the Thing-IF sample code. Please refer other technical websites for the detailed information, such as how to integrate JDeferred and how to code with the Promise mechanism. Please note that using the JDeferred is an option and not mandatory for providing the asynchronous processing with the Thing-IF SDK.

API example

We will use the following simple API example. All APIs in the example represent blocking APIs that will take more than 1 sec to execute. These APIs correspond to the APIs provided by the Thing-IF SDK.

class Result1 {
  public String value1;
}

class Result2 {
  public String value2;
}

class API {
  public static Result1 api1(String a) {
    sleep(1000);
    Result1 result = new Result1();
    result.value1 = a;
    return result;
  }

  public static Result2 api2(String a) {
      sleep(1000);
      Result2 result = new Result2();
      result.value2 = a;
      return result;
  }

  public static void api3(String a) {
    sleep(1000);
    System.out.println(a);
  }

  private static void sleep(int timeInMs) {
    try {
      Thread.sleep(timeInMs);
    } catch (InterruptedException e) {
    }
  }
}

The goal is to execute the methods like this. This sample code is written with blocking APIs, but what we want to implement is to execute them asynchronously using promises.

API api = new API();
Result1 result1 = api.api1("abcd");
Result2 result2 = api.api2(result1.value1);
api.api3(result2.value2);

Defining promises

The following sample code shows how you can code the execution of the API.api1(), API.api2(), and API.api3() methods with JDeferred. We are defining the methods to be executed asynchronously in the doInBackgroundSafe() method.

private AndroidDeferredManager mAdm;

private Promise<Result1, Throwable, Void> executeApi1(final String input) {
  return mAdm.when(new DeferredAsyncTask<Void, Void, Result1>() {
    @Override
    protected Result1 doInBackgroundSafe(final Void... params) throws Exception {
      return API.api1(input);
    }
  });
}

private Promise<Result2, Throwable, Void> executeApi2(final String input) {
  return mAdm.when(new DeferredAsyncTask<Void, Void, Result2>() {
    @Override
    protected Result2 doInBackgroundSafe(final Void... params) throws Exception {
      return API.api2(input);
    }
  });
}

private Promise<Void, Throwable, Void> executeApi3(final String input) {
  return mAdm.when(new DeferredAsyncTask<Void, Void, Void>() {
    @Override
    protected Void doInBackgroundSafe(final Void... params) throws Exception {
      API.api3(input);
      return null;
    }
  });
}

AndroidDeferredManager is a class of JDeferred. In this example, we are saving it in the class's field (we will later explain the initialization procedure).

In the sample code, the methods, executeApi1() to executeApi3(), are defined and are executed inside the doInBackgroundSafe() method of the DeferredAsyncTask class. The types used in the methods are as follows:

  • The type of the method's return value: Promise<Result1, Throwable, Void> and so on.

    • The first parameter Result1 is the value returned from the asynchronously executed process. Its type will be the same as that of the doInBackgroundSafe() method's return value.
    • The second parameter is fixed with Throwable. You cannot change it.
    • The third parameter is the type you want to use for showing the progress. We are setting Void because we are not showing any progress. If you want to show the progress numerically, for example, you can set Integer.
  • The parameter of the method: final String input and so on.

    You can freely set any method parameters. Please specify the parameters required by the target API.

  • The type of DeferredAsyncTask: DeferredAsyncTask<Void, Void, Resul1> and so on.

    • The first parameter is fixed to Void. You cannot change it.
    • The second parameter is the type you want to use for showing the progress. It should match with the type of the promise.
    • The third parameter Result1 is the value returned from the asynchronously executed process. The type will be the same as that of the doInBackgroundSafe() method's return value.
  • The return value of doInBackgroundSafe() method: Result1 and so on.

    The value returned from the asynchronously executed process. The mobile application can freely set any value.

  • The parameter of the doInBackgroundSafe() method: final Void... params

    This is always set as final Void... params.

  • The method's throws: throws Exception

    You can use any exception type.

Sequential method execution with promises

The following sample code shows how you can execute methods sequentially with promises.

mAdm = new AndroidDeferredManager();
mAdm.when(executeApi1("abcd")
).then(new DonePipe<Result1, Result2, Throwable, Void>() {
  @Override
  public Promise<Result2, Throwable, Void> pipeDone(Result1 result) {
    return executeApi2(result.value1);
  }
}).then(new DoneCallback<Result2>() {
  @Override
  public void onDone(Result2 result) {
    executeApi3(result.value2);
  }
}).fail(new FailCallback<Throwable>() {
  @Override
  public void onFail(final Throwable tr) {
    tr.printStackTrace();
  }
});

Put a promise that you want to execute first in the when() method. The then() method is executed when the promise is successful. The fail() method is executed otherwise.

Use the DonePipe if you want to pipe the result from the previous promise to the next promise. Use the DoneCallback to define the process to be executed upon the successful execution.

The most recent fail() method is executed when the exception occurs in the method. You can also aggregate the exception handling as shown in the above sample code.

Using promises with the Thing-IF SDK

Sample code in the Thing-IF SDK guide is presented with a blocking API in a try block, like this one:

List<Action> actions = new ArrayList<Action>();

TurnPower action1 = new TurnPower();
action1.power = true;
actions.add(action1);

try {
  Command command = api.postNewCommand("AirConditioner-Demo", 1, actions);
} catch (ThingIFException e) {
  // Handle the error.
}

The sample code changes as follows if a promise is used:

Promise<Command, Throwable, Void> getState(final boolean power) {
  return adm.when(new DeferredAsyncTask<Void, Void, Command>() {
    @Override
    protected Command doInBackgroundSafe(Void... voids) throws Exception {
      List<Action> actions = new ArrayList<Action>();

      TurnPower action1 = new TurnPower();
      action1.power = power;
      actions.add(action1);

      return api.postNewCommand("AirConditioner-Demo", 1, actions);
    }
  });
}

Using AsyncTask

You can implement asynchronous processing by directly using the Android SDK without JDeferred. For example, create a worker thread with the AsyncTask class and call a blocking API inside the thread. See the sample code below.

void test() {
  final List<Action> actions = new ArrayList<Action>();
  ...
  new AsyncTask<Void, Void, Void>() {
    final Handler handler = new Handler();
      @Override
      protected Void doInBackground(Void... params) {
        try {
          Command command = api.postNewCommand("AirConditioner-Demo", 1, actions);
        } catch (Exception e) {
          final Exception exception = e;
          handler.post(new Runnable() {
            @Override
            public void run() {
              // Handle the error in the main thread.
            }
          });
        }
        return null;
      }
    }.execute();
  }
}

This sample code executes the api.postNewCommand() method in the worker thread. When an error occurs, the main thread gets control and manipulates the user interface based on the information in the exception.

Review the following lines in the sample code. As with JDeferred, many lines are the overheads for asynchronous processing.

  • final List<Action>… is processed in the main thread. It is declared final based on the Java language specification to pass the actions as a parameter to the doInBackground() method which is executed in the worker thread.
  • In the doInBackground() method, write the process that you want to execute in the worker thread. The api.postNewCommand() method is the body to be executed in the worker thread.
  • In the run() method, write the process that you want to execute in the main thread when an exception occurs. You need to call Android APIs in the main thread to manipulate the user interface. Use the post() method of the Handler class to switch from the worker thread to the main thread. The exception is declared final because it is passed to the run() method.

The only three lines explained above serve for the functionality of your mobile app and the remaining lines make a fixed set of statements to switch the threads. You can achieve asynchronous processing in your program by pasting the above sample code and replacing the three lines with your own lines.