【问题标题】:Fast processing of data快速处理数据
【发布时间】:2014-02-19 08:10:26
【问题描述】:

我的应用程序每 80 毫秒获取一次数据(我今天问老板,他说 80 毫秒还可以,但最好是 2 毫秒 - 20 毫秒,比我想象的还要快)。我需要处理传入的消息,因此我尝试使用 if 子句处理它们,并且每次 if 子句为真时,TextView 中都会设置一个新文本@

像这样:

if (data.equalsIgnoreCase(test)) {
    TextView tv = (TextView) findViewById(R.id.textview);
    tv.setText(" 30 % ");
}

问题在于,数据传入的速度如此之快,而 if 子句似乎不够“快”来处理它。

TextView 仅在我停止传输消息时更改,然后在短暂“等待”后TextView更改。

有什么东西可以让它更“实时”吗?

我没有通过谷歌找到有用的东西,我的编程技能很弱,只是为了防止更多的反对

编辑:

我现在发现,我必须检查 768 个不同的值(所有十六进制代码)。所以会有 768 个 if 语句。那肯定会降低速度。

问题是,我不能“等待”先执行 if 语句,然后获取下一条消息。

消息刚刚流入。

我刚刚更新了我的代码,现在使用 ProgressBar 而不是 TextView

if (data.equalsIgnoreCase(TEST)){
    mProgressBar.setProgress(0);
}

EDIT2:添加Thread代码

class RxThread extends Thread { 
    private static final String TEST =  "0 0 0 0 0 40 0 0 ";
private static final String TEST2 = "0 1 0 0 0 41 0 0 ";
private static final String TEST3 = "2 bb 0 0 2 fb 0 0 ";
private static final String TEST4 = "2 bd 0 0 2 fd 0 0 ";
private static final String TEST5 = "2 be 0 0 2 fe 0 0 ";

Handler myHandler = new Handler();

final Runnable r = new Runnable() {
    public void run() {

        demoRxMsg = new MessageStructure();

        while (rxChannel.receiveMessage(demoRxMsg) == ReturnCode.SUCCESS) {

            String data = "";
            String format = "";

            rxChannel.receiveMessage(demoRxMsg);

            if (demoRxMsg.frameFormat == API_ADK.STANDARD_FRAME) {
                format = "SFF";
            } else {
                format = "EFF";
            }
            for (byte i = 0; i < demoRxMsg.dataLength; i++) {
                data = data + Integer.toHexString(demoRxMsg.data[i]) + " ";
            }

            if (data.equalsIgnoreCase(TEST)){
                mProgressBar.setProgress(0);
            } else if (data.equalsIgnoreCase(TEST2)) {
                mProgressBar.setProgress(1);
            } else if (data.equalsIgnoreCase(TEST3)) {
                mProgressBar.setProgress(94);
            } else if (data.equalsIgnoreCase(TEST4)) {
                mProgressBar.setProgress(95);
            } else if (data.equalsIgnoreCase(TEST5)) {
                mProgressBar.setProgress(96);
            }

            }
        }
    }   
};

public void run() {
    while (true) {
        try {
            Thread.sleep(60);
            myHandler.post(r);
        } catch (InterruptedException e) {
            break;
        }
    }
}

如何让它表现更好?

编辑 3:

为了更好地解释它必须有多快:

目前,我每 80 毫秒收到一条十六进制格式的消息。消息对象有5项:帧格式、数据格式、数据长度、消息ID和数据。在完美的情况下,我每 2-20 毫秒得到一个。

我必须区分 768 条不同的消息。这些消息除以 200(得到 0.5% 的步长)。

我想要的是一个ProgressBar,它随着十六进制代码“下雨”和百分比状态的变化而变化和流畅地运行。

一个问题是,我对接收消息的速度没有影响。它总是一样的速度。是否有可能这么快地处理数据?

【问题讨论】:

  • 您应该编辑您的问题,以展示您在多线程方面所做的努力——如果有的话
  • 好的,马上编辑
  • @avalancha,你知道如何解决吗?

标签: java android multithreading performance android-progressbar


【解决方案1】:

好吧,在您的特殊情况下,确实有可能进行优化。 findViewById() 是一个非常昂贵的操作,您应该尝试缓存以加快上面显示的代码。阅读the holder pattern,然后像这样实现它:

private TextView tv;

[...]

if (data.equalsIgnoreCase(test)) {
    if (tv == null) {
        tv = (TextView) findViewById(R.id.textview);
    }
    tv.setText(" 30 % ");
}

但是! 已经说过这可能足以在您的应用程序中产生您想要的效果。 80ms 非常非常快,如果有繁重的工作,Android 往往会永久阻塞 UI 线程

因此,您将不得不考虑线程化,并且可能需要重新设计一下。

我的第一个想法是让输入队列在单独的线程上运行,并且在您确定之间存在暂停时调用TextViewchange。然后,您可以更新视图,知道这可能非常快,即使所有消息都在那里,用户也无法区分

【讨论】:

  • 忘了提一下:它已经在一个单独的线程中运行了 :) 但是谢谢你的提示
【解决方案2】:

您可以让一个变量保存更新信息(使其更新/读取线程安全)并让 UI 线程负责更新。 UI 线程应该从中读取数据并更新其Views。 “更新”线程在收到消息时应该修改这个变量。

您可以将Runnable 发布到更新TextView 的UI 线程,然后重新安排自己在此之后运行。这样您将获得最高性能,因为重新安排 Runnable 将允许 UI 线程完成渲染更新的信息,然后立即返回更新信息,然后重新渲染等等。这样做的一个很好的副作用是您允许 UI 线程也处理用户输入事件。

【讨论】:

    【解决方案3】:

    虽然我不确定这是主要问题,但我确实发现您的代码效率低下:

    1. 你正在用这个创建很多瞬态对象

          for (byte i = 0; i < demoRxMsg.dataLength; i++) {
              data = data + Integer.toHexString(demoRxMsg.data[i]) + " ";
          }
      

      对于 每个 字节,您正在创建至少两个对象:一个 StringBuilder 和一个 String 对象(参考 here)。如果你想得到一个字符串,至少要像下面这样:

          StringBuilder sb=new StringBuilder();
          for (byte i = 0; i < demoRxMsg.dataLength; i++) {
              sb.append(demoRxMsg.data[i]);
          }
          data=sb.toString();
      
    2. 与比较字符串相比,比较原始字节会快得多,这样您就可以完全跳过任何对象的创建。

    3. 我假设在第一个和最后几个数据块之间,有相当多的数据,但是在你当前的实现中,那些不影响 UI 的数据仍然会在 UI 线程上检查,而不是只运行 @ 987654324@ 当您确定需要更新 UI 时。未经测试的代码:

      class RxThread extends Thread {
      private static final String TEST = "0 0 0 0 0 40 0 0 ";
      private static final String TEST2 = "0 1 0 0 0 41 0 0 ";
      private static final String TEST3 = "2 bb 0 0 2 fb 0 0 ";
      private static final String TEST4 = "2 bd 0 0 2 fd 0 0 ";
      private static final String TEST5 = "2 be 0 0 2 fe 0 0 ";
      
      Handler myHandler = new Handler();
      
      public void run() {
      while (true) {
          try {
              Thread.sleep(60);
      
              demoRxMsg = new MessageStructure();
      
              int progress = -1;
              while (rxChannel.receiveMessage(demoRxMsg) == ReturnCode.SUCCESS) {
      
                  String data = "";
                  String format = "";
      
                  rxChannel.receiveMessage(demoRxMsg);
      
                  if (demoRxMsg.frameFormat == API_ADK.STANDARD_FRAME) {
                      format = "SFF";
                  } else {
                      format = "EFF";
                  }
                  for (byte i = 0; i < demoRxMsg.dataLength; i++) {
                      data = data + Integer.toHexString(demoRxMsg.data[i])
                              + " ";
                  }
      
                  if (data.equalsIgnoreCase(TEST)) {
                      progress = 0;
                  } else if (data.equalsIgnoreCase(TEST2)) {
                      progress = 1;
                  } else if (data.equalsIgnoreCase(TEST3)) {
                      progress = 94;
                  } else if (data.equalsIgnoreCase(TEST4)) {
                      progress = 95;
                  } else if (data.equalsIgnoreCase(TEST5)) {
                      progress = 96;
                  }
              }
              if (progress != -1) {
                  final int newProgress = progress;
      
                  myHandler.post(new Runnable() {
                      public void run() {
                          mProgressBar.setProgress(newProgress);
                      }
                  });
              }
          } catch (InterruptedException e) {
              break;
          }
      }
      

      } }

    【讨论】:

    • 在 No.1 上)数据的值给了我一个 12 字符的字符串,这个字符串比十六进制字符更需要比较(由于我正在处理的整个项目
    • @Fraggles 这是一个快速的伪代码来传达基本思想,您可以简单地将其更改为sb.append(Integer.toHexString(demoRxMsg.data[i]),但正如第一行中简要提到的,我认为主要问题可能在其他地方,也许你在 new MessageStructure()rxChannel.receiveMessage(demoRxMsg) 做一些耗时的事情
    • 这是可能的,但 MessageStructure()rxChannel.receiveMessage(demoRxMsg) 是 API 的一部分,我无法更改它
    • @Fraggles 那么我认为你最好的选择是#3,将所有内容移出 UI 线程,除了 必须 在 UI 线程上执行的 mProgressBar.setProgress(progress);
    • @Fraggles 为#3 添加了示例
    猜你喜欢
    • 2011-09-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-28
    • 1970-01-01
    相关资源
    最近更新 更多