{"record":{"id":"f4b18f956a5cd861","repo":"JessYanCoding/AndroidAutoSize","slug":"not-in-applications-main-thread","errorCode":null,"errorMessage":"Not in applications main thread","messagePattern":"Not in applications main thread","errorType":"exception","errorClass":"java.lang.IllegalStateException","httpStatus":null,"severity":"error","filePath":"autosize/src/main/java/me/jessyan/autosize/utils/Preconditions.java","lineNumber":113,"sourceCode":"    }\n\n    public static int checkElementIndex(int index, int size, String desc) {\n        if (index >= 0 && index < size) {\n            return index;\n        } else {\n            throw new IndexOutOfBoundsException(badElementIndex(index, size, desc));\n        }\n    }\n\n    /**\n     * Throws {@link IllegalStateException} if the calling thread is not the application's main\n     * thread.\n     *\n     * @throws IllegalStateException If the calling thread is not the application's main thread.\n     */\n    public static void checkMainThread() {\n        if (Looper.myLooper() != Looper.getMainLooper()) {\n            throw new IllegalStateException(\"Not in applications main thread\");\n        }\n    }\n\n    private static String badElementIndex(int index, int size, String desc) {\n        if (index < 0) {\n            return format(\"%s (%s) must not be negative\", new Object[]{desc, Integer.valueOf(index)});\n        } else if (size < 0) {\n            throw new IllegalArgumentException((new StringBuilder(26)).append(\"negative size: \").append(size).toString());\n        } else {\n            return format(\"%s (%s) must be less than size (%s)\", new Object[]{desc, Integer.valueOf(index), Integer.valueOf(size)});\n        }\n    }\n\n    public static int checkPositionIndex(int index, int size) {\n        return checkPositionIndex(index, size, \"index\");\n    }\n\n    public static int checkPositionIndex(int index, int size, String desc) {","sourceCodeStart":95,"sourceCodeEnd":131,"githubUrl":"https://github.com/JessYanCoding/AndroidAutoSize/blob/e402ecdd998ea07549513ac08c12e9f097f3b48c/autosize/src/main/java/me/jessyan/autosize/utils/Preconditions.java#L95-L131","documentation":"AutoSize throws this IllegalStateException from Preconditions.checkMainThread() when an API that must run on Android's main (UI) thread is invoked from a background thread. Android view/window measurement and UI sizing operations are not thread-safe, so the library enforces main-thread execution defensively. It is a fail-fast guard, not a recoverable failure.","triggerScenarios":"Calling an AutoSize API (e.g. init/autoSizeDensity related entry points that route through checkMainThread) from a worker thread, HandlerThread, RxJava/Coroutine IO dispatcher, or AsyncTask.doInBackground instead of the main looper.","commonSituations":"Developers hooking AutoSize into async code paths: adapting density after a network-driven layout change inside a coroutine on Dispatchers.IO, calling sizing helpers in a background-initialized SDK, or an Activity not yet on the main thread during exotic initialization.","solutions":["Move the AutoSize call to the main thread: wrap it in Activity.runOnUiThread(...) or post it to the main Handler.","With coroutines, call it inside withContext(Dispatchers.Main) { ... }.","With RxJava, use observeOn(AndroidSchedulers.mainThread()) before invoking the API.","If the call originates in a library callback, verify which thread the callback delivers on and hop threads there."],"exampleFix":"// before\nexecutor.execute(() -> AutoSize.autoConvertDensityOfGlobalConfig(activity));\n\n// after\nnew Handler(Looper.getMainLooper()).post(() ->\n    AutoSize.autoConvertDensityOfGlobalConfig(activity));","handlingStrategy":"try-catch","validationCode":"public static boolean isMainThread() {\n    return Looper.myLooper() == Looper.getMainLooper();\n}\n// call site:\nif (isMainThread()) AutoSize.autoConvertDensityOfGlobalConfig(activity);\nelse new Handler(Looper.getMainLooper()).post(() -> AutoSize.autoConvertDensityOfGlobalConfig(activity));","typeGuard":"public static void runOnMain(Runnable r) {\n    if (Looper.myLooper() == Looper.getMainLooper()) r.run();\n    else new Handler(Looper.getMainLooper()).post(r);\n}","tryCatchPattern":"try {\n    Preconditions.checkMainThreadGuarded(); // or the AutoSize call directly\n    AutoSize.autoConvertDensityOfGlobalConfig(activity);\n} catch (IllegalStateException e) {\n    Log.w(\"AutoSize\", \"wrong thread, reposting to main\", e);\n    new Handler(Looper.getMainLooper()).post(() -> AutoSize.autoConvertDensityOfGlobalConfig(activity));\n}","preventionTips":["Always invoke AutoSize APIs from Activity/Fragment lifecycle methods or view callbacks, which run on the main thread.","Centralize sizing logic in one helper that hops to the main thread internally.","In coroutines use withContext(Dispatchers.Main); in RxJava use observeOn(AndroidSchedulers.mainThread()).","Add a debug-mode thread assertion around your sizing helper to catch regressions early."],"tags":["android","threading","main-thread","illegal-state"],"backgroundTag":"invalid-state-transition","analyzedSha":"e402ecdd998ea07549513ac08c12e9f097f3b48c","analyzedAt":"2026-09-07T15:05:42.094Z","contentChangedAt":"2026-09-07T15:05:42.094Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}