Qt Android Service多问题求助:启动延迟、崩溃、QTimer及QTcpSocket失效
Qt Android Service问题排查与修复
问题列表
- 服务无法立即启动,存在1-2分钟延迟
- 服务运行一段时间后停止,应用随之崩溃
- 服务中的QTimer无法正常工作
- QTcpSocket客户端无法正常运行(已添加
android.permission.INTERNET权限)
代码与配置信息
Service的main函数代码
QTcpSocket _socket; void onReadyRead() { QByteArray datas = _socket.readAll(); QString DataAsString = QString(datas); Log::log("DATA: "); Log::log(DataAsString); if(DataAsString!="HELLO\n") NotificationClient().setNotification(DataAsString + " BGN"); } int main_service(int argc, char *argv[]) { QAndroidService app(argc, argv); _socket.connectToHost(QHostAddress("xx.xx.xx.xx"), 1234); QObject::connect(&_socket, &QTcpSocket::readyRead, onReadyRead); _socket.write(QByteArray("get_money()\r\n")); QThread::msleep(1000); Log::log("creating timer.."); QTimer timer; QObject::connect(&timer, &QTimer::timeout, someFunction); timer.start(500); //MoneyWorker *mw = new MoneyWorker(); for(;;) { _socket.write(QByteArray("get_money()\r\n")); Log::log("loopin.."); QThread::msleep(10000); } //NotificationClient().setNotification("The user is happy!"); return app.exec(); }
启动Service的代码
QJniObject::callStaticMethod<void>( "org/qtproject/example/qtandroidservice/QtAndroidService", "startQtAndroidService", "(Landroid/content/Context;)V", QNativeInterface::QAndroidApplication::context());
Java层Service代码
package org.qtproject.example.qtandroidservice; import android.content.Context; import android.content.Intent; import android.util.Log; import org.qtproject.qt.android.bindings.QtService; public class QtAndroidService extends QtService { private static final String TAG = "QtAndroidService"; @Override public void onCreate() { super.onCreate(); Log.i(TAG, "Creating Service"); } @Override public void onDestroy() { super.onDestroy(); Log.i(TAG, "Destroying Service"); } @Override public int onStartCommand(Intent intent, int flags, int startId) { int ret = super.onStartCommand(intent, flags, startId); // Do some work return ret; } public static void startQtAndroidService(Context context) { context.startService(new Intent(context, QtAndroidService.class)); } public static void stopQtAndroidService(Context context) { context.stopService(new Intent(context, QtAndroidService.class)); } public static void log(String message) { Log.i(TAG, message); } }
Manifest中的Service配置
<service android:name="org.qtproject.example.qtandroidservice.QtAndroidService">
adb logcat日志
08-07 22:45:15.182 5342 5366 W ActivityManager: Timeout executing service: ServiceRecord{d2392a2 u0 org.qtproject.example.androidnotifier/org.qtproject.example.qtandroidservice.QtAndroidService} 08-07 22:45:15.531 5342 27607 E ActivityManager: Reason: executing service org.qtproject.example.androidnotifier/org.qtproject.example.qtandroidservice.QtAndroidService 08-07 22:47:35.784 5342 5366 W ActivityManager: Timeout executing service: ServiceRecord{33bcd86 u0 org.qtproject.example.androidnotifier/org.qtproject.example.qtandroidservice.QtAndroidService} 08-07 22:47:37.037 5342 29382 E ActivityManager: Reason: executing service org.qtproject.example.androidnotifier/org.qtproject.example.qtandroidservice.QtAndroidService 08-07 22:47:37.121 5342 7675 W ActivityManager: Scheduling restart of crashed service org.qtproject.example.androidnotifier/org.qtproject.example.qtandroidservice.QtAndroidService in 62676ms for start-requested 08-07 22:48:39.837 5342 5367 I ActivityManager: Start proc 29406:org.qtproject.example.androidnotifier/u0a477 for service {org.qtproject.example.androidnotifier/org.qtproject.example.qtandroidservice.QtAndroidService} 08-07 22:48:39.982 5342 7678 W ActivityManager: Stopping service due to app idle: u0a477 -1m34s200ms org.qtproject.example.androidnotifier/org.qtproject.example.qtandroidservice.QtAndroidService 08-07 22:48:40.198 29406 29428 I QtAndroidService: creating timer.. 08-07 22:48:40.198 29406 29428 I QtAndroidService: loopin.. 08-07 22:48:41.199 29406 29428 I QtAndroidService: loopin.. 08-07 22:48:42.200 29406 29428 I QtAndroidService: loopin.. 08-07 22:48:43.201 29406 29428 I QtAndroidService: loopin.. 08-07 22:48:44.201 29406 29428 I QtAndroidService: loopin.. 08-07 22:48:45.202 29406 29428 I QtAndroidService: loopin.. 08-07 22:48:46.203 29406 29428 I QtAndroidService: loopin.. 08-07 22:48:47.204 29406 29428 I QtAndroidService: loopin..
问题根源与修复方案
1. 服务启动延迟、运行崩溃
根源:代码中的for(;;)死循环+QThread::msleep(10000)完全阻塞了Qt事件循环,app.exec()无法执行。Android系统检测到Service主线程长时间无响应(超过20秒)触发ANR,直接杀死进程,日志中的Timeout executing service就是证明,重启延迟是系统ANR后的调度策略导致。
修复:删除死循环,用QTimer实现定时请求:
// 替换原死循环代码 QTimer* requestTimer = new QTimer(); QObject::connect(requestTimer, &QTimer::timeout, [&](){ if(_socket.state() == QAbstractSocket::ConnectedState){ _socket.write(QByteArray("get_money()\r\n")); Log::log("sending request.."); } }); requestTimer->start(10000);
2. QTimer无法工作
根源:原代码中QTimer timer是局部栈变量,且事件循环被阻塞,导致定时器无法触发;若后续离开作用域(死循环不会,但正常流程会),定时器会被销毁。
修复:
- 将QTimer改为堆分配(
new QTimer()),避免局部变量被销毁 - 确保
app.exec()正常执行,启动Qt事件循环
3. QTcpSocket无法正常运行
根源:事件循环阻塞导致socket的connected、readyRead等信号无法处理;且connectToHost是异步操作,直接调用write时可能未建立连接,导致写入失败。
修复示例:
// 替换原socket连接代码 QObject::connect(&_socket, &QTcpSocket::connected, [&](){ Log::log("socket connected"); _socket.write(QByteArray("get_money()\r\n")); }); QObject::connect(&_socket, &QTcpSocket::errorOccurred, [&](QAbstractSocket::SocketError err){ Log::log("socket error: " + _socket.errorString()); }); _socket.connectToHost(QHostAddress("xx.xx.xx.xx"), 1234);
4. Android后台Service存活优化
根源:日志中Stopping service due to app idle说明系统因应用空闲停止服务,Android 8.0+对后台服务限制严格。
修复:
- 在Java层Service的
onStartCommand返回START_STICKY,确保服务被杀死后自动重启:@Override public int onStartCommand(Intent intent, int flags, int startId) { int ret = super.onStartCommand(intent, flags, startId); return START_STICKY; } - Android 8.0+需使用前台服务,在
onCreate中添加前台通知:@Override public void onCreate() { super.onCreate(); Log.i(TAG, "Creating Service"); // 创建通知渠道(Android O+必须) NotificationChannel channel = new NotificationChannel("service_channel", "Balance Monitor", NotificationManager.IMPORTANCE_LOW); NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); manager.createNotificationChannel(channel); // 构建前台通知 Notification notification = new NotificationCompat.Builder(this, "service_channel") .setContentTitle("Balance Monitor") .setContentText("Checking balance...") .setSmallIcon(R.mipmap.ic_launcher) .build(); startForeground(1, notification); } - 在Manifest中添加前台服务权限:
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
内容的提问来源于stack exchange,提问作者acho
相关产品推荐
相关产品推荐

