前言:嵌入式项目需要升级功能,升级范围有应用升级,系统升级,外设固件升级,升级包的下载等,每一项升级都包含以下流程,检测安装包,提示用户是否升级,升级过程中提供进度,提示用户升级完成。
      经过几次尝试后,发现用if多个分支已不能很好的管理这么多选项了,经同事提示考虑使用状态机。的确是个稳妥的方法。但经试验后发现有一个问题,就是 安装包复制完成后 ,本想驱动状态机进入 “提示用户已完成的UI”,但就像程序睡眠了一样,卡住了,经kill -9 pid杀掉后,之后每次升级都不会卡了,联想到startapp.sh中App退出后有一个sync操作。因此在App中每次 FileCopy如果都 强行加入sync,神奇的解决了问题,有大侠知道原因的请指教
简化的代码如下:
mainwindow.h

点击(此处)折叠或打开

  1. #ifndef MAINWINDOW_H
  2. #define MAINWINDOW_H

  3. #include <QWidget>
  4. #include <QState>
  5. #include <QStateMachine>

  6. #include <QAbstractTransition>
  7. #define STATE_WRITING 0
  8. #define STATE_WRITE_FINISH 1

  9. namespace Ui {
  10. class MainWindow;
  11. }


  12. struct BootStateEvent : public QEvent
  13. {
  14.     BootStateEvent(const int &val) :
  15.         QEvent(QEvent::Type(QEvent::User+100)),
  16.       value(val) {

  17.     }
  18.     int value;
  19.  };
  20. class BootStateTransition : public QAbstractTransition
  21.  {
  22.  public:
  23.     BootStateTransition(const int &value)
  24.         : m_value(value) {}
  25.  protected:
  26.     bool eventTest(QEvent *e)
  27.     {
  28.         if (e->type() != QEvent::Type(QEvent::User+100))// BootStateEvent
  29.             return false;
  30.         BootStateEvent *se = static_cast<BootStateEvent*>(e);
  31.         return (m_value == se->value);
  32.     }

  33.     void onTransition(QEvent *) {}
  34.  private:
  35.     int m_value;

  36.  };

  37. class MainWindow : public QWidget
  38. {
  39.     Q_OBJECT

  40. public:
  41.     explicit MainWindow(QWidget *parent = 0);
  42.     ~MainWindow();

  43. private slots:
  44.     void slotWritingFileOnEnter();
  45.     void slotShowFinishOnEnter();
  46. private:
  47.     Ui::MainWindow *ui;
  48.     void doCopyFile();//do file copy
  49.     void doSync();
  50.     void initMachine();
  51.     QState *writingFile ;
  52.     QState *showFinish ;
  53.     QStateMachine *machine ;
  54. };

  55. #endif // MAINWINDOW_H

mainwindow.cpp

点击(此处)折叠或打开

  1. #include "mainwindow.h"
  2. #include "ui_mainwindow.h"
  3. #include <QDebug>
  4. #include <QProcess>
  5. MainWindow::MainWindow(QWidget *parent) :
  6.     QWidget(parent),
  7.     ui(new Ui::MainWindow)
  8. {
  9.     ui->setupUi(this);
  10.     initMachine();
  11.     machine->start();

  12. }

  13. MainWindow::~MainWindow()
  14. {
  15.     delete ui;
  16. }
  17. void MainWindow::slotWritingFileOnEnter(){
  18.     doCopyFile();
  19.     doSync();
  20.     machine->postEvent(new BootStateEvent(STATE_WRITE_FINISH));//这一句之前加doSync(),否则转入不到s lotShowFinishOnEnter

  21. }

  22. void MainWindow::doCopyFile()
  23. {
  24.     qDebug()<<"FileCopy...";
  25.     qDebug()<<"FileCopy finished";

  26. }

  27. void MainWindow::doSync()
  28. {
  29.     qDebug()<<"doSync...";
  30.     QProcess p;

  31.     QEventLoop loop;
  32.     QObject::connect(&p,SIGNAL(finished(int)),&loop,SLOT(quit()));

  33.     QString programPath = "/sbin/sync";
  34.     QStringList args;
  35.     p.start(programPath,args);
  36.     p.waitForFinished( -1 );
  37. }

  38. void MainWindow::initMachine()
  39. {
  40.     writingFile = new QState();
  41.     showFinish = new QState();
  42.     machine = new QStateMachine();


  43.     machine->addState( writingFile );
  44.     machine->addState( showFinish );
  45.     machine->setInitialState( writingFile );

  46.     BootStateTransition *writingFinishTran = new BootStateTransition(STATE_WRITE_FINISH);

  47.     writingFinishTran->setTargetState( showFinish );
  48.     writingFile->addTransition( writingFinishTran );

  49.     connect(writingFile,SIGNAL(entered()),this,SLOT(slotWritingFileOnEnter()));
  50.     connect(showFinish,SIGNAL(entered()),this,SLOT(slotShowFinishOnEnter()));

  51. }

  52. void MainWindow::slotShowFinishOnEnter(){
  53.     //show finish info
  54.      qDebug()<<"slotShowFinishOnEnter";
  55. }


09-08 15:47