Когда рабочий поток работает, пользовательский интерфейс становится изменчивым

У меня есть приложение для распознавания рукописного ввода - пользователь рисует пальцем, приложение распознает символы. Механизм распознавания работает в рабочем потоке, который имеет минимально возможный приоритет - Thread.MIN_PRIORITY. Это чисто алгоритм CPU/памяти, без ввода-вывода. Тем не менее, когда поток активно работает, пользовательский интерфейс становится довольно изменчивым. Мазки пальца требуют заметной задержки. Я также замечаю, что события прикосновения теряются.

Разве это не то, что нужно было предотвращать потоками? Почему поток пользовательского интерфейса голодает для процессора? Как убедить систему обрабатывать рабочий поток как хорошо, низкоприоритетный фоновый поток?

Похоже, система вводит (охотно или из-за голода процессора) задержку между invalidate() и onDraw(). Могу ли я как-то снизить эту задержку?

Тестирование на относительно старом оборудовании - HTC Magic с Android 2.1.

Ответ 1

Имела ту же проблему, поэтому я сделал свой поток:

  • Thread.yield() после обработки фрагмента работы.

  • Ограниченные обновления, отправленные в поток пользовательского интерфейса с интервалом не менее 500 мс (что приводит к значительно меньшему повторному розыгрышу).

  • Сделал работу рабочего над приоритетными ведрами данных, это основное внимание уделяется обновлению представлений, с которыми пользователь взаимодействует.

Теперь весь пользовательский интерфейс действительно ленив, но свободен от отставания.

Вот как выглядит мой рабочий метод планирования (фактическая работа выполняется методом Process):

//--low priority
Thread.currentThread().setPriority(Thread.MIN_PRIORITY);

//--as long as there more work to do, and not cancelled--
while (mPriorityBuffer.hasNext() && !isCancelled()) {

    //--get the work with highest priority--
    Work next = mPriorityBuffer.getNext();

    //--do work--
    Update u = mProcessor.process(next);

    // collect updates for main thread
    mUpdates.push(u);

    long timeNow = Calendar.getInstance().getTimeInMillis();
    if(timeNow - timeLast > 500){
        //--its been quite a while now, update ui--
        postUpdatesToMainThread();
        timeLast = timeNow;
    }

    //--let UI thread work on updates--
    Thread.yield();
}

Ответ 2

Попробуйте добавить Thread.sleep(1) в основной цикл в методе распознавания символов

@Override
public void run() {
  while (!recognited) {

    //do some script

    try {
      Thread.sleep(1);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  }
}

этот спящий режим позволяет виртуальной машине возобновить другой поток немного раньше и часто

Ответ 3

Возможно, что ваш поток GUI загружается с помощью событий касания, если тогда решение должно ввести несколько мс ожидания в потоке пользовательского интерфейса и увеличить рабочий поток. Подробнее об этом здесь:

https://groups.google.com/forum/?fromgroups=#!topic/android-developers/Oe6k1_bm38o

также, может быть, вы обрабатываете слишком много данных, например, если движение вообще не происходит, или движение недостаточно значимо.