lingochamp/FileDownloader · error · IllegalThreadStateException
Sorry, FileDownloader can not block the main thread…
Error message
Sorry, FileDownloader can not block the main thread, because the system is also callbacks ServiceConnection#onServiceConnected method in the main thread.
What it means
FileDownloadLine.wait() blocks the current thread until the download service binds; because Android invokes ServiceConnection#onServiceConnected on the main thread, waiting on the main thread would deadlock. The library therefore throws IllegalThreadStateException if wait (via startForeground/getSoFar/getTotal/getStatus on pending calls) is invoked from the main thread.
Solutions
- Call these methods from a background thread (worker thread, executor, or coroutine on IO dispatcher).
- Ensure the service is already bound before calling, or use the async callback-based APIs (listener-based start).
- Wrap in try-catch only as a guard; prefer not invoking from the main thread at all.
Example fix
// before FileDownloader.getImpl().startForeground(false); // on main thread // after new Thread(() -> FileDownloader.getImpl().startForeground(false)).start();
Defensive patterns
Strategy: validation
Validate before calling
if (Looper.myLooper() == Looper.getMainLooper()) {
throw new IllegalStateException("call off the main thread");
}
FileDownloader.getImpl().startForeground(false); Type guard
boolean isMainThread() { return Looper.myLooper() == Looper.getMainLooper().getThread() || Looper.myLooper() == Looper.getMainLooper(); } Prevention
- Never call blocking FileDownloader APIs from the UI thread.
- Use RxFileDownloader/Coroutine extensions that schedule on IO.
- Prefer listener-based async APIs over polling getSoFar/getTotal.
When it happens
Trigger: Calling FileDownloader.getImpl().startForeground(false) (or getSoFar/getTotal/getStatus that need service binding) from an Activity/UI thread before the service is connected.
Common situations: Calling startForeground in Application.onCreate or Activity without a background thread; querying progress synchronously in onCreate.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- If you start the task manually, it means this task doesn't…
- This task is running
- This task is dirty to restart, If you want to reuse this…
- the provided mPath[ ] is invalid, can't find its directory
- Create parent directory failed, please make sure you have…
AI-assisted analysis of lingochamp/FileDownloader@6237a8cac1 (2026-09-08).
Data as JSON: /api/errors/4e47bce0a92e68e4.
Report an issue: GitHub.
Appendix: source
Thrown at library/src/main/java/com/liulishuo/filedownloader/FileDownloadLine.java:154
}
};
wait(subscriber);
return (byte) subscriber.getValue();
}
private void wait(final ConnectSubscriber subscriber) {
final ConnectListener connectListener = new ConnectListener(subscriber);
//noinspection SynchronizationOnLocalVariableOrMethodParameter
synchronized (connectListener) {
FileDownloader.getImpl().bindService(connectListener);
if (!connectListener.isFinished()) {
if (Thread.currentThread() == Looper.getMainLooper().getThread()) {
throw new IllegalThreadStateException("Sorry, FileDownloader can not block the "
+ "main thread, because the system is also callbacks "
+ "ServiceConnection#onServiceConnected method in the main thread.");
}
try {
connectListener.wait(200 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
static class ConnectListener implements Runnable {
private boolean mIsFinished = false;
private final ConnectSubscriber mSubscriber;
ConnectListener(ConnectSubscriber subscriber) {View on GitHub (pinned to 6237a8cac1)