{"record":{"id":"b0d99955efc59db0","repo":"DrKLO/Telegram","slug":"moving-more-than-1-item-is-not-supported-yet","errorCode":null,"errorMessage":"Moving more than 1 item is not supported yet","messagePattern":"Moving more than 1 item is not supported yet","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"TMessagesProj/src/main/java/androidx/recyclerview/widget/AdapterHelper.java","lineNumber":587,"sourceCode":"            return false;\n        }\n        if (BuildVars.DEBUG_VERSION) {\n            logNotify(\"onItemRangeRemoved(\" + positionStart + \", \" + itemCount + \")\");\n        }\n        mPendingUpdates.add(obtainUpdateOp(UpdateOp.REMOVE, positionStart, itemCount, null));\n        mExistingUpdateTypes |= UpdateOp.REMOVE;\n        return mPendingUpdates.size() == 1;\n    }\n\n    /**\n     * @return True if updates should be processed.\n     */\n    boolean onItemRangeMoved(int from, int to, int itemCount) {\n        if (from == to) {\n            return false; // no-op\n        }\n        if (itemCount != 1) {\n            throw new IllegalArgumentException(\"Moving more than 1 item is not supported yet\");\n        }\n        if (BuildVars.DEBUG_VERSION) {\n            logNotify(\"onItemRangeMoved(\" + from + \", \" + to + \", \" + itemCount + \")\");\n        }\n        mPendingUpdates.add(obtainUpdateOp(UpdateOp.MOVE, from, to, null));\n        mExistingUpdateTypes |= UpdateOp.MOVE;\n        return mPendingUpdates.size() == 1;\n    }\n\n    /**\n     * Skips pre-processing and applies all updates in one pass.\n     */\n    void consumeUpdatesInOnePass() {\n        // we still consume postponed updates (if there is) in case there was a pre-process call\n        // w/o a matching consumePostponedUpdates.\n        consumePostponedUpdates();\n        final int count = mPendingUpdates.size();\n        for (int i = 0; i < count; i++) {","sourceCodeStart":569,"sourceCodeEnd":605,"githubUrl":"https://github.com/DrKLO/Telegram/blob/45ab8f4308496e1f01026a97fcdb0d58a5274474/TMessagesProj/src/main/java/androidx/recyclerview/widget/AdapterHelper.java#L569-L605","documentation":"AdapterHelper.onItemRangeMoved is the entry point for adapter.notifyItemMoved(from, to). RecyclerView's move model is strictly single-item: a move always relocates exactly one element. There is no notifyItemRangeMoved API that moves a contiguous block, so itemCount must be 1. Passing itemCount != 1 is invalid and unsupported, so the helper refuses it rather than silently producing a wrong layout. Most commonly this is hit by custom adapter code that calls the internal preUpdate or onItemRangeMoved directly with a range.","triggerScenarios":"A custom adapter that calls adapterHelper.onItemRangeMoved(from, to, n) with n>1; wrapping notifyItemMoved inside a loop without DiffUtil; a data model where a 'move' is actually a bulk reordering incorrectly mapped onto a single move op.","commonSituations":"Bulk drag-and-drop reorder where the developer assumes a multi-item move primitive exists; porting code from a list library that supports range moves; a DiffUtil-like custom diff that emits multi-item moves instead of remove+insert pairs.","solutions":["Replace a multi-item move with one notifyItemMoved per item, or better, express it as remove + insert and let DiffUtil batch it.","If implementing drag-to-reorder, call notifyItemMoved once per swapped adjacent pair.","Never call onItemRangeMoved directly from app code; use the public RecyclerView.Adapter.notifyItemMoved(int,int)."],"exampleFix":"// before\n// attempting to move 3 items at once\nadapterHelper.onItemRangeMoved(from, to, 3); // throws\n\n// after\nfor (int i = 0; i < 3; i++) {\n    adapter.notifyItemMoved(from + i, to + i);\n}","handlingStrategy":"validation","validationCode":"// Enforce single-item move contract before notifying\nvoid safeMove(RecyclerView.Adapter<?> a, int from, int to, int count) {\n    if (count != 1) throw new IllegalArgumentException(\"move count must be 1, was \" + count);\n    a.notifyItemMoved(from, to);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Only call the public notifyItemMoved(int,int) — never onItemRangeMoved directly.","Express multi-item reorders as remove+insert or let DiffUtil batch them.","In drag-and-drop, emit one notify per adjacent swap."],"tags":["recyclerview","adapter","move","drag-and-drop"],"backgroundTag":null,"analyzedSha":"45ab8f4308496e1f01026a97fcdb0d58a5274474","analyzedAt":"2026-08-14T05:19:30.815Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}