后台线程锁定UI几秒钟

Fer*_*ari 5 java performance multithreading android greendao

我遇到了一个奇怪的问题.我有我的应用程序的双向同步代码在一个内部运行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.
Run Code Online (Sandbox Code Playgroud)

我不明白为什么会这样.据我所知,代码没有在UI线程中运行,因此不应该导致这种问题.

这是我的代码示例.Inside 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);
        }
    }
Run Code Online (Sandbox Code Playgroud)

如果我注释掉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();
Run Code Online (Sandbox Code Playgroud)

该代码在上述performSync方法中执行.所以这是在原版中创建的另一个线程ScheduledThreadPoolExecutor.老实说,我不明白为什么我需要这样做,以避免冻结用户界面.有任何想法吗?