2011-02-05 161 views
3

因此,IO不会阻止我的Android应用程序中的UI线程,我试图将文件写入操作移动到单独的线程中。这是我用来启动一个低优先级的线程从一个字节的缓冲区写1MB左右的代码:当某些UI事件发生IO操作在其他线程中阻塞我的UI线程?

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(); 

这些线程在我的应用程序启动。不幸的是,我仍然有时会注意到巨大的滞后。我的用户界面每10次左右冻结约2秒钟,我开始/完成上述线程之一。如果我注释掉线程代码,这些延迟就会消失。

我能做些什么来阻止这个IO操作阻塞我的UI线程?

我不确定现在要做什么来诊断问题。我的理解是,IO线程会在发生“outChannel.write”时发生阻塞,因为它正在等待IO操作完成,这意味着我的UI线程会立即接管。这种写操作实际上是否需要大量的CPU能力?

编辑:

随着StrictView上(我敢肯定,因为它夹在我第一次固定在UI线程一些无关的IO问题),我可以证实,没有发生IO在我的IO线程。

运行traceview的结果相当令人费解。用户界面的问题是,当我执行拖放操作时,我每隔10次左右就会冻结大约0.5到1秒。你拖动的东西会冻结,并在延迟后最终跳到你的手指所在的位置。在traceview中,我一直在拖动和放下,直到发生这种情况。对于在traceview中发生这种情况的情况,我的后台线程没有运行,但突然被阻塞了大约1秒,其中我的UI线程上的通常快速调用的操作需要大约x10的时间才能执行。例如,调用.drawBitmap(具有固定大小的位图)显示为每次执行相同的.drawBitamp调用需要花费0.2秒才能执行。我可能只是错误地阅读它,但我不知道该从哪里去或寻找什么。

+0

这不是说每一个线程阻塞你的用户界面。这只是将数据写入卡片的操作系统。文件I/O可能会很慢。您对`fos.getFD()。sync();`的调用很可能导致口吃。 – Falmarri 2011-02-05 00:36:37

+0

所以你说我执行的任何写操作都会阻止用户界面?那么把它移到另一个线程有什么意义呢?当我取出.sync时,它仍然会出现断断续续的情况,但频率较低。反正这并不理想,因为我不能保证我的文件已经写入磁盘。 – rbcc 2011-02-05 00:41:08

回答

6

怎样才能阻止这个IO操作阻塞我的UI线程?

I/O操作不直接阻塞主应用程序线程。您在主应用程序线程上运行的代码阻塞了主应用程序线程。您需要确定在主应用程序线程上运行的代码正在被绑定的位置。要做到这一点,请使用调试器或Log.d()声明或其他。

例如,在大多数Android设备上,文件系统是YAFFS2,它具有每个分区的全局锁定。引用Brad Fitzpatrick

YAFFS有围绕整个文件系统代码一个巨大的锁,所以即使是微小的stat()可以秒阻止如果磁盘否则被其他的东西(在引导过程中,重同步等)敲定。

因此,如果您在后台线程中占用了几秒的文件系统,主应用程序线程将无法执行自己的文件I/O。也许这就是让你烦恼的原因,在这种情况下,Android 2.3中的StrictMode可以帮助你识别你的难题。

然后将它移动到另一个线程的意义是什么?

问题的关键是将闪存I/O从主应用程序线程中移出。所有闪存I/O。

FWIW,Android将出现在ext4设备上(例如Nexus S),并且此问题将消失......尽管您需要担心sync()调用。在YAFFS2上,sync()总体上不那么重要,因为它没有缓冲功能。