目次
- はじめに
- 実装方法
- まとめ
はじめに
本記事では、KonyのThreading APIについてデモを用いて解説いたします。
まず**スレッド(Thread)**とは、プログラムが実行されていく一連の流れのことです。
この流れは通常一本ですが、処理に時間がかかる重たい処理を実行する時などには、複数の流れを用意しないと詰まってしまう(ユーザのアクションに対応できない、別の処理が実行できない)場合もあります。
例えば、以下のような処理は複数のスレッドによって成り立っています。
- ブラウザを使用中、HTMLを読み込んでいる途中でも、戻るボタンを押せる
- 重いファイルをダウンロードしている時に、ダウンロードの進行度が表示される
Konyでは kony.runOnMainThread、kony.runOnWorkerThreadというAPIを用いて、使用するスレッドを指定して処理を実行することができます。
それでは、APIの詳細について説明していきます。
kony.runOnMainThread
非同期のAPIで、メインスレッドでJavaScriptコードを実行するのに使用します。
パラメータ | 説明 |
---|---|
f [Function]【必須】 | 実行するコールバック関数を指定します。 |
args [Array]【必須】 | f に渡されるパラメータを保持するJavaScript配列を指定します。 |
kony.runOnWorkerThread
メインの処理と並行して実行できるマルチスレッドを提供するAPIです。
パラメータ | 説明 |
---|---|
f [Function]【必須】 | 実行するコールバック関数を指定します。 |
args [Array]【必須】 | f に渡されるパラメータを保持するJavaScript配列を指定します。 |
Konyでは、スレッドAPIを使用するためのガイドラインが以下のように記載されています。
・スレッドAPIは、マルチスレッド環境をネイティブにサポートします。
・アプリケーションは、複数の並行スレッドで構成できます。
・メインスレッド(UIスレッド)は、ウィジェットにイベントを割り当てて、UIの要素を描画する役割を果たします。
・メインスレッド(UIスレッド)が止まるような処理はNGです。メインスレッドでネットワークアクセスやデータベースクエリなどの時間のかかる操作を実行すると、ユーザーインターフェイスがブロックされます。
・メインスレッド(UIスレッド)の外部からUIコンポーネントにアクセスしないでください。
JavaScriptスレッド:
・UIの更新を必要としないJavaScriptで記述されたアプリケーションロジックは、メインスレッドまたはUIスレッドとは異なるスレッドで実行されます。・UIを更新する操作は、メインスレッドまたはUIスレッドに投稿されます。
・API kony.runOnMainThread(function、args)を使用して、UIスレッドでJavaScriptバインディングとJavaScriptロジックを実行します。
注意:下記の場合は、非同期ではなく同期モードで実行されます。
例)
- Mainスレッド上でrunOnMainThread()を実行した時
- Workerスレッド上でrunOnWorkerThread()を実行した時
APIの説明は以上なので、 次に、デモを用いて実際の挙動について見てみましょう。
作成したデモ
実際にrunOnMainThread()、runOnWorkerThread()を使って、
以下の処理を各スレッドで実行してログを見ていきたいと思います。
- Mainスレッド: ラベルの変更
- Workerスレッド: 終了まで5秒かかる処理
まず、デモ用にFormを作成し、ラベル : lblMain と ボタン : btnRun を配置しました。
紹介する2つのAPIは iOS/Android用なので、Mobileで作成します。
以下は、FromControllerに記載したソースです。
define({
onClickBtn : function() {
① kony.print("___onClick");
kony.runOnMainThread(this.mainFunction, [this.view.lblMain]);
② kony.print("___finish_onClick");
},
wokerFunction : function() {
// 時間のかかる処理
④ kony.print("___start_workerThread");
var dt1 = new Date().getTime();
var dt2 = new Date().getTime();
var dtDiff = 0;
var count = 0;
// 5秒後に処理終了
while (dtDiff < 5000){
dt2 = new Date().getTime();
dtDiff = dt2 - dt1;
//2.5秒経過ごとにログを出力
if(dtDiff % 2500 === 0){
count++;
⑤ ⑦ kony.print("___count_workerThread : " + count);
}
}
⑧ kony.print("___finish_workerThread");
},
mainFunction : function(widget) {
kony.runOnWorkerThread(this.wokerFunction, [this.view.lblMain]);
// テキストを変更する
③ kony.print("___start_mainThread");
widget.text = "【 Main Thread 】";
⑥ kony.print("___finish_mainThread");
},
});
wokerFunction
では、WhileとDate().getTime()
※現在時刻の取得
を使って、5秒後に終了する処理を書いています。
また、進捗がわかるように2.5秒に一回ログを出力させています。
mainFunction
では、MainスレッドからrunOnWorkerThreadを呼び出して、
その後 引数として受け取っているLabelのテキストを変更する処理を書いています。
出力されるログ
ボタン押下後、Android StudioのLogcatで確認すると以下のようなログが出力されます。
MainとWorkerに分けて見てみましょう。
- 黄色い枠が Mainスレッドで実行されている処理
- 赤い枠が 別スレッドで実行されている処理
ログについての説明
使用されているスレッドをログから確認することができます。
2021-06-21 15:54:08.834 12941-12965/com.orgname.appp D/StandardLib: ___onClick
ログメッセージの形式は次のとおりです。
date time PID-TID/package priority/tag: message
使用スレッドは、ログの PID-TID の部分で確認することができます。
PIDとTIDが同じ場合は基本となるスレッド(メインスレッド)が使用されています。
PID はプロセス ID の略で、TID はスレッド ID の略です。スレッドが 1 つしか存在しない場合、これらは同一になることがあります
https://developer.android.com/studio/debug/am-logcat?hl=ja
解説
①・②
onClickBtn : function() {
① kony.print("___onClick");
kony.runOnMainThread(this.mainFunction, []);
② kony.print("___finish_onClick");
},
①ボタン押下によって___onClick
が出力されます。
②kony.runOnMainThread()は非同期のため、次に___finish_onClick
が出力されます。
※ controller内のonClickBtn
で出力しているログは、メインではなくrunOnWorkerThread
で使われるスレッドと同様のスレッドが使われるようです。
③〜⑧
まず、Workerスレッドとは別スレッド(Mainスレッド)から、kony.runOnWorkerThread
を呼び出しているため非同期モードとなり、Workerスレッドの処理を待たずに③が実行されています。
mainFunction : function(widget) {
kony.runOnWorkerThread(this.wokerFunction, []);
// テキストを変更する
③ kony.print("___start_mainThread");
widget.text = "【 Main Thread 】";
⑥ kony.print("___finish_mainThread");
},
その後、並行してwokerFunction
が実行され、④・⑤が出力されます。
次はmainFunction
の処理が終了することで⑥が出力されて、wokerFunction
にある残りの⑦・⑧が出力されます。
wokerFunction : function() {
// 時間のかかる処理
④ kony.print("___start_workerThread");
var dt1 = new Date().getTime();
var dt2 = new Date().getTime();
var dtDiff = 0;
var count = 0;
// 5秒後に処理終了
while (dtDiff < 5000){
dt2 = new Date().getTime();
dtDiff = dt2 - dt1;
//2.5秒経過ごとにログを出力
if(dtDiff % 2500 === 0){
count++;
⑤ ⑦ kony.print("___count_workerThread : " + count);
}
}
⑧ kony.print("___finish_workerThread");
},
デモの説明は以上です。
: 注意 :
はじめにの最後でもご紹介いたしましたが、controller内のメソッドでの処理は、runOnWorkerThreadで使われるスレッドと同様のスレッドが使われるようでした。
今回はMainスレッドの中で呼び出しましたが、
普通にrunOnWorkerThread()を実行すると、以下の理由から同期モードで実行されてしまうので、中身が全て実行されるまで待機状態になってしまいます。
使用の際は、使用元のメソッドがどのスレッドで実行されているかを確認しましょう。
注意:下記の場合は、非同期ではなく同期モードで実行されます。
例)
- Mainスレッド上でrunOnMainThread()を実行した時
- Workerスレッド上でrunOnWorkerThread()を実行した時
まとめ
今回はkony.runOnMainThread、kony.runOnWorkerThreadというAPIの使用説明・解説をいたしました。本記事がお役に立てば幸いです。
参考