2011-02-05 3 views
3

Чтобы IO не блокировал поток пользовательского интерфейса в моем приложении для Android, я пытаюсь переместить операцию записи файла в отдельный поток. Это код, я использую, чтобы начать с низким приоритетом нитяным писать 1Mb из буфера байт:Операция ввода-вывода в другой ветке, перекрывающей мою ветку пользовательского интерфейса?

Thread t = new Thread(new Runnable() 
{ 
    @Override 
    public void run() 
    { 
    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); 
     try 
     { 
     FileOutputStream fos = new FileOutputStream(filename)); 
     try 
     { 
      final java.nio.channels.FileChannel outChannel = fos.getChannel(); 
      outChannel.write(byteBuffer); 
      fos.getFD().sync(); 
     } 
     finally 
     { 
      if (fos != null) 
      fos.close(); 
     } 
     } 
    catch (Exception e) 
    { 
     e.printStackTrace(); 
    } 
} 
}); 

t.setPriority(Thread.MIN_PRIORITY); 
t.start(); 

Этих потоки запускаются в моем приложении, когда некоторые события пользовательского интерфейса произойдут. К сожалению, я по-прежнему замечаю огромную задержку. Мой пользовательский интерфейс будет замораживаться в течение ~ 2 секунд каждые 10 или около того раз, когда я запускаю/завершаю один из вышеперечисленных потоков. Если я прокомментирую код потока, эти задержки исчезнут.

Что я могу сделать, чтобы остановить эту операцию ввода-вывода от блокировки моего потока пользовательского интерфейса?

Я не уверен, что теперь делать, чтобы диагностировать проблему. Я понял, что поток IO блокируется, когда «outChannel.write» произошло, поскольку он ожидал завершения операции ввода-вывода, что означало бы, что мой поток пользовательского интерфейса немедленно возьмет верх. В этом случае для операции записи требуется большой кусок мощности процессора?

Edit:

С StrictView на (который я уверен, потому что он поймал несколько несвязанных проблем ввода-вывода в потоке пользовательского интерфейса, что я фиксированный первым), я могу подтвердить, нет IO происходит в моем IO потоке.

Результаты бегущей трассировки довольно загадочны. Проблема пользовательского интерфейса заключается в том, что когда я выполняю операции перетаскивания, каждые 10 или около того раз я делаю это, устройство, похоже, замерзает примерно на 0,5-1 с. Вещь, которую вы перетаскиваете, замерзнет, ​​и после задержек в конечном итоге произойдет переход туда, где находится ваш палец. В отслеживании я продолжал перетаскивать, пока это не произошло. В случае, когда это происходит в traceview, мои фоновые потоки не запускаются, но есть внезапный блок около 1 секунды, где операции в моем потоке пользовательского интерфейса, которые обычно бывают быстрыми, требуют более продолжительной работы x10. Например, вызов .drawBitmap (с растровым изображением с фиксированным размером) показан как принимающий ~ 0.2s для выполнения, когда каждый раз до этого один и тот же вызов .drawBitamp занимает десятую часть этого времени. Я мог просто читать это неправильно, но я не знаю, куда идти отсюда или что искать.

+0

Это не тот поток, на который говорят, что блокирует ваш пользовательский интерфейс. Это только ОС, записывающие данные на карту. Файл ввода/вывода может быть медленным. Ваш вызов 'fos.getFD(). Sync();' скорее всего вызывает заикание. – Falmarri

+0

Итак, вы говорите, что любая операция записи, которую я выполняю, блокирует пользовательский интерфейс? Какой смысл переместить его в другой поток? Он все еще заикается, когда я вынимаю .sync, но реже. В любом случае, это не идеально, потому что тогда у меня нет гарантии, что мой файл был записан на диск. – rbcc

ответ

6

Что я могу сделать, чтобы остановить эту операцию ввода-вывода от блокировки моего потока пользовательского интерфейса?

Операция ввода-вывода напрямую не блокирует основную прикладную нить. Ваш код, запущенный в главном потоке приложения, блокирует основной поток приложения. Вам нужно определить, где ваш код, запущенный в основном потоке приложения, привязан. Для этого используйте отладчик или операторы Log.d() или что угодно.

Например, на большинстве Android-устройств файловая система YAFFS2 имеет глобальную блокировку для каждого раздела. Цитирование Brad Fitzpatrick:

yaffs имеет гигантский замок вокруг всего кода файловой системы, поэтому даже незначительные стат() может блокировать на несколько секунд, если диск иначе чеканный чем-то другим (во время загрузки, тяжелой синхронизации и т.д.) ,

Следовательно, если вы связываете файловую систему в течение нескольких секунд в фоновом потоке, основной поток приложений будет неспособен выполнять собственный ввод-вывод. Возможно, это то, что вас отключает, и в этом случае StrictMode в Android 2.3 может помочь вам определить источник вашей трудности.

Какой смысл переместить его в другой поток?

Целью является перемещение флэш-памяти в основной поток приложения. Вспышка ввода/вывода.

FWIW, Android появится на устройствах ext4 (например, Nexus S), и эта проблема отпадет ... хотя вам нужно тогда беспокоиться о звонках sync(). На YAFFS2 sync() менее критичен, по большому счету, так как он немного буферизуется.

+0

Спасибо за советы! Я редактировал свой вопрос с дополнительной информацией. Я действительно сильно потрясен, так как я подтвердил, что в моем потоке пользовательского интерфейса не работает IO, и, как видно, traceview отображает сообщения о нескольких вызовах функций потока пользовательского интерфейса, которые, как правило, быстро запускаются, и они занимают много времени, даже когда фоновый поток isn не получая процессорное время. – rbcc

+0

Проблема блокировки яффов будет иметь смысл, если файл находится на внутреннем хранилище, но если он находится на SD-карте? Это, предположительно, FAT32. Хотя если ваше приложение также находится на SD-карте, там может быть какая-то проблема. Если у вас есть инструменты для написания собственного исполняемого файла командной строки в C, мне будет интересно, что произойдет, если вы создадите тест записи файлов и запустите его из оболочки ADB - будет ли он аналогичным образом замедляться и приложение для Android, работающее на в то же время? На самом деле, никакого кодирования не требуется, вы можете сделать это, используя cat some_big_file> дубликат в оболочке (без 'cp' при установке по умолчанию) –

Смежные вопросы