title: Background thread locking UI for several seconds
body: <p>I'm experiencing a weird issue. I have my app's 2-way sync code running inside a <code>ScheduledThreadPoolExecutor</code>. The code iterates over a large list of objects from the server's response and saves them to the local database (SQLite with GreenDAO).</p>
  
  <p>The problem is, while this thread is processing the list of objects, the UI locks for several seconds and I get multiple warnings of skipped frames in logcat.</p>
  
  <pre><code>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.
  </code></pre>
  
  <p>I don't understand why this is happening. As far as I know the code is not running in the UI thread, and therefore should not cause this kind of issue.</p>
  
  <p>Here's a sample of my code. Inside <code>performSync(changesOnly, false)</code> is where I iterate over the list and persist data to the database.</p>
  
  <pre><code>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);
          }
      }
  </code></pre>
  
  <p>If I comment out the call to <code>performSync(changesOnly, false)</code> the UI doesn't lock, since no objects are processed. I tried using a regular <code>Thread</code> and even an <code>AsyncTask</code> instead of the <code>ScheduledThreadPoolExecutor</code>, but the problem persisted.</p>
  
  <p>In case you're wondering why are there two <code>performSync</code> methods, the second one (where the processing happens) is recursive, and keeps sending batches of 200 objects to the server until it's done. This is not causing the issue, as when the lock happens I'm only receiving data (not sending), and therefore the method only executes once.</p>
  
  <p>Any ideas of what could be causing this? I'm not performing database operations in the UI thread, and the lock only happens with a large list of objects.</p>
  
  <p><strong>UPDATE:</strong> I've managed to fix the freezing by creating another thread before iterating the list and persisting items to the database. So I have the <code>ScheduledThreadPoolExecutor</code> where the sync happens, and a regular <code>Thread</code> where I persist items to the database.</p>
  
  <pre><code>// 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();
  </code></pre>
  
  <p>This code is executed inside the aforementioned <code>performSync</code> method. So it's yet another thread created inside the original <code>ScheduledThreadPoolExecutor</code>. I honestly don't understand why I need to do this in order to avoid freezing the UI. Any ideas?</p>