少し前にQtにおけるAndroidのサービスとスレッドの作成 -Qtで作るAndroid目覚ましもどき #6-1-を書いたが、それからしばらくして改造をしていたら2点ほど気付きというかネタを見つけたので書きます。
というか2つのネタのうち2つ目のネタを調べてたら1つ目のネタを見つけたというわけです。つまりは下記が参考にしたページ。
気付き/トピック
- サービスとアクティビティのオブジェクトを同じにする方法
これまでサービスとアクティビティのオブジェクトを別々にする方法しかわからなかったが、同じにする方法を見つけた。これでプロジェクトの構成が楽になった。 - Qt 5.10ではQAndroidService じゃないと起動しないっぽい
Qt5.9まではQCoreApplicationでできたんだけど
サービスとアクティビティを同じオブジェクトにする
まずAndroidManifest.xmlで別々にしていたオブジェクト(ライブラリというべき?)を同じものにする。すなわち私のコードでは下記。
:
<activity android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation" android:name="org.qtproject.qt5.android.bindings.QtActivity" android:label="-- %%INSERT_APP_NAME%% --" android:screenOrientation="unspecified" android:launchMode="singleTop">
:
<meta-data android:name="android.app.lib_name" android:value="summer_clock"/>
:
</activity>
:
<service android:process=":qt" android:name="com.summer.test.Spring">
:
<meta-data android:name="android.app.lib_name" android:value="ice_clock"/>
:
</service>
:
から、↓ へ
:
<activity android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation" android:name="org.qtproject.qt5.android.bindings.QtActivity" android:label="-- %%INSERT_APP_NAME%% --" android:screenOrientation="unspecified" android:launchMode="singleTop">
:
<meta-data android:name="android.app.lib_name" android:value="summer_ice"/>
:
</activity>
:
<service android:process=":qt" android:name="com.summer.test.Spring">
:
<meta-data android:name="android.app.lib_name" android:value="summer_ice"/>
:
</service>
:
別にアクティビティとサービスのどちらかのライブラリに統一するだけでもいいが、私の場合は、summer_clockと名付けた親プロジェクトからsummer_clockとice_clockの2つのプロジェクトをつくりライブラリもつくっていた状態から、子プロジェクトを廃止して親プロジェクト1つに統合したので上記のような変更になる。
そして当然、こうなるとライブラリを起動させられたときにアクティビティとサービスそれぞれに流さないといけないので、main()を下記のようにする。
int main(int argc, char *argv[])
{
if(argc > 1 && strcmp(argv[1], "-service") == 0) {
qInfo() << "Summer_Ice::Service starting...";
return ice_clock(argc, argv);
} else {
qInfo() << "Summer_Ice::Activity starting...";
return summer_clock(argc, argv);
}
}
ice_clock()とsummer_clock()の中はそれぞれサービスとアクティビティを開始する処理であり、これ自体は特別なことはない、これまで書いた内容なので説明しません。
こう条件分岐できるのはおそらくなんですが下記にAndroidManifest.xmlに書いてある下記のおかげなのでしょう。
<meta-data android:name="android.app.arguments" android:value="-service"/>
Qt 5.10ではQAndroidService じゃないと起動しないっぽい
2017年末にようやく動くレベルになってから2018年の5月の連休に社畜が休みを取って改造していたときに、Qtを5.9から5.10にあげたら下記な感じで動かなくなった。
E/ActivityManager( 1553): 9.1% TOTAL: 1% user + 6.1% kernel + 2% iowait
I/ActivityManager( 1553): Killing 3006:org.qtproject.example:qt/u0a58 (adj 0): bg anr
ANR……Application Not Responding? なにそれーって感じで別に処理同じだしそんな重くないしで困り果ててネットの海を漂っていたところ冒頭のページを発見。
結論としては下記のまま。
So the solution seems to be using Qt 5.10.1 with QAndroidService instead of QCoreApplication.
というわけで下記のように変更する。
// サービス
int ice_clock(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
:
}
から ↓ へ
// サービス
int ice_clock(int argc, char *argv[])
{
# ifdef __ANDROID__
QAndroidService app(argc, argv);
# else
QCoreApplication app(argc, argv);
# endif
:
}
QAndroidServiceはAndroidアプリ用のコンパイルじゃないとコンパイルできないので、WindowsやLinuxで画面確認するために__ANDROID__
で分けておく。(Android以外ではサービス起動しないからコンパイルさえ通ればなんだけど)
せっかくなのでgoogleの翻訳と英文を見比べながら読んでみるが、どうやら、QCoreApplicationでは?QAndroidServiceのプライベートなセマフォを触りに行って固まりANRになる、だからQAndroidServiceはだめ、でもQt5.10.0ではQAndroidServiceでもANRになっていて、Qt5.10.1ではなおったっぽいけど変更内容には小さなバグ修正としか書いてなくて不思議、でも大丈夫、みたいなことが書いてあると思った。
いなかで底辺IT企業の社畜やってる身にはとても計り知れない感じがしました。