Third Party Technologies
This topic briefly explains the third party libraries used in the Android mobile app of Hello Thing-IF.
You can skip this topic if you do not need to get information further as these technologies are out of the scope of Kii Cloud. Search general technical information on the Internet for more information.
Using promises through JDeferred
You need to call any APIs that access Kii Cloud from a worker thread because those APIs take some time to complete.
All the APIs of the Thing-IF SDK for Android are blocking APIs which do not return control to the caller until the process is complete. The entire mobile app would freeze when the main thread goes into wait mode for a response via network because it is the main thread that handles the user interface in Android. To avoid this problem, create a worker thread and call any blocking API within the worker thread.
Hello Thing-IF uses JDeferred to automate API call in the worker thread.
To use the Thing-IF SDK, you need to use the Kii Cloud SDK together. Hello Thing-IF consistently uses blocking APIs although the Kii Cloud SDK supports both blocking and non-blocking APIs.
Non-blocking APIs create worker threads within the SDK and return the result with a callback method. See the Learn More section at the end of this topic for more information.
For example, suppose you want to call this blocking API to execute a command.
try {
Command command = mApi.postNewCommand(HelloThingIF.SCHEMA_NAME, HelloThingIF.SCHEMA_VERSION, actions);
Log.i("CommandID: " + command.getCommandID());
} catch (Throwable tr) {
tr.printStackTrace();
}
The above call can be rewritten to use a promise through JDeferred as below.
First, enable postNewCommand()
to execute in a worker thread. To execute the desired process in a worker thread, use an API wrapper as in PromiseAPIWrapper.java of the sample app and add the process to the doInBackgroundSafe
method.
public Promise<Command, Throwable, Void> postNewCommand(final String schemaName, final int schemaVersion, final List<Action> actions) {
return mAdm.when(new DeferredAsyncTask<Void, Void, Command>() {
@Override
protected Command doInBackgroundSafe(Void... voids) throws Exception {
return mApi.postNewCommand(schemaName, schemaVersion, actions);
}
});
}
The caller of postNewCommand()
(CommandFragment.java of the sample app) calls methods of AndroidDeferredManager
for asynchronous processing as below. Add the processes on success and failure in the onDone()
and onFail()
methods, respectively.
AndroidDeferredManager mAdm = new AndroidDeferredManager();
PromiseAPIWrapper api = new PromiseAPIWrapper(mAdm, mApi);
mAdm.when(api.postNewCommand(HelloThingIF.SCHEMA_NAME, HelloThingIF.SCHEMA_VERSION, actions)
).then(new DoneCallback<Command>() {
@Override
public void onDone(Command command) {
Log.i("CommandID: " + command.getCommandID());
}
}).fail(new FailCallback<Throwable>() {
@Override
public void onFail(final Throwable tr) {
tr.printStackTrace();
}
});
Implementation with JDeferred might look very complicated but most of the lines are just the overheads of asynchronous processing. For example, application logic in the above code is limited to the small parts colored in the below figure and the remaining parts are the overheads to use JDeferred. In order to implement promises to execute any processes, all you need to do is to rewrite the colored parts.
See the below sequence diagram for the process execution. AndroidDeferredManager internally creates a thread and calls the doInBackgroundSafe
method. An API of the Kii Cloud SDK or the Thing-IF SDK is executed as a blocking API in the worker thread and the user can operate the screen.
The onDone()
method or the onFail()
method is called after the process is complete. Now the main thread has control and you need no exclusive processing with other user interface processes.
The benefit of using promises is reduced complexity in execution of consecutive asynchronous processes. Chaining API calls with promises does not complicate the program unlike the so-called "callback hell" without promises. Hello Thing-IF simply uses promises just as a framework of asynchronous processing as Hello Thing-IF does not need to chain API calls. If you use promises on a full scale, refer to the Learn More section below.
Using AsyncTask
You can also 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 {
// Do something with the worker thread
mApi.postNewCommand(HelloThingIF.SCHEMA_NAME, HelloThingIF.SCHEMA_VERSION, actions);
} catch (Exception e) {
final Exception exception = e;
handler.post(new Runnable() {
@Override
public void run() {
// Do something with the main thread
mTextViewMessage.setText("Error: " + exception.getLocalizedMessage());
}
});
}
return null;
}
}.execute();
}
}
This sample code executes mApi.postNewCommand()
in a worker thread. When an error occurs, the main thread gets control and manipulates the user interface based on the information in exception
.
Review the following lines in the sample code. As with JDeferred, many lines are just the overheads for asynchronous processing.
final List<Action>…
is processed in the main thread. It is declared final based on the Java language specification in order to passactions
as a parameter to thedoInBackground
method which is executed in a worker thread.mApi.postNewCommand()
is the blocking API to execute in a worker thread.mTextViewMessage.setText()
is executed in the main thread when an exception occurs. You need to call Android APIs which manipulate the user interface in the main thread. Use thepost()
method of the Handler class to switch from a worker thread to the main thread.exception
is also declared final because it is passed torun()
.
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 mobile app by pasting the above sample code and replacing the three lines with your own lines.
Using Butter Knife
Hello Thing-IF uses Butter Knife to simplify the implementation of user interface.
Butter Knife is used for the following two purposes:
- Bind user interface parts to fields of classes
- Bind buttons to methods of listeners
Use the @BindView
annotation when you declare fields as below to bind user interface parts to fields of classes. You do not need to conventionally call findViewById()
.
@BindView(R.id.textEdit1)
TextEdit myTextEdit;
Use the @OnClick
annotation in a method as below to bind buttons to listeners. You do not need to conventionally call setOnClickListener()
nor prepare listner classes.
@OnClick(R.id.buttonExecute)
void onExecuteClicked() {
}
After the above preparation, execute ButterKnife.bind()
in initialization and unbind()
in post-processing.
private Unbinder mButterknifeUnbunder;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
...
mButterknifeUnbunder = ButterKnife.bind(this, view);
...
}
@Override
public void onDestroyView() {
super.onDestroyView();
mButterknifeUnbunder.unbind();
}
Hello Thing-IF uses the above code in LoginFragment and CommandFragment.
What's next?
The next topic explains initialization of the mobile app in the HelloThingIF class.
Go to Application Class Implementation.
If you want to learn more...
- See Blocking API in the Thing-IF SDK Development Guide for an overview of how to implement JDeferred.
- You can use promises with the Kii Cloud SDK for JavaScript as well. See the tutorial for the Kii Cloud SDK to learn about how to use promises.
- The Kii Cloud SDK for Android supports both blocking and non-blocking APIs. See Blocking vs. Non-Blocking API for more information.
- Access the website of Butter Knife for more information about Butter Knife. If you incorporate Butter Knife into a new project, access the repository on GitHub, which has more information than the website.