{"id":634,"date":"2025-07-15T23:12:26","date_gmt":"2025-07-15T23:12:26","guid":{"rendered":"https:\/\/boochlin.com\/?p=634"},"modified":"2026-09-19T17:04:07","modified_gmt":"2026-09-19T17:04:07","slug":"viewmodelscope-vs-remembercoroutinescope-%e5%85%b6%e5%af%a6%e6%b2%92%e5%95%a5%e5%a5%bd-versus-%ef%bc%8c%e5%b0%b1%e6%98%af-soc-%e8%81%b7%e8%b2%ac%e5%88%86%e9%9b%a2","status":"publish","type":"post","link":"https:\/\/boochlin.com\/?p=634","title":{"rendered":"viewModelScope vs rememberCoroutineScope \u5176\u5be6\u6c92\u5565\u597d versus \uff0c\u5c31\u662f SOC \u8077\u8cac\u5206\u96e2"},"content":{"rendered":"<ul>\n<li>\n<p>viewModelScope\uff1a\u8207 <strong>ViewModel<\/strong> \u7684\u751f\u547d\u9031\u671f\u7d81\u5b9a\uff0c\u53ea\u80fd\u7528\u5728<strong>\u8cc7\u6599\/\u908f\u8f2f\u5c64<\/strong>\u3002<\/p>\n<\/li>\n<li>\n<p>rememberCoroutineScope\uff1a\u8207 <strong>Composable \u756b\u9762\u5143\u4ef6<\/strong>\u7684\u751f\u547d\u9031\u671f\u7d81\u5b9a\uff0c\u53ea\u80fd\u7528\u5728 <strong>UI \u5c64<\/strong>\u3002<\/p>\n<\/li>\n<\/ul>\n<p>\u6c38\u9060\u4e0d\u8981\u5728 rememberCoroutineScope \u4e2d\u8655\u7406\u696d\u52d9\u908f\u8f2f\uff0c\u4e5f\u6c38\u9060\u4e0d\u8981\u5728 viewModelScope \u4e2d\u76f4\u63a5\u63a7\u5236\u9700\u8981 Composable \u4e0a\u4e0b\u6587\u7684 UI \u5143\u4ef6<\/p>\n<hr>\n<h3>\u4f55\u6642\u8a72\u7528\u54ea\u500b\uff1f<\/h3>\n<p>\u4f60\u53ef\u4ee5\u554f\u81ea\u5df1\u4e00\u500b\u554f\u984c\uff1a<\/p>\n<p>\u300c\u7576\u624b\u6a5f\u87a2\u5e55\u65cb\u8f49\u6642\uff0c\u9019\u500b\u975e\u540c\u6b65\u4efb\u52d9\u61c9\u8a72\u8981\u7e7c\u7e8c\u57f7\u884c\uff0c\u9084\u662f\u61c9\u8a72\u8981\u53d6\u6d88\u91cd\u4f86\uff1f\u300d<\/p>\n<ul>\n<li>\n<p><strong>\u5982\u679c\u7b54\u6848\u662f\u300c\u61c9\u8a72\u7e7c\u7e8c\u57f7\u884c\u300d<\/strong>: \u90a3\u5c31\u7528 viewModelScope\u3002<\/p>\n<ul>\n<li><strong>\u60c5\u5883<\/strong>: \u4f60\u6b63\u5728\u5f9e\u7db2\u8def\u4e0b\u8f09\u4e00\u500b\u4f7f\u7528\u8005\u982d\u50cf\u3002\u4f7f\u7528\u8005\u53ea\u662f\u65cb\u8f49\u4e00\u4e0b\u624b\u6a5f\uff0c\u4f60\u4e0d\u5e0c\u671b\u4e0b\u8f09\u4e2d\u65b7\uff0c\u800c\u662f\u5e0c\u671b\u5b83\u7e7c\u7e8c\u5728\u80cc\u666f\u5b8c\u6210\uff0c\u7136\u5f8c\u986f\u793a\u5728\u65b0\u65b9\u5411\u7684\u756b\u9762\u4e0a\u3002\u9019\u662f\u8cc7\u6599\u5c64\u7684\u4efb\u52d9\uff0c\u8207 ViewModel \u7684\u751f\u547d\u9031\u671f\u4e00\u81f4\u3002<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<pre><code class=\"hljs language-kotlin\"><span class=\"hljs-comment\">\/\/ \u5728 ViewModel \u4e2d<\/span>\n<span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title class_\">ProfileViewModel<\/span> : <span class=\"hljs-type\">ViewModel<\/span>() {\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">fun<\/span> <span class=\"hljs-title\">fetchAvatar<\/span><span class=\"hljs-params\">()<\/span><\/span> {\n        viewModelScope.launch {\n            <span class=\"hljs-comment\">\/\/ \u5373\u4f7f\u87a2\u5e55\u65cb\u8f49\uff0c\u9019\u500b\u4e0b\u8f09\u4efb\u52d9\u4e5f\u4e0d\u6703\u4e2d\u65b7<\/span>\n            <span class=\"hljs-keyword\">val<\/span> avatar = repository.downloadAvatar()\n            _uiState.update { it.copy(avatar = avatar) }\n        }\n    }\n}<\/code><\/pre>\n<ul>\n<li>\n<p><strong>\u5982\u679c\u7b54\u6848\u662f\u300c\u61c9\u8a72\u53d6\u6d88\u91cd\u4f86\u300d\u6216\u300c\u61c9\u8a72\u505c\u6b62\u300d<\/strong>: \u90a3\u5c31\u7528 rememberCoroutineScope\u3002<\/p>\n<ul>\n<li><strong>\u60c5\u5883<\/strong>: \u7576\u67d0\u500b\u72c0\u614b\u8b8a\u70ba true \u6642\uff0c\u4f60\u9700\u8981\u986f\u793a\u4e00\u500b Snackbar \u63d0\u793a\u300c\u8a0a\u606f\u5df2\u50b3\u9001\u300d\u3002\u5982\u679c\u4f7f\u7528\u8005\u5728\u9019\u6642\u65cb\u8f49\u4e86\u87a2\u5e55\uff0c\u820a\u7684 Snackbar \u5c31\u6c92\u6709\u610f\u7fa9\u4e86\uff0c\u4f60\u53ef\u80fd\u6703\u60f3\u5728\u65b0\u756b\u9762\u4e0a\u6839\u64da\u65b0\u7684\u72c0\u614b\u6c7a\u5b9a\u662f\u5426\u91cd\u65b0\u986f\u793a\u3002\u9019\u500b\u4efb\u52d9\u5b8c\u5168\u4f9d\u9644\u65bc\u7576\u524d\u7684 UI\u3002<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<pre><code class=\"hljs language-kotlin\"><span class=\"hljs-comment\">\/\/ \u5728 Composable \u4e2d<\/span>\n<span class=\"hljs-meta\">@Composable<\/span>\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">fun<\/span> <span class=\"hljs-title\">MessageSender<\/span><span class=\"hljs-params\">(snackbarHostState: <span class=\"hljs-type\">SnackbarHostState<\/span>)<\/span><\/span> {\n    <span class=\"hljs-comment\">\/\/ \u53d6\u5f97\u4e00\u500b\u8207 Composable \u751f\u547d\u9031\u671f\u7d81\u5b9a\u7684 scope<\/span>\n    <span class=\"hljs-keyword\">val<\/span> scope = rememberCoroutineScope()\n\n    Button(\n        onClick = {\n            <span class=\"hljs-comment\">\/\/ \u5728\u9ede\u64ca\u4e8b\u4ef6\u9019\u7a2e callback \u4e2d\uff0c\u624b\u52d5\u555f\u52d5\u5354\u7a0b<\/span>\n            scope.launch {\n                <span class=\"hljs-comment\">\/\/ \u9019\u500b\u4efb\u52d9\u8207 UI \u76f8\u95dc\uff0c\u5982\u679c\u756b\u9762\u6d88\u5931\uff0c\u4efb\u52d9\u4e5f\u8a72\u53d6\u6d88<\/span>\n                snackbarHostState.showSnackbar(<span class=\"hljs-string\">&quot;\u8a0a\u606f\u5df2\u50b3\u9001\uff01&quot;<\/span>)\n            }\n        }\n    ) {\n        Text(<span class=\"hljs-string\">&quot;\u50b3\u9001\u8a0a\u606f&quot;<\/span>)\n    }\n}<\/code><\/pre>\n<ul>\n<li>\n<p>viewModelScope \u95dc\u5fc3\u7684\u662f<strong>\u8cc7\u6599\u7684\u5b58\u6d3b<\/strong>\uff0c\u5b83\u6bd4 UI \u66f4\u6301\u4e45\uff0c\u80fd\u8de8\u8d8a\u77ed\u66ab\u7684 UI \u91cd\u5efa\uff08\u5982\u87a2\u5e55\u65cb\u8f49\uff09\u3002<\/p>\n<\/li>\n<li>\n<p>rememberCoroutineScope \u95dc\u5fc3\u7684\u662f<strong>\u756b\u9762\u7684\u5448\u73fe<\/strong>\uff0c\u5b83\u7684\u751f\u547d\u975e\u5e38\u77ed\u66ab\uff0c\u8207\u4f60\u5728\u87a2\u5e55\u4e0a\u770b\u5230\u7684\u5143\u4ef6\u540c\u751f\u5171\u6b7b\u3002<\/p>\n<\/li>\n<\/ul>\n<hr>\n<p>\u985e\u4f3c viewModelScope \u7684\u6709<\/p>\n<h3>LifecycleScope<\/h3>\n<p>\u9019\u662f viewModelScope \u6700\u76f4\u63a5\u7684\u5144\u5f1f\u3002\u5982\u679c\u8aaa viewModelScope \u662f\u70ba ViewModel \u91cf\u8eab\u6253\u9020\u7684\uff0c\u90a3 LifecycleScope \u5c31\u662f\u70ba <strong>Activity \u548c Fragment<\/strong> \u9019\u985e\u5177\u6709\u660e\u78ba\u751f\u547d\u9031\u671f\u7684 UI \u5143\u4ef6\u6240\u8a2d\u8a08\u7684\u3002<\/p>\n<pre><code class=\"hljs language-kotlin\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title class_\">MyFragment<\/span> : <span class=\"hljs-type\">Fragment<\/span>() {\n\n    <span class=\"hljs-keyword\">override<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">fun<\/span> <span class=\"hljs-title\">onViewCreated<\/span><span class=\"hljs-params\">(view: <span class=\"hljs-type\">View<\/span>, savedInstanceState: <span class=\"hljs-type\">Bundle<\/span>?)<\/span><\/span> {\n        <span class=\"hljs-keyword\">super<\/span>.onViewCreated(view, savedInstanceState)\n\n        <span class=\"hljs-comment\">\/\/ \u4f7f\u7528 lifecycleScope \u555f\u52d5\u5354\u7a0b<\/span>\n        viewLifecycleOwner.lifecycleScope.launch {\n            <span class=\"hljs-comment\">\/\/ \u5728\u9019\u88e1\u57f7\u884c\u9577\u6642\u9593\u7684\u80cc\u666f\u4efb\u52d9\uff0c\u4f8b\u5982\u7db2\u8def\u8acb\u6c42\u6216\u8cc7\u6599\u5eab\u8b80\u53d6<\/span>\n            <span class=\"hljs-keyword\">val<\/span> <span class=\"hljs-keyword\">data<\/span> = fetchData()\n            updateUi(<span class=\"hljs-keyword\">data<\/span>)\n        }\n    }\n}<\/code><\/pre>\n<h3>GlobalScope (\u5168\u57df\u4f5c\u7528\u57df)<\/h3>\n<p>GlobalScope \u662f\u4e00\u500b<strong>\u91cd\u91cf\u7d1a<\/strong>\u7684\u5de5\u5177\uff0c\u9700\u8981\u8b39\u614e\u4f7f\u7528\u3002\u5b83\u6b63\u5982\u5176\u540d\uff0c\u662f\u4e00\u500b<strong>\u5168\u57df<\/strong>\u7684\u4f5c\u7528\u57df<\/p>\n<pre><code class=\"hljs language-kotlin\"><span class=\"hljs-comment\">\/\/ \u8b66\u544a\uff1a\u9664\u975e\u4f60\u975e\u5e38\u78ba\u5b9a\uff0c\u5426\u5247\u4e0d\u8981\u9019\u6a23\u505a\uff01<\/span>\n<span class=\"hljs-comment\">\/\/ \u9019\u500b\u4efb\u52d9\u6703\u4e00\u76f4\u57f7\u884c\uff0c\u76f4\u5230 App \u88ab\u6bba\u6389\u3002<\/span>\nGlobalScope.launch {\n    <span class=\"hljs-keyword\">while<\/span> (<span class=\"hljs-literal\">true<\/span>) {\n        delay(<span class=\"hljs-number\">30_000<\/span>) <span class=\"hljs-comment\">\/\/ \u6bcf 30 \u79d2\u57f7\u884c\u4e00\u6b21<\/span>\n        Log.d(<span class=\"hljs-string\">&quot;GlobalScope&quot;<\/span>, <span class=\"hljs-string\">&quot;Doing some background work...&quot;<\/span>)\n    }\n}<\/code><\/pre>\n<h3>\u81ea\u8a02 CoroutineScope. \u5176\u5be6\u5c31\u662fSupervisorJob<\/h3>\n<p>\u9019\u5728\u8655\u7406\u975e\u6a19\u6e96\u751f\u547d\u9031\u671f\u7684\u7269\u4ef6\u6642\u7279\u5225\u6709\u7528\u3002<\/p>\n<pre><code class=\"hljs language-kotlin\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title class_\">BluetoothConnectionManager<\/span> {\n\n    <span class=\"hljs-comment\">\/\/ 1. \u5efa\u7acb\u4e00\u500b\u5305\u542b Job \u548c Dispatcher \u7684\u81ea\u8a02 Scope<\/span>\n    <span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">val<\/span> scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)\n\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">fun<\/span> <span class=\"hljs-title\">startListening<\/span><span class=\"hljs-params\">()<\/span><\/span> {\n        scope.launch {\n            <span class=\"hljs-comment\">\/\/ \u958b\u59cb\u76e3\u807d\u85cd\u7259\u8a0a\u865f...<\/span>\n        }\n    }\n\n    <span class=\"hljs-comment\">\/\/ 2. \u5fc5\u9808\u624b\u52d5\u5728\u9069\u7576\u7684\u6642\u6a5f\u53d6\u6d88\uff01<\/span>\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">fun<\/span> <span class=\"hljs-title\">disconnect<\/span><span class=\"hljs-params\">()<\/span><\/span> {\n        <span class=\"hljs-comment\">\/\/ \u9019\u6703\u53d6\u6d88 scope \u5167\u6240\u6709\u7531\u5b83\u555f\u52d5\u7684\u5354\u7a0b<\/span>\n        scope.cancel()\n    }\n}<\/code><\/pre>\n<hr>\n<p>\u2014<\/p>\n","protected":false},"excerpt":{"rendered":"<p>viewModelScope\uff1a\u8207 ViewModel \u7684\u751f\u547d\u9031\u671f\u7d81\u5b9a\uff0c\u53ea\u80fd\u7528\u5728\u8cc7\u6599\/\u908f\u8f2f\u5c64\u3002 remember [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":1248,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[86],"tags":[203,248,285],"_links":{"self":[{"href":"https:\/\/boochlin.com\/index.php?rest_route=\/wp\/v2\/posts\/634"}],"collection":[{"href":"https:\/\/boochlin.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/boochlin.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/boochlin.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/boochlin.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=634"}],"version-history":[{"count":15,"href":"https:\/\/boochlin.com\/index.php?rest_route=\/wp\/v2\/posts\/634\/revisions"}],"predecessor-version":[{"id":1552,"href":"https:\/\/boochlin.com\/index.php?rest_route=\/wp\/v2\/posts\/634\/revisions\/1552"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/boochlin.com\/index.php?rest_route=\/wp\/v2\/media\/1248"}],"wp:attachment":[{"href":"https:\/\/boochlin.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=634"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/boochlin.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=634"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/boochlin.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=634"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}