我遇到了一个奇怪的问题。我的应用程序的双向同步代码在ScheduledThreadPoolExecutor
内运行。代码从服务器的响应中迭代大量对象,并将它们保存到本地数据库(带有GreenDAO的SQLite)。
问题是,当这个线程正在处理对象列表时,UI会锁定几秒钟,并且我在logcat中得到多个跳过帧的警告。
02-16 02:34:34.539 5730-5730/com.myapp.android D/SyncService﹕ Sync done.
02-16 02:34:34.552 5730-5730/com.myapp.android I/Choreographer﹕ Skipped 123 frames! The application may be doing too much work on its main thread.
02-16 02:34:41.060 5730-5748/com.myapp.android I/art﹕ Background sticky concurrent mark sweep GC freed 168341(7MB) AllocSpace objects, 1(81KB) LOS objects, 15% free, 39MB/46MB, paused 1.774ms total 108.998ms
02-16 02:34:42.515 5730-5748/com.myapp.android I/art﹕ Background partial concurrent mark sweep GC freed 249676(9MB) AllocSpace objects, 34(3MB) LOS objects, 32% free, 33MB/49MB, paused 10.125ms total 118.693ms
02-16 02:34:45.361 5730-5748/com.myapp.android I/art﹕ Background sticky concurrent mark sweep GC freed 166082(7MB) AllocSpace objects, 1(81KB) LOS objects, 14% free, 41MB/49MB, paused 3.151ms total 115.302ms
02-16 02:34:46.792 5730-5748/com.myapp.android I/art﹕ Background partial concurrent mark sweep GC freed 296675(11MB) AllocSpace objects, 0(0B) LOS objects, 29% free, 38MB/54MB, paused 4.427ms total 122.870ms
02-16 02:34:49.785 5730-5748/com.myapp.android I/art﹕ Background sticky concurrent mark sweep GC freed 172207(7MB) AllocSpace objects, 0(0B) LOS objects, 13% free, 46MB/54MB, paused 3.229ms total 125.006ms
02-16 02:34:51.274 5730-5748/com.myapp.android I/art﹕ Background partial concurrent mark sweep GC freed 302918(11MB) AllocSpace objects, 0(0B) LOS objects, 27% free, 43MB/59MB, paused 5.143ms total 132.996ms
02-16 02:34:54.200 5730-5748/com.myapp.android I/art﹕ Background sticky concurrent mark sweep GC freed 167589(7MB) AllocSpace objects, 6(486KB) LOS objects, 13% free, 51MB/59MB, paused 5.902ms total 136.040ms
02-16 02:34:55.570 5730-5748/com.myapp.android I/art﹕ Background partial concurrent mark sweep GC freed 292352(11MB) AllocSpace objects, 0(0B) LOS objects, 24% free, 48MB/64MB, paused 4.440ms total 157.392ms
02-16 02:34:58.510 5730-5748/com.myapp.android I/art﹕ Background sticky concurrent mark sweep GC freed 173205(7MB) AllocSpace objects, 0(0B) LOS objects, 11% free, 56MB/64MB, paused 5.286ms total 133.044ms
02-16 02:35:00.100 5730-5748/com.myapp.android I/art﹕ Background partial concurrent mark sweep GC freed 303665(11MB) AllocSpace objects, 0(0B) LOS objects, 23% free, 53MB/69MB, paused 10.063ms total 233.137ms
02-16 02:35:03.054 5730-5748/com.myapp.android I/art﹕ Background sticky concurrent mark sweep GC freed 173642(7MB) AllocSpace objects, 0(0B) LOS objects, 10% free, 61MB/69MB, paused 6.528ms total 148.586ms
02-16 02:35:03.784 5730-5730/com.myapp.android I/Choreographer﹕ Skipped 1752 frames! The application may be doing too much work on its main thread.
我不明白为什么会这样。据我所知,代码没有在UI线程中运行,因此不应该引起这种问题。
这是我的代码示例。在performSync(changesOnly, false)
内部是我遍历列表并将数据保存到数据库的地方。
public void performSync(final boolean changesOnly, int delay) {
// Skip sync if it's already running.
if (!isSyncing()) {
// Create new thread for responsiveness.
new ScheduledThreadPoolExecutor(1).schedule(new Runnable() {
@Override
public void run() {
// Forward call to internal sync method.
performSync(changesOnly, false);
}
}, delay, TimeUnit.SECONDS);
}
}
如果我注释掉对performSync(changesOnly, false)
的调用,则UI不会锁定,因为没有处理任何对象。我尝试使用常规Thread
甚至是AsyncTask
而不是ScheduledThreadPoolExecutor
,但问题仍然存在。
如果你想知道为什么有两个performSync
方法,第二个(处理发生的地方)是递归的,并且不断向服务器发送批量的200个对象,直到它为止。完成。这不会导致问题,因为当锁发生时我只接收数据(不发送),因此该方法只执行一次。
有什么可能导致这种情况的想法?我没有在UI线程中执行数据库操作,只有大量对象才会发生锁定。
更新:我已经设法通过在迭代列表并将项目持久保存到数据库之前创建另一个线程来修复冻结。所以我有ScheduledThreadPoolExecutor
同步发生的地方,以及常规Thread
,我将项目保存到数据库。
// Create another thread for processing objects.
new Thread(new Runnable() {
@Override
public void run() {
// Start thread with low priority.
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
// Process new objects and persist to the database.
if (response.getObjects() != null) {
for (MyObject object : response.getObjects()) {
...
}
}
}
}).start();
此代码在上述performSync
方法中执行。所以它是在原始ScheduledThreadPoolExecutor
内创建的另一个线程。老实说,我不明白为什么我需要这样做以避免冻结用户界面。有什么想法吗?