search_index.json 132 KB

1
  1. {"config":{"lang":["en","zh"],"separator":"[\\s\\-,:!=\\[\\]()\"/]+|(?!\\b)(?=[A-Z][a-z])|\\.(?!\\d)|&[lg]t;","pipeline":["stemmer"]},"docs":[{"location":"index.html","title":"\u4f7f\u7528","text":"<p>Net\u662f\u57fa\u4e8eOkHttp/\u534f\u7a0b\u7684\u975e\u4fb5\u5165\u5f0f\u6846\u67b6(\u53ef\u4f7f\u7528\u6240\u6709Api), \u53ef\u5347\u7ea7OkHttp\u7248\u672c\u4fdd\u6301\u7f51\u7edc\u5b89\u5168</p> <p></p> <p>STAR/\u5206\u4eab\u53ef\u4ee5\u8ba9\u66f4\u591a\u4eba\u53c2\u4e0e\u5230\u672c\u5f00\u6e90\u9879\u76ee</p> <p></p> <p>\u524d\u8a00</p> <ol> <li>\u9605\u8bfb\u6587\u6863, \u5feb\u901f\u4e86\u89e3</li> <li>\u9605\u8bfb\u793a\u4f8b, \u5feb\u901f\u8fd0\u7528</li> <li>\u9605\u8bfb\u6e90\u7801, \u719f\u7ec3\u5e76\u62d3\u5c55</li> </ol>"},{"location":"index.html#_1","title":"\u4f7f\u7528","text":"<p> \u53d1\u8d77\u7f51\u7edc\u8bf7\u6c42\u7684\u4e09\u4e2a\u6b65\u9aa4</p> <ol> <li>\u521b\u5efa\u4f5c\u7528\u57df</li> <li>\u53d1\u8d77\u8bf7\u6c42\u52a8\u4f5c</li> <li>\u7b49\u5f85\u6570\u636e\u8fd4\u56de</li> </ol> \u7b80\u5355\u8bf7\u6c42\u540c\u6b65\u8bf7\u6c42\u5e76\u53d1\u8bf7\u6c42 <pre><code>scopeNetLife {\n // \u5927\u62ec\u53f7\u5185\u5c5e\u4e8e\u4f5c\u7528\u57df\n val data = Get&lt;String&gt;(Api.USER).await() // \u53d1\u8d77GET\u8bf7\u6c42\u5e76\u8fd4\u56de`String`\n}\n</code></pre> <pre><code>scopeNetLife {\n // B\u5c06\u7b49\u5f85A\u8bf7\u6c42\u8fd4\u56de\u7ed3\u679c\u540e\u53d1\u8d77\u8bf7\u6c42\n val userInfo = Get&lt;UserInfo&gt;(Api.USER).await() // A\n\n val config = Get&lt;Config&gt;(Api.CONFIG){ // B\n param(\"userId\", userInfo.id) // \u5c06\u4e0a\u4e2a\u8bf7\u6c42\u7ed3\u679c\u4f5c\u4e3a\u53c2\u6570\n }.await()\n}\n</code></pre> <pre><code>scopeNetLife {\n // \u4e24\u4e2a\u8bf7\u6c42\u540c\u65f6\u53d1\u8d77\n val getUserInfoAsync = Get&lt;UserInfo&gt;(Api.USER)\n val getConfigAsync = Get&lt;Config&gt;(Api.CONFIG)\n\n val userInfo = getUserInfoAsync.await() // \u7b49\u5f85\u6570\u636e\u8fd4\u56de\n val config = getConfigAsync.await()\n}\n</code></pre> <ol> <li>\u591a\u4e2a\u7f51\u7edc\u8bf7\u6c42\u5728\u540c\u4e00\u4e2a\u4f5c\u7528\u57df\u5185\u53ef\u4ee5\u7edf\u4e00\u7ba1\u7406</li> <li>\u5982\u679c\u591a\u4e2a\u7f51\u7edc\u8bf7\u6c42\u4e4b\u95f4\u6beb\u65e0\u5173\u8054, \u53ef\u4ee5\u521b\u5efa\u591a\u4e2a\u4f5c\u7528\u57df\u6765\u8bf7\u6c42</li> </ol> <p>\u5f3a\u5236\u521d\u59cb\u5316</p> <p>\u591a\u8fdb\u7a0b\u6216Xposed\u9879\u76ee\u8981\u6c42\u5148\u521d\u59cb\u5316</p> <p>\u81ea\u52a8\u8bc6\u522b<code>Url</code>\u6216\u8005<code>Path</code></p> <pre><code>scopeNetLife {\n val userInfo = Get&lt;String&gt;(\"/net\").await() // \u7b49\u4e8e\"${NetConfig.host}/net\"\n val config = Get&lt;String&gt;(\"https://github.com/liangjingkanji/net\").await()\n}\n</code></pre>"},{"location":"index.html#_2","title":"\u8fd4\u56de\u7ed3\u679c","text":"<p>\u8fd4\u56de\u7ed3\u679c\u652f\u6301\u7684\u6570\u636e\u7c7b\u578b(\u5373Post\u7b49\u51fd\u6570\u7684<code>\u6cdb\u578b</code>)\u7531\u8f6c\u6362\u5668\u51b3\u5b9a, \u9ed8\u8ba4\u652f\u6301\u4ee5\u4e0b\u7c7b\u578b</p> \u51fd\u6570 \u63cf\u8ff0 String \u5b57\u7b26\u4e32 ByteArray \u5b57\u8282\u6570\u7ec4 ByteString \u5185\u90e8\u5b9a\u4e49\u7684\u4e00\u79cd\u5b57\u7b26\u4e32\u5bf9\u8c61 Response \u6700\u57fa\u7840\u7684\u54cd\u5e94 File \u6587\u4ef6\u5bf9\u8c61, \u8fd9\u79cd\u60c5\u51b5\u5176\u5b9e\u5e94\u5f53\u79f0\u4e3a\u4e0b\u8f7d\u6587\u4ef6 <pre><code>scopeNetLife {\n val file = Get&lt;File&gt;(Api.FILE).await()\n}\n</code></pre> <p>\u8be6\u7ec6\u67e5\u770b\u8f6c\u6362\u5668, \u975e\u4ee5\u4e0a\u7c7b\u578b\u8981\u6c42\u81ea\u5b9a\u4e49\u8f6c\u6362\u5668</p> <p>\u4e0b\u8f7dApk \u4e0b\u8f7d\u6e90\u7801 \u793a\u4f8b\u4ee3\u7801 \u754c\u9762\u6f14\u793a</p>"},{"location":"auto-dialog.html","title":"\u81ea\u52a8\u52a0\u8f7d\u6846","text":"<p>Net\u652f\u6301\u53d1\u8d77\u8bf7\u6c42\u5f00\u59cb\u65f6\u663e\u793a\u52a0\u8f7d\u6846, \u8bf7\u6c42\u7ed3\u675f\u65f6\u9690\u85cf\u52a0\u8f7d\u6846(\u65e0\u8bba\u6210\u8d25)</p>"},{"location":"auto-dialog.html#_1","title":"\u81ea\u52a8\u663e\u793a","text":"<pre><code>scopeDialog {\n tv.text = Post&lt;String&gt;(Api.PATH) {\n param(\"username\", \"\u7528\u6237\u540d\") // \u8bf7\u6c42\u53c2\u6570\n param(\"pwd\", \"123456\")\n }.await()\n}\n</code></pre> <p>\u9ed8\u8ba4\u662f\u539f\u751f\u52a0\u8f7d\u6846(MaterialDesign Dialog), \u53ef\u81ea\u5b9a\u4e49</p> <p></p>"},{"location":"auto-dialog.html#_2","title":"\u5355\u4f8b\u81ea\u5b9a\u4e49","text":"<p>\u6307\u5b9a\u5f53\u524d\u8bf7\u6c42\u52a0\u8f7d\u6846</p> <pre><code>val dialog = BubbleDialog(requireActivity(), \"\u52a0\u8f7d\u4e2d\")\n\nscopeDialog(dialog) {\n tv.text = Post&lt;String&gt;(Api.PATH) {\n param(\"username\", \"\u7528\u6237\u540d\")\n param(\"pwd\", \"123456\")\n }.await()\n}\n</code></pre> <p></p> <p>\u83ca\u82b1\u52a0\u8f7d\u5bf9\u8bdd\u6846</p> <p>\u793a\u4f8b\u4f7f\u7528\u7684iOS\u98ce\u683c\u5bf9\u8bdd\u6846: BubbleDialog</p>"},{"location":"auto-dialog.html#_3","title":"\u5168\u5c40\u81ea\u5b9a\u4e49","text":"<p>\u521d\u59cb\u5316\u65f6\u6307\u5b9a\u52a0\u8f7d\u5bf9\u8bdd\u6846\u6784\u9020\u5668<code>NetDialogFactory</code></p> <pre><code>NetConfig.initialize(Api.HOST, this) {\n setDialogFactory {\n ProgressDialog(it).apply {\n setMessage(\"\u6211\u662f\u5168\u5c40\u81ea\u5b9a\u4e49\u7684\u52a0\u8f7d\u5bf9\u8bdd\u6846...\")\n }\n }\n}\n</code></pre> <p>\u5982\u4ec5\u4fee\u6539\u52a0\u8f7d\u5bf9\u8bdd\u6846\u6587\u672c, \u5728\u9879\u76ee<code>values</code>\u76ee\u5f55\u7684strings.xml\u6dfb\u52a0\u4ee5\u4e0b</p> <pre><code>&lt;!--\u5bf9\u8bdd\u6846--&gt;\n&lt;string name=\"net_dialog_msg\"&gt;\u52a0\u8f7d\u4e2d&lt;/string&gt;\n</code></pre> <p>\u81ea\u5b9a\u4e49\u7684\u52a0\u8f7d\u6846\u4e0d\u662fDialog</p> <p>\u7531\u4e8e<code>scopeDialog</code>\u53ea\u80fd\u6307\u5b9aDialog\u7c7b\u578b, \u56e0\u6b64\u53ea\u80fd\u624b\u52a8\u5b9e\u73b0<code>Dialog</code>\u63a5\u53e3</p> <p>\u4ec5\u8981\u6c42\u590d\u5199 DialogCoroutineScope \u5185\u8c03\u7528\u7684<code>Dialog</code>\u65b9\u6cd5</p>"},{"location":"auto-dialog.html#_4","title":"\u751f\u547d\u5468\u671f","text":"<p>\u4f7f\u7528<code>scopeDialog</code>\u53d1\u8d77\u8bf7\u6c42\u540e, \u5206\u4e3a\u4e09\u4e2a\u751f\u547d\u5468\u671f</p> \u52a0\u8f7d\u6846\u72b6\u6001 \u4f5c\u7528\u57df \u663e\u793a \u6267\u884c<code>scopeDialog</code>\u65f6\u663e\u793a\u52a0\u8f7d\u6846 \u9690\u85cf \u4f5c\u7528\u57df\u5185\u4efb\u52a1\u7ed3\u675f\u65f6\u9690\u85cf\u52a0\u8f7d\u6846 \u624b\u52a8\u53d6\u6d88 \u53d6\u6d88\u4f5c\u7528\u57df\u5185\u6240\u6709\u7f51\u7edc\u8bf7\u6c42"},{"location":"auto-pull.html","title":"\u81ea\u52a8\u5206\u9875\u52a0\u8f7d","text":"<p>\u9996\u5148\u8bf7\u9605\u8bfb\u4e0a\u7ae0\u8282 \u81ea\u52a8\u4e0b\u62c9\u5237\u65b0, \u5df2\u63d0\u53ca\u5185\u5bb9\u4e0d\u518d\u91cd\u590d</p>"},{"location":"auto-pull.html#_1","title":"\u81ea\u52a8\u5206\u9875","text":"<p>\u63d0\u4f9b<code>addData()</code>\u6765\u7b80\u5316\u5206\u9875, \u5f00\u53d1\u8005\u53ef\u4ee5\u501f\u9274\u5b9e\u73b0</p> <pre><code>page.onRefresh {\n scope {\n val data = Get&lt;Game&gt;(Api.PATH) {\n param(\"page\", index)\n }.await().data\n addData(data.list) {\n index &lt; data.total\n }\n }\n}.autoRefresh()\n</code></pre>"},{"location":"auto-pull.html#_2","title":"\u7d22\u5f15\u81ea\u589e","text":"<p><code>index</code> \u6bcf\u6b21\u4e0a\u62c9\u52a0\u8f7d\u81ea\u52a8++1, \u5237\u65b0\u5217\u8868\u91cd\u7f6e\u4e3a<code>PageRefreshLayout.startIndex</code></p>"},{"location":"auto-pull.html#_3","title":"\u6709\u66f4\u591a\u9875","text":"<p>\u6839\u636e<code>hasMore</code>\u8fd4\u56de\u7ed3\u679c\u662f\u5426\u5173\u95ed\u4e0a\u62c9\u52a0\u8f7d, <code>isEmpty</code>\u51b3\u5b9a\u662f\u5426\u663e\u793a<code>\u7a7a\u6570\u636e</code>\u7f3a\u7701\u9875</p> <pre><code>fun addData(\n data: List&lt;Any?&gt;?,\n adapter: BindingAdapter? = null,\n isEmpty: () -&gt; Boolean = { data.isNullOrEmpty() },\n hasMore: BindingAdapter.() -&gt; Boolean = { true }\n)\n</code></pre> <p> 1. PageRefreshLayout \u4e0b\u62c9\u5237\u65b0/\u4e0a\u62c9\u52a0\u8f7d</p>"},{"location":"auto-refresh.html","title":"\u81ea\u52a8\u4e0b\u62c9\u5237\u65b0","text":"<p>\u6a21\u5757\u5316\u4f9d\u8d56</p> <p>\u5982\u679c\u81ea\u5df1\u5904\u7406\u4e0b\u62c9\u5237\u65b0\u53ef\u8df3\u8fc7\u672c\u7ae0, Net\u53ef\u4ee5\u4ec5\u4ec5\u4f5c\u4e3a\u7b80\u5355\u7684\u7f51\u7edc\u6846\u67b6\u5b58\u5728</p> <p> Net\u53ef\u4f9d\u8d56\u4e09\u65b9\u5e93 BRV \u5b9e\u73b0\u81ea\u52a8\u5904\u7406\u4e0b\u62c9\u5237\u65b0</p> <p></p> <pre><code>implementation 'com.github.liangjingkanji:BRV:+' // \u4f7f\u7528\u56fa\u5b9a\u7248\u672c\u53f7\u66ff\u6362+\u7b26\u53f7\n</code></pre>"},{"location":"auto-refresh.html#pagerefreshlayout","title":"PageRefreshLayout","text":"<pre><code>&lt;com.drake.brv.PageRefreshLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:tools=\"http://schemas.android.com/tools\"\n xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n android:id=\"@+id/page\"\n android:layout_width=\"match_parent\"\n android:layout_height=\"match_parent\"\n tools:context=\".ui.fragment.PushRefreshFragment\"&gt;\n\n &lt;androidx.recyclerview.widget.RecyclerView\n android:id=\"@+id/rv_push\"\n android:layout_width=\"match_parent\"\n android:layout_height=\"match_parent\" /&gt;\n\n&lt;/com.drake.brv.PageRefreshLayout&gt;\n</code></pre>"},{"location":"auto-refresh.html#_1","title":"\u521b\u5efa\u5217\u8868","text":"<pre><code>rv_push.linear().setup {\n addType&lt;String&gt;(R.layout.item_list)\n}\n</code></pre>"},{"location":"auto-refresh.html#_2","title":"\u7f51\u7edc\u8bf7\u6c42","text":"<ol> <li>\u8bf7\u6c42\u5f00\u59cb, \u663e\u793a\u4e0b\u62c9\u5237\u65b0\u52a8\u753b</li> <li>\u8bf7\u6c42\u6210\u529f, \u663e\u793a<code>\u5185\u5bb9</code>\u7f3a\u7701\u9875</li> <li>\u8bf7\u6c42\u5931\u8d25, \u663e\u793a<code>\u9519\u8bef</code>\u7f3a\u7701\u9875</li> </ol> <pre><code>page.onRefresh {\n scope {\n // \u8bf7\u6c42\u5230\u6570\u636e\u8bbe\u7f6e\u5230RecyclerView\n rv_push.models = Get&lt;Game&gt;(Api.PATH).await().data.list\n }\n}.autoRefresh()\n</code></pre>"},{"location":"auto-refresh.html#_3","title":"\u751f\u547d\u5468\u671f","text":"\u751f\u547d\u5468\u671f \u63cf\u8ff0 \u5f00\u59cb <code>showLoading/autoRefresh</code>\u89e6\u53d1<code>onRefresh</code>, \u5f00\u59cb\u8bf7\u6c42 \u7ed3\u675f PageRefreshLayout\u88ab\u9500\u6bc1, \u8bf7\u6c42\u81ea\u52a8\u53d6\u6d88"},{"location":"auto-state.html","title":"\u81ea\u52a8\u7f3a\u7701\u9875","text":"<p>\u6a21\u5757\u5316\u4f9d\u8d56</p> <p>\u5982\u679c\u81ea\u5df1\u5904\u7406\u7f3a\u7701\u9875\u53ef\u8df3\u8fc7\u672c\u7ae0, Net\u53ef\u4ee5\u4ec5\u4ec5\u4f5c\u4e3a\u7b80\u5355\u7684\u7f51\u7edc\u6846\u67b6\u5b58\u5728</p> <p> Net\u53ef\u4f9d\u8d56\u4e09\u65b9\u5e93\u5b9e\u73b0\u81ea\u52a8\u7f3a\u7701\u9875, \u4ee5\u4e0b\u4e8c\u9009\u4e00\u4f9d\u8d56</p> <ol> <li>\u4f9d\u8d56 StateLayout <pre><code>implementation 'com.github.liangjingkanji:StateLayout:+' // \u4f7f\u7528\u56fa\u5b9a\u7248\u672c\u53f7\u66ff\u6362+\u7b26\u53f7\n</code></pre></li> <li>\u4f9d\u8d56 BRV (\u56e0\u4e3aBRV\u5305\u542bStateLayout) <pre><code>implementation 'com.github.liangjingkanji:BRV:+' // \u4f7f\u7528\u56fa\u5b9a\u7248\u672c\u53f7\u66ff\u6362+\u7b26\u53f7\n</code></pre></li> </ol>"},{"location":"auto-state.html#_1","title":"\u521d\u59cb\u5316","text":"<p>\u5728Application\u4e2d\u521d\u59cb\u5316\u7f3a\u7701\u9875</p> <pre><code>StateConfig.apply {\n emptyLayout = R.layout.layout_empty\n loadingLayout = R.layout.layout_loading\n errorLayout = R.layout.layout_error\n}\n</code></pre>"},{"location":"auto-state.html#_2","title":"\u521b\u5efa","text":"<p>\u4f7f\u7528<code>StateLayout</code>\u5305\u88f9\u7684\u5185\u5bb9\u5373<code>\u5185\u5bb9</code>(content)</p> <pre><code>&lt;com.drake.statelayout.StateLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:tools=\"http://schemas.android.com/tools\"\n android:layout_width=\"match_parent\"\n android:id=\"@+id/state\"\n android:layout_height=\"match_parent\"\n tools:context=\".ui.fragment.StateLayoutFragment\"&gt;\n\n &lt;TextView\n android:id=\"@+id/tv\"\n android:padding=\"32dp\"\n android:textStyle=\"bold\"\n android:layout_width=\"match_parent\"\n android:layout_height=\"match_parent\"\n android:text=\"\u5185\u5bb9\" /&gt;\n\n&lt;/com.drake.statelayout.StateLayout&gt;\n</code></pre>"},{"location":"auto-state.html#_3","title":"\u7f51\u7edc\u8bf7\u6c42","text":"<ol> <li>\u8bf7\u6c42\u5f00\u59cb, \u663e\u793a<code>\u52a0\u8f7d\u4e2d</code>\u7f3a\u7701\u9875</li> <li>\u8bf7\u6c42\u6210\u529f, \u663e\u793a<code>\u5185\u5bb9</code>\u7f3a\u7701\u9875</li> <li>\u8bf7\u6c42\u5931\u8d25, \u663e\u793a<code>\u9519\u8bef</code>\u7f3a\u7701\u9875</li> </ol> <p><pre><code>state.onRefresh {\n scope {\n tv.text = Get&lt;String&gt;(Api.PATH).await()\n }\n}.showLoading()\n</code></pre> </p>"},{"location":"auto-state.html#_4","title":"\u751f\u547d\u5468\u671f","text":"\u751f\u547d\u5468\u671f \u63cf\u8ff0 \u5f00\u59cb <code>showLoading</code>\u89e6\u53d1<code>onRefresh</code>, \u5f00\u59cb\u8bf7\u6c42 \u7ed3\u675f \u7f3a\u7701\u9875\u88ab\u9500\u6bc1, \u8bf7\u6c42\u81ea\u52a8\u53d6\u6d88"},{"location":"cache.html","title":"\u7f13\u5b58","text":""},{"location":"cache.html#_1","title":"\u7f13\u5b58\u4f18\u52bf","text":"<ol> <li>\u9875\u9762\u79d2\u5f00</li> <li>\u51cf\u5c11\u670d\u52a1\u5668\u538b\u529b</li> <li>\u65e0\u7f51\u7edc\u53ef\u7528</li> </ol>"},{"location":"cache.html#net","title":"Net\u7f13\u5b58\u7279\u70b9","text":"<ol> <li>\u7f13\u5b58\u4efb\u4f55\u8bf7\u6c42\u65b9\u5f0f</li> <li>\u7f13\u5b58\u4efb\u4f55\u6570\u636e, File/\u56fe\u7247/JSON/ProtoBuf\u7b49</li> <li>\u9650\u5236\u6700\u5927\u7f13\u5b58\u7a7a\u95f4</li> <li>\u4f7f\u7528<code>DiskLruCache</code>\u5b9e\u73b0, \u5220\u9664\u6700\u8fd1\u6700\u5c11\u4f7f\u7528</li> </ol>"},{"location":"cache.html#_2","title":"\u914d\u7f6e\u7f13\u5b58","text":"<p>\u4e0d\u914d\u7f6e<code>Cache</code>\u662f\u4e0d\u4f1a\u542f\u7528\u7f13\u5b58\u7684 <pre><code>NetConfig.initialize(Api.HOST, this) {\n // Net\u652f\u6301Http\u7f13\u5b58\u534f\u8bae\u548c\u5f3a\u5236\u7f13\u5b58\u6a21\u5f0f\n // \u5f53\u8d85\u8fc7maxSize\u6700\u5927\u503c\u4f1a\u6839\u636e\u6700\u8fd1\u6700\u5c11\u4f7f\u7528\u7b97\u6cd5\u6e05\u9664\u7f13\u5b58\u6765\u9650\u5236\u7f13\u5b58\u5927\u5c0f\n cache(Cache(cacheDir, 1024 * 1024 * 128))\n}\n</code></pre></p> <p>\u5224\u65ad\u54cd\u5e94\u6765\u81ea\u7f13\u5b58</p> <p>\u5982\u679c<code>Response.cacheResponse</code>\u4e0d\u4e3anull\u7684\u65f6, \u4ee3\u8868Response\u6765\u81ea\u672c\u5730\u7f13\u5b58</p>"},{"location":"cache.html#http","title":"Http\u7f13\u5b58\u534f\u8bae","text":"<p>OkHttp\u9ed8\u8ba4\u7684Http\u7f13\u5b58\u534f\u8bae\u63a7\u5236, \u8981\u6c42\u4ee5\u4e0b\u6761\u4ef6</p> <ul> <li>Get\u8bf7\u6c42\u65b9\u5f0f</li> <li>\u7f13\u5b58\u4f7f\u7528Url\u4e3akey, \u56e0\u6b64Url\u6539\u53d8\u4f1a\u8bfb\u4e0d\u5230\u7f13\u5b58</li> <li>\u54cd\u5e94\u5934\u63a7\u5236\u7f13\u5b58: Cache-Control</li> </ul> <p> \u901a\u8fc7<code>setCacheControl</code>\u53ef\u4ee5\u63a7\u5236Http\u7f13\u5b58\u534f\u8bae, \u539f\u7406\u662f\u4fee\u6539\u8bf7\u6c42\u5934</p> <pre><code>scopeNetLife {\n Post&lt;String&gt;(Api.PATH) {\n setCacheControl(CacheControl.FORCE_CACHE) // \u5f3a\u5236\u4f7f\u7528\u7f13\u5b58\n // setCacheControl(CacheControl.FORCE_NETWORK) // \u5f3a\u5236\u4f7f\u7528\u7f51\u7edc\n // setCacheControl(CacheControl.Builder().noStore().noCache().build()) // \u7981\u6b62\u7f13\u5b58\n }.await()\n}\n</code></pre> <p>\u5982\u679c\u65e0\u6cd5\u5b9e\u73b0Http\u6807\u51c6\u7f13\u5b58\u534f\u8bae, \u6216\u8981\u7f13\u5b58Get\u4ee5\u5916\u7684\u8bf7\u6c42\u65b9\u6cd5, \u53ef\u4ee5\u4f7f\u7528<code>\u5f3a\u5236\u7f13\u5b58\u6a21\u5f0f</code></p>"},{"location":"cache.html#_3","title":"\u5f3a\u5236\u7f13\u5b58\u6a21\u5f0f","text":"<p>\u65e0\u8bba\u5f53\u524d\u8bf7\u6c42\u662f\u5426\u5b58\u5728Http\u6807\u51c6\u7f13\u5b58\u534f\u8bae, \u5f53\u8bbe\u7f6e\u5f3a\u5236\u7f13\u5b58\u6a21\u5f0f\u65f6\u4f1a\u65e0\u89c6Http\u7f13\u5b58\u534f\u8bae</p> <pre><code>scopeNetLife {\n tv.text =\n Post&lt;String&gt;(Api.PATH) {\n setCacheMode(CacheMode.REQUEST_THEN_READ) // \u8bf7\u6c42\u7f51\u7edc\u5931\u8d25\u4f1a\u8bfb\u53d6\u7f13\u5b58, \u8bf7\u65ad\u7f51\u6d4b\u8bd5\n }.await()\n}\n</code></pre> \u5f3a\u5236\u7f13\u5b58\u6a21\u5f0f \u63cf\u8ff0 READ \u53ea\u8bfb\u53d6\u7f13\u5b58, \u8bfb\u4e0d\u5230<code>NoCacheException</code> WRITE \u53ea\u8bf7\u6c42\u7f51\u7edc, \u5f3a\u5236\u5199\u5165\u7f13\u5b58 READ_THEN_REQUEST \u5148\u4ece\u7f13\u5b58\u8bfb\u53d6\uff0c\u5982\u679c\u5931\u8d25\u518d\u4ece\u7f51\u7edc\u8bfb\u53d6, \u5f3a\u5236\u5199\u5165\u7f13\u5b58 REQUEST_THEN_READ \u5148\u4ece\u7f51\u7edc\u8bfb\u53d6\uff0c\u5982\u679c\u5931\u8d25\u518d\u4ece\u7f13\u5b58\u8bfb\u53d6, \u5f3a\u5236\u5199\u5165\u7f13\u5b58"},{"location":"cache.html#key","title":"\u81ea\u5b9a\u7f13\u5b58Key","text":"<p>\u4ec5<code>\u5f3a\u5236\u7f13\u5b58\u6a21\u5f0f</code>\u6709\u6548, \u7f13\u5b58Key\u9ed8\u8ba4\u662f<code>\u8bf7\u6c42\u65b9\u5f0f+URL</code>\u540e\u4ea7\u751f\u7684<code>sha1\u503c</code></p> <p>\u5982\u679c\u8981\u7f13\u5b58\u533a\u522b\u8bf7\u6c42\u53c2\u6570, \u8bf7\u81ea\u5b9a\u4e49\u7f13\u5b58key</p> <pre><code>scopeNetLife {\n tv.text =\n Post&lt;String&gt;(Api.PATH) {\n setCacheMode(CacheMode.REQUEST_THEN_READ) // \u8bf7\u6c42\u7f51\u7edc\u5931\u8d25\u4f1a\u8bfb\u53d6\u7f13\u5b58, \u8bf7\u65ad\u7f51\u6d4b\u8bd5\n setCacheKey(\"\u8bf7\u6c42\u70ed\u95e8\u4fe1\u606f\" + params) // \u5177\u4f53\u503c\u90fd\u884c\n }.await()\n}\n</code></pre>"},{"location":"cache.html#_4","title":"\u7f13\u5b58\u6709\u6548\u671f","text":"<ol> <li>\u4ec5<code>\u5f3a\u5236\u7f13\u5b58\u6a21\u5f0f</code>\u6709\u6548, \u6807\u51c6Http\u7f13\u5b58\u534f\u8bae\u9075\u5b88\u534f\u8bae\u672c\u8eab\u7684\u6709\u6548\u671f</li> <li>\u7f13\u5b58\u6709\u6548\u671f\u8fc7\u671f\u53ea\u662f\u8ba9\u7f13\u5b58\u65e0\u6548, \u4e0d\u4f1a\u7acb\u5373\u5220\u9664 \u6839\u636e(\u6700\u8fd1\u6700\u5c11\u4f7f\u7528)\u539f\u5219\u5728\u7f13\u5b58\u7a7a\u95f4\u8fbe\u5230\u914d\u7f6e\u503c\u65f6\u5220\u9664(\u5373\u4f7f\u7f13\u5b58\u6709\u6548\u671f\u672a\u5230)</li> </ol> <pre><code>scopeNetLife {\n tv.text =\n Post&lt;String&gt;(Api.PATH) {\n setCacheMode(CacheMode.REQUEST_THEN_READ) // \u8bf7\u6c42\u7f51\u7edc\u5931\u8d25\u4f1a\u8bfb\u53d6\u7f13\u5b58, \u8bf7\u65ad\u7f51\u6d4b\u8bd5\n setCacheValidTime(1, TimeUnit.DAYS) // \u7f13\u5b58\u4ec5\u4e00\u5929\u5185\u6709\u6548\n }.await()\n}\n</code></pre>"},{"location":"cache.html#_5","title":"\u9884\u89c8(\u7f13\u5b58+\u7f51\u7edc)","text":"<p>\u9884\u89c8\u53c8\u53ef\u4ee5\u7406\u89e3\u4e3a\u56de\u9000\u8bf7\u6c42, \u4e00\u822c\u7528\u4e8e\u79d2\u5f00\u9996\u9875\u6216\u8005\u56de\u9000\u52a0\u8f7d\u6570\u636e</p> <pre><code>scopeNetLife {\n // \u7136\u540e\u6267\u884c\u8fd9\u91cc(\u7f51\u7edc\u8bf7\u6c42)\n tv.text = Get&lt;String&gt;(Api.PATH) {\n setCacheMode(CacheMode.WRITE)\n }.await()\n Log.d(\"\u65e5\u5fd7\", \"\u7f51\u7edc\u8bf7\u6c42\")\n}.preview {\n // \u5148\u6267\u884c\u8fd9\u91cc(\u4ec5\u8bfb\u7f13\u5b58), \u4efb\u4f55\u5f02\u5e38\u90fd\u89c6\u4e3a\u8bfb\u53d6\u7f13\u5b58\u5931\u8d25\n tv.text = Get&lt;String&gt;(Api.PATH) {\n setCacheMode(CacheMode.READ)\n }.await()\n Log.d(\"\u65e5\u5fd7\", \"\u8bfb\u53d6\u7f13\u5b58\")\n}\n</code></pre> <p>\u9884\u89c8\u548c\u52a0\u8f7d\u4e24\u6b21\u6709\u4ec0\u4e48\u533a\u522b?</p> <p>\u533a\u522b\u662f<code>preview</code>\u53ef\u4ee5\u63a7\u5236\u4ee5\u4e0b\u884c\u4e3a</p> <ol> <li><code>breakError</code> \u8bfb\u53d6\u7f13\u5b58\u6210\u529f\u540e\u4e0d\u518d\u5904\u7406\u8bf7\u6c42\u7684\u9519\u8bef, \u9ed8\u8ba4false</li> <li><code>breakLoading</code> \u8bfb\u53d6\u7f13\u5b58\u6210\u529f\u540e\u7acb\u523b\u7ed3\u675f\u52a0\u8f7d\u52a8\u753b, \u9ed8\u8ba4true</li> </ol>"},{"location":"callback.html","title":"Callback","text":"<p>Net\u652f\u6301OkHttp\u7684\u539f\u6709\u7684\u961f\u5217\u8bf7\u6c42<code>Callback</code></p> <p>\u4e0d\u63a8\u8350</p> <p>Callback\u5c5e\u4e8e\u63a5\u53e3\u56de\u8c03, \u5176\u4ee3\u7801\u5197\u4f59, \u4e14\u65e0\u6cd5\u652f\u6301\u5e76\u53d1\u8bf7\u6c42</p> <pre><code>Net.post(Api.PATH).enqueue(object : Callback {\n override fun onFailure(call: Call, e: IOException) {\n }\n\n override fun onResponse(call: Call, response: Response) {\n // \u6b64\u5904\u4e3a\u5b50\u7ebf\u7a0b\n val body = response.body?.string() ?: \"\u65e0\u6570\u636e\"\n runMain {\n // \u6b64\u5904\u4e3a\u4e3b\u7ebf\u7a0b\n tv.text = body\n }\n }\n})\n</code></pre>"},{"location":"cancel.html","title":"\u53d6\u6d88\u8bf7\u6c42","text":"<p>\u90e8\u5206\u573a\u666f\u5f00\u53d1\u8005\u60f3\u624b\u52a8\u53d6\u6d88\u8bf7\u6c42</p> <pre><code>downloadScope = scopeNetLife {\n // \u4e0b\u8f7d\u6587\u4ef6\n val file = Get&lt;File&gt;(Api.DOWNLOAD).await()\n}\n\ndownloadScope.cancel() // \u53d6\u6d88\u4e0b\u8f7d\n</code></pre>"},{"location":"cancel.html#_1","title":"\u4efb\u610f\u4f4d\u7f6e\u53d6\u6d88","text":"<p>\u53d1\u8d77\u8bf7\u6c42\u65f6\u6307\u5b9a<code>Id</code></p> <pre><code>scopeNetLife {\n tv.text = Get&lt;String&gt;(Api.DOWNLOAD){\n setId(\"\u8bf7\u6c42\u7528\u6237\u4fe1\u606f\")\n }.await()\n}\n</code></pre> \u6839\u636eID\u53d6\u6d88\u6839\u636eGroup\u53d6\u6d88 <pre><code>Net.cancelId(\"\u8bf7\u6c42\u7528\u6237\u4fe1\u606f\")\n</code></pre> <pre><code>Net.cancelGroup(\"\u8bf7\u6c42\u5206\u7ec4\u540d\u79f0\")\n</code></pre>"},{"location":"cancel.html#groupid","title":"Group\u548cId\u533a\u522b","text":"\u51fd\u6570 \u63cf\u8ff0 id \u8bf7\u6c42\u552f\u4e00Id, \u5b9e\u9645\u4e0a\u91cd\u590d\u4e5f\u884c, \u4f46\u662f\u53d6\u6d88\u8bf7\u6c42\u65f6\u904d\u5386\u5230\u6307\u5b9aId\u5c31\u4f1a\u7ed3\u675f\u904d\u5386 group \u5141\u8bb8\u591a\u4e2a\u8bf7\u6c42\u4f7f\u7528\u76f8\u540cgroup, \u5728\u53d6\u6d88\u8bf7\u6c42\u65f6\u4f1a\u904d\u5386\u6240\u6709\u5206\u7ec4\u7684\u8bf7\u6c42 <p>\u4f5c\u7528\u57df\u7ed3\u675f\u8bf7\u6c42\u81ea\u52a8\u53d6\u6d88</p> <p>\u5728<code>scopeXX()</code>\u4f5c\u7528\u57df\u4e2d\u53d1\u8d77\u8bf7\u6c42\u65f6\u4f1a\u9ed8\u8ba4\u4f7f\u7528\u5f53\u524d\u534f\u7a0b\u9519\u8bef\u5904\u7406\u5668\u4f5c\u4e3aGroup <pre><code>setGroup(coroutineContext[CoroutineExceptionHandler])\n</code></pre> \u5728\u4f5c\u7528\u57df\u7ed3\u675f\u65f6 \u4f1a<code>cancelGroup</code>, \u6240\u4ee5\u5982\u679c\u4f60\u624b\u52a8\u6307\u5b9a\u5206\u7ec4\u4f1a\u5bfc\u81f4\u65e0\u6cd5\u81ea\u52a8\u53d6\u6d88</p>"},{"location":"config.html","title":"\u5168\u5c40\u914d\u7f6e","text":"<p>\u5168\u5c40\u914d\u7f6e\u5e94\u5728<code>Application.onCreate</code>\u4e2d\u914d\u7f6e</p>"},{"location":"config.html#_1","title":"\u521d\u59cb\u914d\u7f6e","text":"<p>\u4e24\u79cd\u65b9\u5f0f\u521d\u59cb\u914d\u7f6e, \u4e0d\u521d\u59cb\u5316\u4e5f\u80fd\u76f4\u63a5\u4f7f\u7528</p> Net\u521d\u59cb\u5316OkHttp\u6784\u9020\u5668\u521d\u59cb\u5316 <pre><code>NetConfig.initialize(Api.HOST, this) {\n // \u8d85\u65f6\u914d\u7f6e, \u9ed8\u8ba4\u662f10\u79d2, \u8bbe\u7f6e\u592a\u957f\u65f6\u95f4\u4f1a\u5bfc\u81f4\u7528\u6237\u7b49\u5f85\u8fc7\u4e45\n connectTimeout(30, TimeUnit.SECONDS)\n readTimeout(30, TimeUnit.SECONDS)\n writeTimeout(30, TimeUnit.SECONDS)\n setDebug(BuildConfig.DEBUG)\n setConverter(SerializationConverter())\n}\n</code></pre> <pre><code>val okHttpClientBuilder = OkHttpClient.Builder()\n .setDebug(BuildConfig.DEBUG)\n .setConverter(SerializationConverter())\n .addInterceptor(LogRecordInterceptor(BuildConfig.DEBUG))\nNetConfig.initialize(Api.HOST, this, okHttpClientBuilder)\n</code></pre> <p>\u5982\u679c\u8bf7\u6c42\u6307\u5b9aPath\u4f1a\u548c\u4e0a\u9762<code>Api.HOST</code>\u7ec4\u6210Url\u540e\u53d1\u8d77\u8bf7\u6c42</p> <p>\u5f3a\u5236\u521d\u59cb\u5316</p> <p>\u5982\u679c\u662f\u591a\u8fdb\u7a0b\u9879\u76ee(\u4f8b\u5982Xposed)\u5fc5\u987b\u521d\u59cb\u5316, \u56e0\u4e3a\u591a\u8fdb\u7a0b\u65e0\u6cd5\u81ea\u52a8\u6307\u5b9aContext</p> \u53ef\u914d\u7f6e\u9009\u9879 \u63cf\u8ff0 setDebug \u5f00\u542f\u65e5\u5fd7 setSSLCertificate \u914d\u7f6eHttps\u8bc1\u4e66 trustSSLCertificate \u4fe1\u4efb\u6240\u6709Https\u8bc1\u4e66 setConverter \u8f6c\u6362\u5668, \u5c06\u8bf7\u6c42\u7ed3\u679c\u8f6c\u4e3a\u4efb\u4f55\u7c7b\u578b setRequestInterceptor \u8bf7\u6c42\u62e6\u622a\u5668, \u5168\u5c40\u8bf7\u6c42\u5934/\u8bf7\u6c42\u53c2\u6570 setErrorHandler \u5168\u5c40\u9519\u8bef\u5904\u7406 setDialogFactory \u5168\u5c40\u5bf9\u8bdd\u6846 <p>\u4fee\u6539\u914d\u7f6e</p> <p>NetConfig\u5b58\u50a8\u6240\u6709\u5168\u5c40\u914d\u7f6e\u53d8\u91cf, \u53ef\u4ee5\u540e\u7eed\u4fee\u6539, \u4e14\u5927\u90e8\u5206\u652f\u6301\u5355\u4f8b\u6307\u5b9a\u914d\u7f6e</p>"},{"location":"config.html#_2","title":"\u91cd\u8bd5\u6b21\u6570","text":"<p>\u53ef\u4ee5\u6dfb\u52a0<code>RetryInterceptor</code>\u62e6\u622a\u5668\u5373\u53ef\u5b9e\u73b0\u5931\u8d25\u4ee5\u540e\u4f1a\u91cd\u8bd5\u6307\u5b9a\u6b21\u6570</p> <p>\u9ed8\u8ba4\u60c5\u51b5\u4e0b\u8bbe\u7f6e\u8d85\u65f6\u65f6\u95f4\u5373\u53ef, OkHttp\u5185\u90e8\u4e5f\u6709\u91cd\u8bd5\u673a\u5236</p> <pre><code>NetConfig.initialize(Api.HOST, this) {\n // ... \u5176\u4ed6\u914d\u7f6e\n addInterceptor(RetryInterceptor(3)) // \u5982\u679c\u5168\u90e8\u5931\u8d25\u4f1a\u91cd\u8bd5\u4e09\u6b21\n}\n</code></pre> <p>\u957f\u65f6\u95f4\u963b\u788d\u7528\u6237\u4ea4\u4e92</p> <p>OkHttp\u5185\u90e8\u4e5f\u6709\u91cd\u8bd5\u673a\u5236, \u5982\u679c\u8fd8\u6dfb\u52a0\u91cd\u8bd5\u62e6\u622a\u5668\u53ef\u80fd\u5bfc\u81f4\u8bf7\u6c42\u65f6\u95f4\u8fc7\u957f, \u957f\u65f6\u95f4\u963b\u788d\u7528\u6237\u4ea4\u4e92</p>"},{"location":"config.html#_3","title":"\u591a\u57df\u540d","text":"<p>Net\u53ef\u968f\u65f6\u53d8\u66f4\u8bf7\u6c42\u57df\u540d, \u4ee5\u4e0b\u4ecb\u7ecd\u4e09\u79cd\u65b9\u5f0f</p> \u4fee\u6539Host\u6307\u5b9a\u5168\u8def\u5f84\u4f7f\u7528\u62e6\u622a\u5668 <pre><code>NetConfig.host = Api.HOST_VIDEO\n</code></pre> <p>\u5efa\u8bae\u4f7f\u7528\u5355\u4f8b\u7c7b\u7ba1\u7406\u8bf7\u6c42Url <pre><code>object Api {\n const val HOST_IMG = \"http://127.0.0.1\"\n const val BANNER = \"$HOST_IMG/banner\"\n const val HOME = \"/home\"\n}\nscopeNetLife {\n val banner = Get&lt;BannerModel&gt;(Api.BANNER).await()\n val home = Get&lt;HomeModel&gt;(Api.HOME).await()\n}\n</code></pre></p> <p>\u8bf7\u6c42\u6307\u5b9a<code>tag</code>, \u62e6\u622a\u5668\u4e2d\u6839\u636etag\u4fee\u6539Url, \u5efa\u8baetag\u4e3a\u5305\u542b\u57df\u540d\u7684\u679a\u4e3e\u6216\u5355\u4f8b <pre><code>scopeNetLife {\n val data = Get&lt;String&gt;(Api.PATH, GAME).await() // User\u5373\u4e3atag\n}\n// \u62e6\u622a\u5668\u5982\u4f55\u4fee\u6539\u8bf7\u641c\u7d22\n</code></pre></p>"},{"location":"config.html#_4","title":"\u7f51\u7edc\u5b89\u5168\u914d\u7f6e","text":"<p>Net\u81ea\u52a8\u542f\u7528\u7f51\u7edc\u914d\u7f6e\u6587\u4ef6, \u9ed8\u8ba4\u652f\u6301Http\u8bf7\u6c42, \u53ef\u81ea\u5b9a\u4e49</p> network_security_config.xml<pre><code>&lt;network-security-config&gt;\n &lt;base-config cleartextTrafficPermitted=\"true\" /&gt;\n&lt;/network-security-config&gt;\n</code></pre> <p>\u65e0\u6cd5\u6253\u5305Apk</p> <p>\u5f53\u5f00\u53d1\u8005\u81ea\u5b9a\u4e49\u4f7f\u7528\u975e\u540c\u540d<code>network_security_config</code>\u65f6\u7f51\u7edc\u914d\u7f6e\u6587\u4ef6\u65f6\u4f1a\u65e0\u6cd5\u6253\u5305Apk</p> <p>\u8bf7\u6dfb\u52a0<code>tools:replace</code> AndroidManifest.xml<pre><code>&lt;application\n tools:replace=\"android:networkSecurityConfig\"&gt;\n</code></pre></p>"},{"location":"converter-customize.html","title":"\u81ea\u5b9a\u4e49\u8f6c\u6362\u5668","text":"<p>Net\u81ea\u5b9a\u4e49\u8f6c\u6362\u5668\u53ef\u652f\u6301\u4efb\u4f55\u6570\u636e\u7c7b\u578b, \u751a\u81f3<code>Bitmap</code></p> <p>\u6cdb\u578b\u548c\u8f6c\u6362\u5668\u5173\u7cfb</p> <ol> <li>\u5982\u679c<code>Post&lt;Model&gt;</code>, \u90a3\u4e48<code>NetConverter.onConvert</code>\u8fd4\u56de\u503c\u5fc5\u987b\u4e3aModel</li> <li>\u5982\u679c<code>Post&lt;Model?&gt;</code>, \u5141\u8bb8<code>NetConverter.onConvert</code>\u8fd4\u56de\u503c\u4e3anull</li> <li>\u4efb\u4f55\u9519\u8bef\u8bf7\u5728\u8f6c\u6362\u5668\u4e2d\u76f4\u63a5\u629b\u51fa\u5f02\u5e38</li> </ol> <pre><code>scopeNetLife {\n val userList = Get&lt;List&lt;UserModel&gt;&gt;(Api.PATH) {\n converter = GsonConverter()\n }.await()\n}\n</code></pre> <p>Net\u7531\u4e8e\u4f4e\u8026\u5408\u539f\u5219\u4e0d\u81ea\u5e26\u4efb\u4f55\u5e8f\u5217\u5316\u6846\u67b6</p>"},{"location":"converter-customize.html#_1","title":"\u8bbe\u7f6e\u8f6c\u6362\u5668","text":"\u5168\u5c40\u5355\u4f8b <pre><code>NetConfig.initialize(Api.HOST, this) {\n setConverter(SerializationConverter())\n}\n</code></pre> <pre><code>scopeNetLife {\n tv.text = Get&lt;String&gt;(Api.PATH){\n converter = SerializationConverter()\n }.await()\n}\n</code></pre>"},{"location":"converter-customize.html#_2","title":"\u5e38\u89c1\u8f6c\u6362\u5668","text":"<p>\u5b9e\u73b0JSONConverter\u63a5\u53e3\u5feb\u901f\u5b9e\u73b0JSON\u89e3\u6790, \u6216\u76f4\u63a5\u590d\u5236\u4ee5\u4e0b\u8f6c\u6362\u5668\u793a\u4f8b</p> \u5e8f\u5217\u5316\u6846\u67b6 \u793a\u4f8b\u4ee3\u7801 \u63cf\u8ff0 kotlin-serialization SerializationConverter Kotlin\u5b98\u65b9\u5e8f\u5217\u5316\u6846\u67b6 kotlin-serialization ProtobufConverter Kotlin\u5b98\u65b9\u5e8f\u5217\u5316\u6846\u67b6 gson GsonConverter \u8c37\u6b4c\u5e8f\u5217\u5316\u6846\u67b6 fastJson FastJsonConverter \u963f\u91cc\u5df4\u5df4\u5e8f\u5217\u5316\u6846\u67b6 moshi MoshiConverter Square\u5e8f\u5217\u5316\u6846\u67b6"},{"location":"converter-customize.html#_3","title":"\u81ea\u5b9a\u4e49\u8f6c\u6362\u5668","text":"<p>\u8f6c\u6362\u5668\u539f\u7406\u975e\u5e38\u7b80\u5355, \u5b9e\u73b0<code>NetConverter</code>\u63a5\u53e3\u8fd4\u56de\u4e00\u4e2a\u5bf9\u8c61(\u7b49\u4e8e\u8bf7\u6c42\u6cdb\u578b)</p> \u5efa\u8bae\u4fdd\u7559\u9ed8\u8ba4\u652f\u6301\u7684\u7c7b\u578b <pre><code>class CustomizeConverter: NetConverter {\n\n override fun &lt;R&gt; onConvert(succeed: Type, response: Response): R? {\n try {\n return NetConverter.onConvert&lt;R&gt;(succeed, response)\n } catch (e: ConvertException) {\n // ... \u4ec5\u81ea\u5b9a\u4e49\u4e0d\u652f\u6301\u7684\u7c7b\u578b\n return \u4efb\u4f55\u5bf9\u8c61 as R\n }\n }\n}\n</code></pre> <p>\u8f6c\u6362\u5668\u4e2d\u53ef\u4ee5\u6839\u636e\u9519\u8bef\u7801\u629b\u51fa\u81ea\u5b9a\u4e49\u5f02\u5e38</p> \u8f6c\u6362\u5668\u5f02\u5e38\u94fe <pre><code>// \u975eCancellationException/NetException\u53ca\u5176\u5b50\u7c7b\u7684\u4e0a\u629bConvertException\ntry {\n return request.converter().onConvert&lt;R&gt;(type, this) as R\n} catch (e: CancellationException) {\n throw e\n} catch (e: NetException) {\n throw e\n} catch (e: Throwable) {\n throw ConvertException(this, cause = e)\n}\n</code></pre> <ol> <li>\u65e5\u5fd7\u8bb0\u5f55\u5efa\u8bae\u4f7f\u7528\u62e6\u622a\u5668</li> <li>\u8f6c\u6362\u5668\u4e2d\u629b\u51fa\u5f02\u5e38\u88ab\u5168\u5c40\u9519\u8bef\u5904\u7406\u6355\u83b7</li> </ol>"},{"location":"converter-struct.html","title":"\u81ea\u5b9a\u4e49\u7ed3\u6784\u89e3\u6790","text":"<p>\u4e0a\u4e00\u7ae0\u8282\u4ecb\u7ecd\u5982\u4f55\u5e8f\u5217\u5316\u6846\u67b6\u89e3\u6790JSON, \u800c\u672c\u7ae0\u662f\u4ecb\u7ecd\u5982\u4f55\u5b9a\u4e49\u6620\u5c04\u6570\u636e\u7c7b</p>"},{"location":"converter-struct.html#json","title":"JSON","text":"<p>\u89e3\u6790\u63a5\u53e3\u8fd4\u56de\u7684\u5b8c\u6574JSON</p> JSON\u6570\u636e\u7c7b\u7f51\u7edc\u8bf7\u6c42 <pre><code>{\n \"code\":0,\n \"msg\":\"\u8bf7\u6c42\u6210\u529f\",\n \"data\": {\n \"name\": \"\u5f6d\u4e8e\u664f\",\n \"age\": 27,\n \"height\": 180\n }\n}\n</code></pre> <pre><code>data class UserModel (\n var code:Int,\n var msg:String,\n var data:Data,\n) {\n data class Data(var name: String, var age: Int, var height: Int)\n}\n</code></pre> <pre><code>scopeNetLife {\n val data = Get&lt;UserModel&gt;(Api.USER).await().data\n}\n</code></pre> \u4ee5\u4e0a\u8bbe\u8ba1\u4e0d\u5408\u7406 <p>\u6b63\u5e38\u60c5\u51b5\u4e0bHttp\u72b6\u6001\u7801200\u65f6\u53ea\u8fd4\u56de\u6709\u6548\u6570\u636e <pre><code>{\n \"name\": \"\u5f6d\u4e8e\u664f\",\n \"age\": 27,\n \"height\": 180\n}\n</code></pre> \u4efb\u4f55\u975e\u6b63\u5e38\u6d41\u7a0b\u8fd4\u56de200\u72b6\u6001\u7801, \u4f8b\u5982400(\u9519\u8bef\u8bf7\u6c42)/401(\u8ba4\u8bc1\u5931\u8d25) <pre><code>{\n \"code\":412302,\n \"msg\":\"\u5bc6\u7801\u9519\u8bef\",\n}\n</code></pre> \u53ea\u8981\u8ba4\u4e3a\u9700\u8981\u89e3\u6790\u7ed3\u6784\u4f53\u60c5\u51b5\u4e0b, \u90fd\u5e94\u5c5e\u4e8e\u6b63\u5e38\u6d41\u7a0b</p>"},{"location":"converter-struct.html#_1","title":"\u5254\u9664\u65e0\u6548\u5b57\u6bb5","text":"<p>\u4ee5\u4e0b\u6f14\u793a\u4ec5\u89e3\u6790<code>data</code>\u5b57\u6bb5\u8fd4\u56de\u6709\u6548\u6570\u636e</p> <p>\u6b64\u6570\u636e\u7c7b\u53ea\u9700\u8981\u5305\u542bdata\u503c</p> <pre><code>data class UserModel(var name: String, var age: Int, var height: Int)\n</code></pre> <p>\u8f6c\u6362\u5668\u53ea\u89e3\u6790data\u5b57\u6bb5</p> <pre><code>class GsonConvert : JSONConvert(code = \"code\", message = \"msg\", success = \"200\") {\n private val gson = GsonBuilder().serializeNulls().create()\n\n override fun &lt;S&gt; String.parseBody(succeed: Type): S? {\n val data = JSONObject(this).getString(\"data\")\n return gson.fromJson(data, succeed)\n }\n}\n</code></pre> <p>\u8bf7\u6c42\u76f4\u63a5\u8fd4\u56de</p> <pre><code>scopeNetLife {\n val data = Get&lt;UserModel&gt;(Api.USER).await()\n}\n</code></pre>"},{"location":"converter-struct.html#_2","title":"\u4e0d\u89c4\u8303\u6570\u636e","text":"<p>\u63a8\u8350\u5728\u8f6c\u6362\u5668\u4e2d\u89e3\u6790\u4e4b\u524d\u5904\u7406\u597d\u6570\u636e</p> <ol> <li> <p>\u5b57\u6bb5\u503c\u4e3a<code>\"null\"</code>\u800c\u4e0d\u662f<code>null</code>, \u6216\u8005json\u5728\u5b57\u7b26\u4e32\u4e2d <pre><code> {\n \"data\": \"{ \"title\": \"name\" }\"\n \"msg\": \"null\"\n }\n</code></pre> \u66ff\u6362\u4e3a\u89c4\u8303\u5185\u5bb9<pre><code>json = bodyString.replace(\"\\\"{\", \"{\")\njson = bodyString.replace(\"}\\\"\", \"}\")\njson = bodyString.replace(\"\\\"null\\\"\", \"null\")\n</code></pre></p> </li> <li> <p>\u670d\u52a1\u5668\u6210\u529f\u65f6\u4e0d\u8fd4\u56de\u6570\u636e\u6216\u8005\u8fd4\u56de<code>null</code> <pre><code>if (response.body == null || bodyString == \"null\") {\n \"{}\".bodyString.parseBody&lt;R&gt;(succeed)\n}\n</code></pre></p> </li> <li> <p>\u5b57\u6bb5\u503c\u4e3anull, \u4f7f\u7528 kotlin-serialization \u81ea\u52a8\u4f7f\u7528\u5b57\u6bb5\u9ed8\u8ba4\u503c <pre><code>{\n \"msg\": null\n}\n</code></pre></p> </li> <li>\u5b57\u6bb5\u65e0\u5f15\u53f7\u6216\u5b57\u6bb5\u540d\u4e3a\u6570\u5b57, \u4f7f\u7528 kotlin-serialization \u53ef\u4ee5\u7981\u7528JSON\u89c4\u8303\u9650\u5236 \u6570\u5b57\u4f7f\u7528map\u89e3\u6790<pre><code> {\n \"data\": {\n 23: 32\n }\n }\n</code></pre> \u7981\u7528JSON\u89c4\u8303\u9650\u5236<pre><code>val jsonDecoder = Json {\n // ...\n isLenient = true\n}\n</code></pre></li> </ol>"},{"location":"converter-struct.html#_3","title":"\u6cdb\u578b\u6570\u636e\u7c7b","text":"<p>\u67d0\u4e9b\u5730\u533a\u5f88\u591a\u5f00\u53d1\u8005\u4e60\u60ef\u8fd9\u4e48\u4f7f\u7528, \u56e0\u4e3a\u4ed6\u4eec\u63a5\u53e3\u8fd4\u56de\u65e0\u5173\u5b57\u6bb5, \u4f46\u662f\u6280\u672f\u4e0d\u591f\u65e0\u6cd5\u81ea\u5b9a\u4e49\u8f6c\u6362\u5668\u6765\u7b80\u5316\u53d6\u503c</p> <p>\u6240\u4ee5\u4ed6\u4eec\u9009\u62e9\u66f4\u590d\u6742\u7684\u65b9\u5f0f: \u4f7f\u7528\u6cdb\u578b\u6765\u7b80\u5316</p> <pre><code>open class BaseResult&lt;T&gt; {\n var code: Int = 0\n var msg: String = \"\"\n var data: T? = null\n}\n\nclass Result(var name: String) : BaseResult&lt;Result&gt;()\n</code></pre> <p>\u7528\u52a0\u6cd5\u89e3\u51b3\u95ee\u9898\u7684\u4eba\uff0c\u603b\u6709\u4eba\u613f\u610f\u7528\u4e58\u6cd5\u7ed9\u4f60\u7b54\u6848</p>"},{"location":"converter.html","title":"\u8f6c\u6362\u5668","text":"<p>Net\u652f\u6301\u8bf7\u6c42\u8fd4\u56de\u7684\u6570\u636e\u7c7b\u578b\u53d6\u51b3\u4e8e\u4f60\u7684\u8f6c\u6362\u5668\u5b9e\u73b0</p>"},{"location":"converter.html#getapipathawait","title":"Get&lt;\u4efb\u4f55\u5bf9\u8c61&gt;(Api.PATH).await()","text":"<p>\u9ed8\u8ba4\u8f6c\u6362\u5668\u652f\u6301\u8fd4\u56de\u4ee5\u4e0b\u6570\u636e\u7c7b\u578b</p> \u51fd\u6570 \u63cf\u8ff0 String \u5b57\u7b26\u4e32 ByteArray \u5b57\u8282\u6570\u7ec4 ByteString \u66f4\u591a\u529f\u80fd\u7684\u5b57\u7b26\u4e32\u5bf9\u8c61 File \u6587\u4ef6\u5bf9\u8c61, \u8fd9\u79cd\u60c5\u51b5\u5176\u5b9e\u5e94\u5f53\u79f0\u4e3a\u4e0b\u8f7d\u6587\u4ef6 Response \u6240\u6709\u54cd\u5e94\u4fe1\u606f(\u54cd\u5e94\u4f53/\u54cd\u5e94\u5934/\u8bf7\u6c42\u4fe1\u606f\u7b49) <p>\u4f7f\u7528\u793a\u4f8b</p> <pre><code>scopeNetLife {\n Get&lt;Response&gt;(Api.PATH).await().headers(\"\u54cd\u5e94\u5934\u540d\u79f0\") // \u8fd4\u56de\u54cd\u5e94\u5934\n}\n</code></pre> \u8f6c\u6362\u5668\u5b9e\u73b0\u975e\u5e38\u7b80\u5355 NetConverter.kt<pre><code>interface NetConverter {\n\n @Throws(Throwable::class)\n fun &lt;R&gt; onConvert(succeed: Type, response: Response): R?\n\n companion object DEFAULT : NetConverter {\n /**\n * \u8fd4\u56de\u7ed3\u679c\u5e94\u5f53\u7b49\u4e8e\u6cdb\u578b\u5bf9\u8c61, \u53ef\u7a7a\n * @param succeed \u8bf7\u6c42\u8981\u6c42\u8fd4\u56de\u7684\u6cdb\u578b\u7c7b\u578b\n * @param response \u8bf7\u6c42\u54cd\u5e94\u5bf9\u8c61\n */\n override fun &lt;R&gt; onConvert(succeed: Type, response: Response): R? {\n return when {\n succeed === String::class.java &amp;&amp; response.isSuccessful -&gt; response.body?.string() as R\n succeed === ByteString::class.java &amp;&amp; response.isSuccessful -&gt; response.body?.byteString() as R\n succeed is GenericArrayType &amp;&amp; succeed.genericComponentType === Byte::class.java &amp;&amp; response.isSuccessful -&gt; response.body?.bytes() as R\n succeed === File::class.java &amp;&amp; response.isSuccessful -&gt; response.file() as R\n succeed === Response::class.java -&gt; response as R\n else -&gt; throw ConvertException(response, \"An exception occurred while converting the NetConverter.DEFAULT\")\n }\n }\n }\n}\n</code></pre> <p>\u5047\u8bbe\u4e0d\u652f\u6301\u4f60\u9700\u8981\u7684\u6570\u636e\u7c7b\u578b, \u4f8b\u5982JSON/ProtoBuf/Bitmap\u7b49\u8bf7\u81ea\u5b9a\u4e49\u8f6c\u6362\u5668</p>"},{"location":"cookie.html","title":"Cookie","text":"<p>\u53ef\u4ee5\u5b9e\u73b0OkHttp\u7684<code>CookieJar</code>, \u4e14\u63d0\u4f9b\u6301\u4e45\u5316\u7684PersistentCookieJar</p> <pre><code>NetConfig.initialize(Api.HOST, this) {\n // \u6dfb\u52a0\u6301\u4e45\u5316Cookie\n cookieJar(PersistentCookieJar(this@App))\n}\n</code></pre> <p>\u53ef\u4ee5\u624b\u52a8\u589e\u5220Cookie</p> PersistentCookieJar \u63cf\u8ff0 addAll \u6dfb\u52a0Cookie getAll \u83b7\u53d6\u67d0\u4e2a\u57df\u540d\u7684\u6240\u6709Cookie remove \u5220\u9664\u67d0\u4e2a\u57df\u540d\u4e0b\u6240\u6709\u6216\u8005\u6307\u5b9a\u540d\u79f0\u7684Cookie clear \u5220\u9664\u5ba2\u6237\u7aef\u5168\u90e8Cookie <p>\u53ef\u901a\u8fc7\u5ba2\u6237\u7aef\u83b7\u53d6\u5230\u5df2\u914d\u7f6ecookieJar <pre><code>(NetConfig.okHttpClient.cookieJar as? PersistentCookieJar)?.clear()\n</code></pre></p> <p>\u9694\u7eddCookies\u5171\u4eab</p> <p>\u4e3a<code>PersistentCookieJar</code>\u6307\u5b9a\u4e0d\u540c<code>dbName</code>\u963b\u6b62\u4e0d\u540c\u7684\u5ba2\u6237\u7aef\u5171\u4eabCookies</p>"},{"location":"coroutine-request.html","title":"\u534f\u7a0b\u8bf7\u6c42","text":"<p>Net\u7684\u534f\u7a0b\u4f5c\u7528\u57df\u4f1a\u81ea\u52a8\u5904\u7406\u534f\u7a0b\u751f\u547d\u5468\u671f</p> <p>\u5728\u4e0a\u7ae0\u8282\u5df2\u7ecf\u4ecb\u7ecd\u5982\u4f55\u53d1\u8d77\u5e76\u53d1\u7f51\u7edc\u8bf7\u6c42, \u8fd9\u91cc\u6f14\u793a\u540c\u65f6(\u5e76\u53d1)\u8bf7\u6c42<code>\u4e00\u4e07\u6b21</code>, \u7136\u540e\u53d6\u6d88\u5168\u90e8</p> <pre><code>val job = scopeNetLife {\n repeat(10000) {\n // \u8fd9\u91cc\u5c06\u8fd4\u56de\u7684\u6570\u636e\u663e\u793a\u5728TextView\u4e0a\n launch {\n tv.text = Get&lt;String&gt;(Api.PATH).await()\n }\n }\n}\n</code></pre> <p>\u7b49\u5f85\u4e94\u79d2\u540e\u53d6\u6d88\u8bf7\u6c42 <pre><code>thread {\n Thread.sleep(5000) // \u7b49\u5f85\u4e94\u79d2\n job.cancel()\n}\n</code></pre></p> <p></p> <p>Net\u4e3b\u8981\u4f7f\u7528\u534f\u7a0b\u8bf7\u6c42, \u4f46\u4e5f\u652f\u6301\u5176\u4ed6\u65b9\u5f0f\u53d1\u8d77\u8bf7\u6c42</p> <ul> <li>\u540c\u6b65\u8bf7\u6c42</li> <li>\u56de\u8c03\u8bf7\u6c42</li> <li>\u534f\u7a0b\u8bf7\u6c42</li> </ul>"},{"location":"debounce.html","title":"\u641c\u7d22\u8282\u6d41","text":"<p>\u8282\u6d41</p> <p>\u5728\u4e00\u5b9a\u65f6\u95f4\u95f4\u9694\u5185\uff0c\u53ea\u6267\u884c\u6700\u540e\u4e00\u6b21\u8bf7\u6c42, \u5ffd\u7565\u5176\u4ed6\u591a\u4f59\u7684\u8bf7\u6c42</p> <p>\u641c\u7d22\u8f93\u5165\u6846\u4e00\u822c\u90fd\u662f\u8f93\u5165\u5b8c\u5173\u952e\u8bcd\u540e\u81ea\u52a8\u5f00\u59cb\u641c\u7d22</p> <p>\u8fd9\u4e2a\u8fc7\u7a0b\u6d89\u53ca\u5230</p> <ol> <li>\u6bcf\u6b21\u53d8\u5316\u90fd\u641c\u7d22\u4f1a\u5bfc\u81f4\u670d\u52a1\u5668\u538b\u529b, \u5e94\u5728\u505c\u6b62\u8f93\u5165\u6ee1\u8db3\u4e00\u5b9a\u65f6\u95f4\u540e\u81ea\u52a8\u641c\u7d22</li> <li>\u5f53\u4ea7\u751f\u65b0\u7684\u641c\u7d22\u8bf7\u6c42\u540e\u5e94\u53d6\u6d88\u65e7\u8bf7\u6c42, \u4ee5\u9632\u6b62\u65e7\u6570\u636e\u8986\u76d6\u65b0\u6570\u636e</li> <li>\u5f53\u8f93\u5165\u5185\u5bb9\u6ca1\u6709\u53d8\u5316(\u4f8b\u590d\u5236\u7c98\u8d34\u91cd\u590d\u5185\u5bb9\u5230\u641c\u7d22\u6846)\u4e0d\u4f1a\u53d1\u8d77\u641c\u7d22\u8bf7\u6c42</li> </ol> <p></p> <p></p> <p></p> <pre><code>var scope: CoroutineScope? = null\n\n// distinctUntilChanged \u8868\u793a\u8fc7\u6ee4\u6389\u91cd\u590d\u7ed3\u679c\nbinding.etInput.debounce().distinctUntilChanged().launchIn(this) {\n scope?.cancel() // \u53d1\u8d77\u65b0\u7684\u8bf7\u6c42\u524d\u53d6\u6d88\u65e7\u7684\u8bf7\u6c42, \u907f\u514d\u65e7\u6570\u636e\u8986\u76d6\u65b0\u6570\u636e\n scope = scopeNetLife { // \u4fdd\u5b58\u65e7\u7684\u8bf7\u6c42\u5230\u4e00\u4e2a\u53d8\u91cf\u4e2d\n tv.text = \"\u8bf7\u6c42\u4e2d\"\n tv.text = Get&lt;String&gt;(Api.TIME).await()\n }\n}\n</code></pre> <p>\u6307\u5b9a\u53c2\u6570\u8bbe\u7f6e\u8282\u6d41\u9600\u8d85\u65f6\u65f6\u95f4 <pre><code>fun EditText.debounce(timeoutMillis: Long = 800)\n</code></pre> 1. \u793a\u4f8b-\u81ea\u52a8\u641c\u7d22\u5206\u9875\u5217\u8868</p>"},{"location":"download-file.html","title":"\u4e0b\u8f7d\u6587\u4ef6","text":"<p>\u6cdb\u578b\u6539\u4e3a<code>File</code>\u5373\u53ef</p> <pre><code>scopeNetLife {\n val file = Get&lt;File&gt;(Api.DOWNLOAD).await()\n}\n</code></pre>"},{"location":"download-file.html#_1","title":"\u4e0b\u8f7d\u9009\u9879","text":"<p>\u4e30\u5bcc\u7684\u4e0b\u8f7d\u5b9a\u5236\u65b9\u6848, \u5e76\u4e14\u5728\u4e0d\u65ad\u66f4\u65b0</p> <pre><code>scopeNetLife {\n val file =\n Get&lt;File&gt;(\"https://github.com/liangjingkanji/Net/releases/latest/download/net-sample.apk\") {\n setDownloadFileName(\"net.apk\")\n setDownloadDir(requireContext().filesDir)\n setDownloadMd5Verify()\n }.await()\n}\n</code></pre> \u914d\u7f6e\u9009\u9879 \u63cf\u8ff0 addDownloadListener \u4e0b\u8f7d\u8fdb\u5ea6\u76d1\u542c\u5668 setDownloadFileName \u4e0b\u8f7d\u6587\u4ef6\u540d setDownloadDir \u4e0b\u8f7d\u76ee\u5f55 setDownloadMd5Verify \u4e0b\u8f7d\u6587\u4ef6MD5\u6821\u9a8c setDownloadFileNameConflict \u4e0b\u8f7d\u6587\u4ef6\u540c\u540d\u51b2\u7a81\u89e3\u51b3 setDownloadFileNameDecode \u6587\u4ef6\u540dUrl\u89e3\u7801\u4e2d\u6587 setDownloadTempFile \u4e34\u65f6\u6587\u4ef6\u540d"},{"location":"download-file.html#_2","title":"\u91cd\u590d\u4e0b\u8f7d","text":"<p>\u9632\u6b62\u91cd\u590d\u4e0b\u8f7d\u6709\u4ee5\u4e0b\u65b9\u5f0f</p> \u51fd\u6570 \u63cf\u8ff0 \u6587\u4ef6\u5224\u65ad \u5224\u65ad\u672c\u5730\u662f\u5426\u5b58\u5728\u540c\u540d\u6587\u4ef6 \u7f13\u5b58\u6a21\u5f0f \u5f00\u542f\u7f13\u5b58, \u5360\u7528\u8bbe\u5907\u4e24\u4efd\u7a7a\u95f4(\u7f13\u5b58/\u4e0b\u8f7d\u6210\u529f\u6587\u4ef6\u90fd\u5360\u7a7a\u95f4) MD5\u6821\u9a8c \u670d\u52a1\u5668\u8fd4\u56de<code>Content-MD5</code>, \u5ba2\u6237\u7aef\u5f00\u542f<code>setDownloadMd5Verify</code>"},{"location":"error-global.html","title":"\u5168\u5c40\u6355\u83b7","text":"<p>\u53ef\u5b9e\u73b0<code>NetErrorHandler</code>\u63a5\u53e3\u6765\u76d1\u542c\u5168\u5c40\u9519\u8bef\u5904\u7406</p> \u521b\u5efa\u914d\u7f6e <pre><code>class NetworkingErrorHandler : NetErrorHandler {\n override fun onError(e: Throwable) {\n // .... \u5176\u4ed6\u9519\u8bef\n if (e is ResponseException &amp;&amp; e.tag == 401) { // \u5224\u65ad\u5f02\u5e38\u4e3atoken\u5931\u6548\n // \u6253\u5f00\u767b\u5f55\u754c\u9762\u6216\u8005\u5f39\u767b\u5f55\u5931\u6548\u5bf9\u8bdd\u6846\n }\n }\n}\n</code></pre> <pre><code>NetConfig.initialize(Api.HOST, this) {\n setErrorHandler(NetworkingErrorHandler))\n}\n</code></pre> NetErrorHandler \u4f7f\u7528\u573a\u666f \u89e6\u53d1\u4f4d\u7f6e <code>onError</code> \u5410\u53f8\u9519\u8bef\u4fe1\u606f <code>scopeNetLife/scopeDialog</code> <code>onStateError</code> \u8981\u6c42\u9519\u8bef\u663e\u793a\u5728\u7f3a\u7701\u9875 <code>PageRefreshLayout.scope/StateLayout.scope</code> <p>\u4ee5\u4e0b\u60c5\u51b5\u5168\u5c40\u9519\u8bef\u5904\u7406\u65e0\u6548</p> <ol> <li>\u5f02\u6b65\u4efb\u52a1\u4f5c\u7528\u57df(<code>scope/scopeLife</code>)\u53d1\u751f\u7684\u9519\u8bef</li> <li>\u4f7f\u7528\u5355\u4f8b\u9519\u8bef\u5904\u7406\u5904\u7406\u7684\u9519\u8bef</li> </ol>"},{"location":"error-single.html","title":"\u5355\u4f8b\u6355\u83b7","text":"<p>\u6355\u83b7\u5f53\u524d\u8bf7\u6c42/\u4f5c\u7528\u57df\u9519\u8bef, \u5c06\u4e0d\u4f1a\u518d\u88ab\u5168\u5c40\u9519\u8bef\u5904\u7406</p>"},{"location":"error-single.html#_1","title":"\u6355\u83b7\u8bf7\u6c42","text":"<p>\u4e00\u4e2a\u8bf7\u6c42\u53d1\u751f\u9519\u8bef\u4f1a\u53d6\u6d88\u5f53\u524d\u4f5c\u7528\u57df\u5185\u6240\u6709\u8bf7\u6c42, \u4f46\u5355\u72ec\u6355\u83b7\u540e\u4e0d\u4f1a\u518d\u5f71\u54cd\u5176\u4ed6\u8bf7\u6c42</p> <p>\u4f8b\u5982 <pre><code>scopeNetLife {\n Get&lt;String&gt;(\"path\").await() // \u5931\u8d25\n Get&lt;String&gt;(\"path2\").await() // \u4e0a\u9762\u5931\u8d25, \u6b64\u5904\u4e5f\u4e0d\u4f1a\u6267\u884c\n}\n</code></pre></p> <p>\u6355\u83b7\u7b2c\u4e00\u4e2a\u534f\u7a0b\u907f\u514d\u7ec8\u6b62\u540e\u7eed\u6267\u884c <pre><code>scopeNetLife {\n try {\n Get&lt;String&gt;(\"path\").await() // \u5931\u8d25\n } catch(e:Exception) {\n }\n Get&lt;String&gt;(\"path2\").await() // \u4e0a\u9762\u5931\u8d25, \u6b64\u5904\u7ee7\u7eed\u6267\u884c\n}\n</code></pre> \u5f53\u7136\u5982\u679c\u521b\u5efa\u4e0d\u540c\u7684\u4f5c\u7528\u57df\u5206\u522b\u8bf7\u6c42\u90a3\u662f\u4e92\u4e0d\u5f71\u54cd\u7684 <pre><code>scopeNetLife {\n Get&lt;String&gt;(\"path\").await() // \u5931\u8d25\n}\nscopeNetLife {\n Get&lt;String&gt;(\"path2\").await() // \u4e0a\u9762\u5931\u8d25, \u6b64\u5904\u5b8c\u5168\u4e0d\u53d7\u5f71\u54cd\n}\n</code></pre></p> <p></p>"},{"location":"error-single.html#_2","title":"\u6355\u83b7\u4f5c\u7528\u57df","text":"<pre><code>scope {\n val data = Get&lt;String&gt;(\"http://www.error.com/\").await()\n}.catch {\n // \u534f\u7a0b\u5185\u53d1\u751f\u9519\u8bef\u56de\u8c03, it\u4e3a\u5f02\u5e38\u5bf9\u8c61\n}.finally {\n // \u534f\u7a0b\u6267\u884c\u5b8c\u6bd5\u56de\u8c03(\u4e0d\u8bba\u6210\u8d25), it\u4e3a\u5f02\u5e38\u5bf9\u8c61\n}\n</code></pre> \u51fd\u6570 \u533a\u522b catch \u53d1\u751f\u9519\u8bef\u540e\u56de\u8c03, \u53d6\u6d88\u4e0d\u56de\u8c03 \u4e0d\u4f1a\u518d\u6267\u884c\u5168\u5c40\u9519\u8bef\u5904\u7406, \u53ef\u4f7f\u7528<code>handleError</code>\u518d\u6b21\u4f20\u9012\u7ed9\u5168\u5c40 finally \u6267\u884c\u5b8c\u6bd5\u56de\u8c03(\u4e0d\u8bba\u6210\u8d25), \u53d6\u6d88\u4f5c\u7528\u57df\u65f6<code>it</code>\u4e3a<code>CancellationException</code> \u6267\u884c\u5168\u5c40\u9519\u8bef\u5904\u7406"},{"location":"error-throws.html","title":"\u81ea\u5b9a\u4e49\u5f02\u5e38\u629b\u51fa","text":"<p>\u4ee5\u4e0b\u4e3aNet\u5185\u90e8\u629b\u51fa\u7684\u5f02\u5e38\u5bf9\u8c61</p> \u5f02\u5e38 \u63cf\u8ff0 NetException \u672a\u77e5\u7684\u7f51\u7edc\u5f02\u5e38, \u4e00\u822c\u60c5\u51b5\u5e94\u5f53\u7ee7\u627f\u4ed6\u6765\u521b\u5efa\u81ea\u5b9a\u4e49\u7684\u7f51\u7edc\u5f02\u5e38 HttpFailureException Http\u8bf7\u6c42\u9519\u8bef, Http\u8bf7\u6c42\u5931\u8d25(onFailure) HttpResponseException Http\u8bf7\u6c42\u6210\u529f\u540e\u53d1\u751f\u7684\u9519\u8bef, Http\u8bf7\u6c42\u6210\u529f\u4f46\u53d1\u751f\u5f02\u5e38(onResponse) URLParseException \u5730\u5740\u9519\u8bef NetUnknownHostException \u57df\u540d\u9519\u8bef NetSocketTimeoutException \u8fde\u63a5\u8d85\u65f6 NetConnectException \u8fde\u63a5\u7f51\u7edc\u5931\u8d25, \u8bbe\u5907\u672a\u5f00\u542f\u7f51\u7edc NetworkingException \u5f53\u524d\u7f51\u7edc\u4e0d\u53ef\u7528, <code>Net\u5e76\u672a\u5b9e\u73b0</code> DownloadFileException \u4e0b\u8f7d\u6587\u4ef6\u5f02\u5e38 ConvertException \u89e3\u6790\u9519\u8bef, <code>NetConvert</code>\u4e2d\u53d1\u751f\u7684\u672a\u6355\u83b7\u5f02\u5e38\u90fd\u7b97\u89e3\u6790\u9519\u8bef RequestParamsException \u8bf7\u6c42\u53c2\u6570\u9519\u8bef <code>400 - 499</code> \u8303\u56f4\u5185\u9519\u8bef\u7801 ServerResponseException \u670d\u52a1\u5668\u9519\u8bef <code>500 - 599</code> \u8303\u56f4\u5185\u9519\u8bef\u7801 ResponseException \u9519\u8bef\u7801\u5f02\u5e38, \u4e00\u822c\u5e94\u7528\u4e8e\u540e\u7aef\u8fd4\u56de\u7684\u9519\u8bef\u7801\u548c\u5176\u5b9a\u4e49\u7684\u6210\u529f\u7801\u4e0d\u5339\u914d NullPointerException \u7a7a\u6307\u9488, \u4e00\u822c\u662f\u5728\u4f5c\u7528\u57df\u5185\u64cd\u4f5c\u4e00\u4e2a\u7a7a\u7684\u5bf9\u8c61 <p>NetworkingException</p> <p>\u7531\u4e8e\u8c37\u6b4c\u9650\u5236Net\u65e0\u6cd5\u5224\u65ad\u7f51\u7edc\u662f\u5426\u53ef\u7528, \u8bf7\u5f00\u53d1\u8005\u81ea\u5df1\u629b\u51fa</p>"},{"location":"error-throws.html#_1","title":"\u81ea\u5b9a\u4e49\u5f02\u5e38","text":"<p>\u5728\u8f6c\u6362\u5668(NetConverter)\u6216\u62e6\u622a\u5668(Interceptor)\u4e2d\u629b\u51fa\u4efb\u4f55\u5f02\u5e38 \u8be5\u5f02\u5e38\u5bf9\u8c61\u90fd\u4f1a\u88ab\u5355\u4f8b\u6216\u5168\u5c40\u9519\u8bef\u5904\u7406\u63a5\u6536, \u53ef\u7528\u4e8e\u5224\u65ad\u5f02\u5e38\u4fe1\u606f\u505a\u7279\u6b8a\u5904\u7406 (\u4f8b\u5982Token\u5931\u6548\u5219\u8df3\u8f6c\u5230\u767b\u5f55\u9875\u9762)</p> <p>\u8f6c\u6362\u53d1\u751f\u5f02\u5e38</p> <p>NetConverter\u4e2d\u7684\u6240\u6709\u5f02\u5e38\u9664\u975e\u662f<code>NetException\u5b50\u7c7b</code>\u5426\u5219\u90fd\u5c06\u88ab<code>ConvertException</code>\u5305\u88f9 \u5373\u6355\u83b7\u7684\u662f<code>ConvertException</code>, cause\u624d\u4e3a\u5b9e\u9645\u629b\u51fa\u5f02\u5e38</p>"},{"location":"error-throws.html#_2","title":"\u5f02\u5e38\u4f20\u9012\u5b57\u6bb5","text":"<p>Net\u81ea\u5e26\u5f02\u5e38\u4f1a\u6709\u7c7b\u578b\u4e3aAny\u7684\u5b57\u6bb5<code>tag</code>, \u53ef\u7528\u4f20\u9012\u5bf9\u8c61\u7528\u4e8e\u5224\u65ad\u9519\u8bef\u5904\u7406</p> <p>\u4f8b\u5982<code>ResponseException</code>\u5e38\u7528\u4e8e\u4f5c\u4e3a\u8bf7\u6c42\u670d\u52a1\u5668\u6210\u529f\u4f46\u540e\u7aef\u4e1a\u52a1\u9519\u8bef, \u7136\u540etag\u4e3a\u4f20\u9012\u7684\u9519\u8bef\u7801</p> <p>\u793a\u4f8b\u4ee3\u7801</p> \u8f6c\u6362\u5668\u629b\u51fa\u5f02\u5e38\u5168\u5c40\u9519\u8bef\u5904\u7406\u5f02\u5e38 <pre><code>class SerializationConverter(\n val success: String = \"0\",\n val code: String = \"code\",\n val message: String = \"msg\"\n) : NetConverter {\n\n override fun &lt;R&gt; onConvert(succeed: Type, response: Response): R? {\n try {\n return NetConverter.onConvert&lt;R&gt;(succeed, response)\n } catch (e: ConvertException) {\n val code = response.code\n when {\n code in 200..299 -&gt; { // \u8bf7\u6c42\u6210\u529f\n // ... \u5047\u8bbeToken\u5931\u6548. \u540e\u7aef\u8fd4\u56de\u4e1a\u52a1\u9519\u8bef\u7801 srvCode = 401\n throw ResponseException(response, errorMessage, tag = srvCode) // \u5c06\u4e1a\u52a1\u9519\u8bef\u7801\u4f5c\u4e3atag\u4f20\u9012\n }\n code in 400..499 -&gt; throw RequestParamsException(response, code.toString()) // \u8bf7\u6c42\u53c2\u6570\u9519\u8bef\n code &gt;= 500 -&gt; throw ServerResponseException(response, code.toString()) // \u670d\u52a1\u5668\u5f02\u5e38\u9519\u8bef\n else -&gt; throw ConvertException(response)\n }\n }\n }\n}\n</code></pre> <pre><code>class NetworkingErrorHandler : NetErrorHandler {\n override fun onError(e: Throwable) {\n // .... \u5176\u4ed6\u9519\u8bef\n if (e is ResponseException &amp;&amp; e.tag == 401) { // \u5224\u65ad\u5f02\u5e38\u4e3atoken\u5931\u6548\n // \u6253\u5f00\u767b\u5f55\u754c\u9762\u6216\u8005\u5f39\u767b\u5f55\u5931\u6548\u5bf9\u8bdd\u6846\n }\n }\n}\n</code></pre>"},{"location":"error-tip.html","title":"\u81ea\u5b9a\u4e49\u9519\u8bef\u63d0\u793a","text":"<p>\u7f51\u7edc\u9519\u8bef\u63d0\u793a</p> <p>\u7f51\u7edc\u8bf7\u6c42\u53d1\u751f\u9519\u8bef\u4e00\u5b9a\u8981\u63d0\u793a\u7ed9\u7528\u6237, \u5e76\u4e14\u662f\u53ef\u8bfb\u8bed\u4e49\u53e5</p> <p>\u4fee\u6539\u9ed8\u8ba4\u5410\u53f8\u9519\u8bef\u6587\u672c\u6216\u56fd\u9645\u5316\u53c2\u8003\u4ee5\u4e0b\u65b9\u5f0f</p>"},{"location":"error-tip.html#_1","title":"\u521b\u5efa\u591a\u8bed\u8a00","text":"<p>\u9519\u8bef\u63d0\u793a\u6587\u672c\u88ab\u5b9a\u4e49\u5728<code>strings.xml</code>, \u5728\u9879\u76ee\u4e2d\u521b\u5efa\u540c\u540d<code>name</code>\u53ef\u590d\u5199Net\u5b9a\u4e49\u7684\u6587\u672c</p> <p>\u56fd\u9645\u5316\u8bed\u8a00\u5219\u9700\u521b\u5efa\u591a\u8bed\u8a00<code>values</code>, \u4f8b\u5982\u82f1\u8bed\u662f<code>values-en</code>\u4e0b\u521b\u5efa<code>strings.xml</code></p> \u9519\u8bef\u6587\u672c <pre><code> &lt;!--\u7f51\u7edc\u8bf7\u6c42\u5f02\u5e38--&gt;\n &lt;string name=\"net_connect_error\"&gt;\u8fde\u63a5\u7f51\u7edc\u5931\u8d25&lt;/string&gt;\n &lt;string name=\"net_url_error\"&gt;\u8bf7\u6c42\u8d44\u6e90\u5730\u5740\u9519\u8bef&lt;/string&gt;\n &lt;string name=\"net_host_error\"&gt;\u65e0\u6cd5\u627e\u5230\u6307\u5b9a\u670d\u52a1\u5668\u4e3b\u673a&lt;/string&gt;\n &lt;string name=\"net_connect_timeout_error\"&gt;\u8fde\u63a5\u670d\u52a1\u5668\u8d85\u65f6\uff0c%s&lt;/string&gt;\n &lt;string name=\"net_download_error\"&gt;\u4e0b\u8f7d\u8fc7\u7a0b\u53d1\u751f\u9519\u8bef&lt;/string&gt;\n &lt;string name=\"net_no_cache_error\"&gt;\u8bfb\u53d6\u7f13\u5b58\u5931\u8d25&lt;/string&gt;\n &lt;string name=\"net_parse_error\"&gt;\u89e3\u6790\u6570\u636e\u65f6\u53d1\u751f\u5f02\u5e38&lt;/string&gt;\n &lt;string name=\"request_failure\"&gt;\u8bf7\u6c42\u5931\u8d25&lt;/string&gt;\n &lt;string name=\"net_request_error\"&gt;\u8bf7\u6c42\u53c2\u6570\u9519\u8bef&lt;/string&gt;\n &lt;string name=\"net_server_error\"&gt;\u670d\u52a1\u54cd\u5e94\u9519\u8bef&lt;/string&gt;\n &lt;string name=\"net_null_error\"&gt;\u53d1\u751f\u7a7a\u5f02\u5e38&lt;/string&gt;\n &lt;string name=\"net_error\"&gt;\u672a\u77e5\u7f51\u7edc\u9519\u8bef&lt;/string&gt;\n &lt;string name=\"net_other_error\"&gt;\u672a\u77e5\u9519\u8bef&lt;/string&gt;\n &lt;string name=\"no_error_message\"&gt;\u65e0\u9519\u8bef\u4fe1\u606f&lt;/string&gt;\n\n &lt;!--\u5bf9\u8bdd\u6846--&gt;\n &lt;string name=\"net_dialog_msg\"&gt;\u52a0\u8f7d\u4e2d&lt;/string&gt;\n</code></pre>"},{"location":"error-tip.html#neterrorhandler","title":"\u521b\u5efaNetErrorHandler","text":"<p>\u4f7f\u7528\u81ea\u5b9a\u4e49\u5168\u5c40\u9519\u8bef\u5904\u7406\u53ef\u5b8c\u5168\u4fee\u6539, \u53ef\u4e0d\u63d0\u793a\u9519\u8bef\u6216\u9644\u4e0a\u9519\u8bef\u4fe1\u606f</p> \u5168\u5c40\u9519\u8bef\u5904\u7406 <pre><code>fun onError(e: Throwable) {\n val message = when (e) {\n is UnknownHostException -&gt; NetConfig.app.getString(R.string.net_host_error)\n is URLParseException -&gt; NetConfig.app.getString(R.string.net_url_error)\n is NetConnectException -&gt; NetConfig.app.getString(R.string.net_connect_error)\n is NetSocketTimeoutException -&gt; NetConfig.app.getString(\n R.string.net_connect_timeout_error,\n e.message\n )\n is DownloadFileException -&gt; NetConfig.app.getString(R.string.net_download_error)\n is ConvertException -&gt; NetConfig.app.getString(R.string.net_parse_error)\n is RequestParamsException -&gt; NetConfig.app.getString(R.string.net_request_error)\n is ServerResponseException -&gt; NetConfig.app.getString(R.string.net_server_error)\n is NullPointerException -&gt; NetConfig.app.getString(R.string.net_null_error)\n is NoCacheException -&gt; NetConfig.app.getString(R.string.net_no_cache_error)\n is ResponseException -&gt; e.message\n is HttpFailureException -&gt; NetConfig.app.getString(R.string.request_failure)\n is NetException -&gt; NetConfig.app.getString(R.string.net_error)\n else -&gt; NetConfig.app.getString(R.string.net_other_error)\n }\n\n Net.debug(e)\n TipUtils.toast(message)\n}\n</code></pre>"},{"location":"error.html","title":"\u9519\u8bef\u5904\u7406","text":"<p>Net\u6709\u5b8c\u5584\u7684\u9519\u8bef\u5904\u7406\u673a\u5236, \u5177\u5907\u6355\u83b7\u5f02\u5e38/\u53d6\u6d88\u8bf7\u6c42/\u9519\u8bef\u63d0\u793a/\u8ffd\u8e2a\u94fe\u8def</p> <p>\u6536\u96c6\u7f51\u7edc\u65e5\u5fd7</p> <p>\u5728Net\u4f5c\u7528\u57df\u5185\u53d1\u751f\u7684\u5f02\u5e38\u90fd\u4f1a\u88ab\u5168\u5c40\u9519\u8bef\u5904\u7406\u6355\u83b7, \u53ef\u4ee5\u5c06\u5176\u7b5b\u9009\u4e0a\u4f20\u65e5\u5fd7</p> <p> \u4ee5\u4e0b\u4f4d\u7f6e\u629b\u51fa\u5f02\u5e38\u4f1a\u88ab\u6355\u83b7</p> \u51fd\u6570 \u63cf\u8ff0 \u4f5c\u7528\u57df <code>scopeXX</code>\u4ee3\u7801\u5757\u4e2d \u62e6\u622a\u5668 <code>Interceptor/RequestInterceptor</code> \u8f6c\u6362\u5668 <code>NetConverter</code> <p>\u5982\u679c\u6355\u83b7\u5230\u9519\u8bef\u9ed8\u8ba4\u4f1a\u6267\u884c\u4ee5\u4e0b\u64cd\u4f5c</p> <ol> <li><code>Logcat</code>\u8f93\u51fa\u5f02\u5e38\u5806\u6808\u4fe1\u606f, \u81ea\u5b9a\u4e49\u5f02\u5e38\u629b\u51fa</li> <li><code>Toast</code>\u663e\u793a\u9519\u8bef\u6587\u672c, \u81ea\u5b9a\u4e49\u9519\u8bef\u63d0\u793a</li> </ol> <p></p> <p>\u6355\u83b7\u4e0d\u5230\u5f02\u5e38</p> <p>\u5982\u679c\u8bf7\u6c42\u672a\u6267\u884c<code>await()</code>, \u90a3\u4e48\u5373\u4f7f\u53d1\u751f\u9519\u8bef\u4e5f\u4e0d\u4f1a\u88ab\u6355\u83b7\u5230</p> <p> \u81ea\u5b9a\u4e49\u8bf7\u9605\u8bfb\u5168\u5c40\u9519\u8bef\u5904\u7406</p>"},{"location":"fastest.html","title":"\u6700\u5feb\u8bf7\u6c42\u7ed3\u679c","text":"<p>\u591a\u4e2a\u8bf7\u6c42\u5e76\u53d1\u6267\u884c</p> <ol> <li>\u5f53\u67d0\u4e2a\u8bf7\u6c42\u6210\u529f\u65f6, \u5269\u4f59\u8bf7\u6c42\u5c06\u88ab\u81ea\u52a8\u53d6\u6d88</li> <li>\u5168\u90e8\u9519\u8bef\u65f6\u5219\u4f1a\u629b\u51fa\u6700\u540e\u4e00\u4e2a\u8bf7\u6c42\u9519\u8bef\u4f5c\u4e3a\u7ed3\u679c</li> </ol> <p>\u5f02\u5e38\u4fe1\u606f</p> <p>\u5148\u5931\u8d25\u7684\u8bf7\u6c42\u9519\u8bef\u4f1a\u88ab\u5ffd\u7565, \u4f46LogCat\u4f9d\u7136\u4f1a\u8f93\u51fa\u5f02\u5e38</p> <p>\u793a\u4f8b <pre><code>scopeNetLife {\n\n // \u540c\u65f6\u53d1\u8d77\u56db\u4e2a\u7f51\u7edc\u8bf7\u6c42\n val pathAsync = Get&lt;String&gt;(\"path\") // \u9519\u8bef\u63a5\u53e3\n val pathAsync1 = Get&lt;String&gt;(\"path1\") // \u9519\u8bef\u63a5\u53e3\n val pathAsync2 = Get&lt;String&gt;(\"path2\")\n val pathAsync3 = Post&lt;String&gt;(\"path3\")\n\n // \u53ea\u8fd4\u56de\u6700\u5feb\u7684\u8bf7\u6c42\u7ed3\u679c\n tv.text = fastest(pathAsync, pathAsync1, pathAsync2, pathAsync3)\n}\n</code></pre></p>"},{"location":"fastest.html#_1","title":"\u53d6\u6d88\u5269\u4f59","text":"<p>\u4e0a\u9762\u7684\u793a\u4f8b\u4e0d\u4f1a\u5728\u83b7\u53d6\u5230\u7ed3\u679c\u540e\u53d6\u6d88\u5269\u4f59\u8bf7\u6c42, \u9700\u8bbe\u7f6e\u540c\u4e00\u8bf7\u6c42\u5206\u7ec4\u624d\u53ef\u4ee5</p> <pre><code>scopeNetLife {\n // \u540c\u65f6\u53d1\u8d77\u56db\u4e2a\u7f51\u7edc\u8bf7\u6c42\n val pathAsync = Get&lt;String&gt;(\"path\") { setGroup(\"\u521d\u59cb\u5316\") }\n val pathAsync1 = Post&lt;String&gt;(\"path1\") { setGroup(\"\u521d\u59cb\u5316\") }\n val pathAsync2 = Get&lt;String&gt;(\"path2\") { setGroup(\"\u521d\u59cb\u5316\") } // \u9519\u8bef\u63a5\u53e3\n val pathAsync3 = Get&lt;String&gt;(\"path3\") { setGroup(\"\u521d\u59cb\u5316\") } // \u9519\u8bef\u63a5\u53e3\n\n // \u53ea\u8fd4\u56de\u6700\u5feb\u7684\u8bf7\u6c42\u7ed3\u679c\n tv.text = fastest(listOf(pathAsync, pathAsync1, pathAsync2, pathAsync3), \"\u521d\u59cb\u5316\")\n}\n</code></pre>"},{"location":"fastest.html#_2","title":"\u7c7b\u578b\u4e0d\u4e00\u81f4","text":"<p>\u5f53\u9700\u8981\u8fd4\u56de\u7ed3\u679c, \u4f46\u591a\u63a5\u53e3\u8fd4\u56de\u6570\u636e\u7c7b\u578b\u4e0d\u540c, \u4f7f\u7528<code>transform</code>\u8f6c\u6362\u4e3a\u540c\u4e00\u7c7b\u578b\u7ed3\u679c</p> <pre><code>scopeNetLife {\n\n val pathAsync = Post&lt;String&gt;(\"path\").transform {\n Log.d(\"\u65e5\u5fd7\", \"Post\") // \u5982\u679c\u8be5\u63a5\u53e3\u6700\u5feb\u5219\u4f1a\u56de\u8c03\u8fd9\u91cc\n it // \u8fd9\u91cc\u53ef\u4ee5\u8fd4\u56de\u5176\u4ed6\u6570\u636e\u7ed3\u679c\n }\n\n val pathAsync1 = Get&lt;String&gt;(\"path1\").transform {\n Log.d(\"\u65e5\u5fd7\", \"Get\") // \u5982\u679c\u8be5\u63a5\u53e3\u6700\u5feb\u5219\u4f1a\u56de\u8c03\u8fd9\u91cc\n it\n }\n\n tv.text = fastest(pathAsync, pathAsync1)\n}\n</code></pre> <p>\u53ea\u6709\u6700\u5feb\u8fd4\u56de\u7ed3\u679c\u7684\u7f51\u7edc\u8bf7\u6c42(\u6216\u5f02\u6b65\u4efb\u52a1)\u7684<code>transform</code>\u56de\u8c03\u624d\u4f1a\u88ab\u6267\u884c\u5230</p>"},{"location":"fastest.html#_3","title":"\u6355\u83b7\u9519\u8bef","text":"<pre><code>scopeNetLife {\n val pathAsync = Get&lt;String&gt;(\"path\")\n val pathAsync1 = Get&lt;String&gt;(\"path1\")\n val pathAsync2 = Get&lt;String&gt;(\"path2\")\n\n val data = try {\n fastest(listOf(pathAsync, pathAsync1, pathAsync2))\n // \u5f53task/task1/task2\u5168\u90e8\u9519\u8bef\u540e\u624d\u5e76\u53d1\u6267\u884cbackupTask/backupTask1\n } catch (e: Exception) {\n val pathAsync3 = Get&lt;String&gt;(\"path3\")\n val pathAsync4 = Get&lt;String&gt;(\"path4\")\n fastest(listOf(pathAsync3, pathAsync4))\n }\n}\n</code></pre>"},{"location":"https.html","title":"Https\u8bc1\u4e66","text":"<p>Net\u53ef\u5feb\u901f\u914d\u7f6eHttps\u8bc1\u4e66, \u6216\u8005\u4f7f\u7528OkHttp\u7684\u65b9\u5f0f</p>"},{"location":"https.html#ca","title":"\u4f7f\u7528CA\u8bc1\u4e66","text":"<p>Https\u5982\u679c\u4f7f\u7528\u7684CA\u8bc1\u4e66, \u4e0d\u9700\u8981\u4efb\u4f55\u914d\u7f6e\u53ef\u4ee5\u76f4\u63a5\u8bbf\u95ee</p> <pre><code>scopeNetLife {\n tv.text = Get&lt;String&gt;(Api.PATH).await()\n}\n</code></pre>"},{"location":"https.html#_1","title":"\u4fe1\u4efb\u6240\u6709\u8bc1\u4e66","text":"<p>\u4fe1\u4efb\u6240\u6709\u8bc1\u4e66\u53ef\u4ee5\u89e3\u51b3\u65e0\u6cd5\u8bbf\u95ee\u79c1\u6709\u8bc1\u4e66\u7684Https\u5730\u5740\u95ee\u9898</p> \u5168\u5c40\u914d\u7f6e\u5355\u4f8b\u914d\u7f6e <pre><code>NetConfig.initialize(Api.HOST, this){\n trustSSLCertificate() // \u4fe1\u4efb\u6240\u6709\u8bc1\u4e66\n}\n</code></pre> <pre><code>scopeNetLife {\n Get&lt;String&gt;(Api.PATH){\n setClient {\n trustSSLCertificate()\n }\n }.await()\n}\n</code></pre>"},{"location":"https.html#_2","title":"\u5bfc\u5165\u8bc1\u4e66","text":"<p>\u79c1\u6709\u8bc1\u4e66\u53ef\u4ee5\u653e\u5230\u4efb\u4f55\u4f4d\u7f6e, \u53ea\u8981\u8bfb\u53d6\u5230<code>InputStream</code>\u6d41\u5bf9\u8c61\u5373\u53ef</p> \u5168\u5c40\u914d\u7f6e\u5355\u4f8b\u914d\u7f6e <pre><code>NetConfig.initialize(Api.HOST, this) {\n val privateCertificate = resources.assets.open(\"https.certificate\")\n setSSLCertificate(privateCertificate)\n}\n</code></pre> <pre><code>scopeNetLife {\n Get&lt;String&gt;(Api.PATH) {\n setClient {\n val privateCertificate = resources.assets.open(\"https.certificate\") // \u8fd9\u91cc\u7684\u8bc1\u4e66\u662f\u653e\u5230\u5e94\u7528\u7684\u8d44\u4ea7\u76ee\u5f55\u4e0b\n setSSLCertificate(privateCertificate)\n }\n }.await()\n}\n</code></pre>"},{"location":"interceptor.html","title":"\u62e6\u622a\u5668","text":"<p>\u6839\u636e\u4f7f\u7528\u573a\u666f\u9009\u62e9</p> <ol> <li><code>Interceptor</code>: \u652f\u6301\u4e09\u65b9OkHttp\u62e6\u622a\u5668\u7ec4\u4ef6, \u5141\u8bb8\u4fee\u6539\u8bf7\u6c42/\u54cd\u5e94\u4fe1\u606f, \u53ef\u4ee5\u8f6c\u53d1\u8bf7\u6c42</li> <li><code>RequestInterceptor</code>: Net\u72ec\u6709\u7684\u8f7b\u91cf\u7ea7\u62e6\u622a\u5668, \u5141\u8bb8\u4fee\u6539\u5168\u5c40\u8bf7\u6c42\u5934/\u8bf7\u6c42\u53c2\u6570, \u65e0\u6cd5\u8f6c\u53d1\u8bf7\u6c42 </li> </ol> <p>\u7981\u6b62\u65e0\u6548\u5c01\u88c5</p> <p>\u4e0d\u5e94\u4e3a\u5168\u5c40\u53c2\u6570/\u52a0\u5bc6\u7b49\u5c01\u88c5\u8bf7\u6c42\u65b9\u6cd5, \u5e94\u81ea\u5b9a\u4e49\u62e6\u622a\u5668/\u8f6c\u6362\u5668\u6765\u5b9e\u73b0, \u5e38\u89c1\u62e6\u622a\u5668\u793a\u4f8b</p>"},{"location":"interceptor.html#_1","title":"\u62e6\u622a\u5668","text":"<p>\u6dfb\u52a0\u62e6\u622a\u5668</p> <pre><code>NetConfig.initialize(Api.HOST, this) {\n addInterceptor(RefreshTokenInterceptor())\n}\n</code></pre> <p>\u5ba2\u6237\u7aeftoken\u81ea\u52a8\u7eed\u671f\u793a\u4f8b</p> <pre><code>class RefreshTokenInterceptor : Interceptor {\n override fun intercept(chain: Interceptor.Chain): Response {\n val request = chain.request()\n val response = chain.proceed(request)\n return synchronized(RefreshTokenInterceptor::class.java) {\n if (response.code == 401 &amp;&amp; UserConfig.isLogin &amp;&amp; !request.url.encodedPath.contains(Api.Token)) {\n val tokenInfo = Net.get(Api.Token).execute&lt;TokenModel&gt;() // \u540c\u6b65\u8bf7\u6c42token\n if (tokenInfo.isExpired) {\n // token\u8fc7\u671f\u629b\u51fa\u5f02\u5e38, \u7531\u5168\u5c40\u9519\u8bef\u5904\u7406\u5668\u5904\u7406, \u5728\u5176\u4e2d\u53ef\u4ee5\u8df3\u8f6c\u5230\u767b\u9646\u754c\u9762\u63d0\u793a\u7528\u6237\u91cd\u65b0\u767b\u9646\n throw ResponseException(response, \"\u767b\u5f55\u72b6\u6001\u5931\u6548\")\n } else {\n UserConfig.token = tokenInfo.token\n }\n chain.proceed(request)\n } else {\n response\n }\n }\n }\n}\n</code></pre>"},{"location":"interceptor.html#_2","title":"\u8bf7\u6c42\u62e6\u622a\u5668","text":"<p>\u8f7b\u91cf\u7ea7\u62e6\u622a\u5668(<code>RequestInterceptor</code>), \u5176Api\u66f4\u9002\u5408\u6dfb\u52a0\u5168\u5c40\u8bf7\u6c42\u5934/\u53c2\u6570</p> <pre><code>NetConfig.initialize(Api.HOST, this) {\n setRequestInterceptor(object : RequestInterceptor {\n override fun interceptor(request: BaseRequest) {\n request.param(\"client\", \"Net\")\n request.setHeader(\"token\", \"123456\")\n }\n })\n}\n</code></pre> <p>\u53ef\u4ee5\u770b\u51fa<code>setRequestInterceptor</code>\u4ec5\u652f\u6301\u4e00\u4e2a, <code>addInterceptor</code>\u652f\u6301\u591a\u4e2a\u62e6\u622a\u5668</p>"},{"location":"interval.html","title":"\u8f6e\u8be2\u5668/\u5012\u8ba1\u65f6","text":"<p>Net\u81ea\u5e26\u8f6e\u8be2\u5668(\u8ba1\u65f6\u5668), \u5305\u542b\u4ee5\u4e0b\u7279\u6027</p> <ul> <li>\u6b63\u8ba1\u65f6</li> <li>\u5012\u8ba1\u65f6</li> <li>\u6307\u5b9a\u6b21\u6570</li> <li>\u652f\u6301\u5f00\u59cb/\u505c\u6b62/\u6682\u505c/\u7ee7\u7eed/\u91cd\u7f6e/\u5207\u6362\u5f00\u5173</li> <li>\u4ec5\u9875\u9762\u663e\u793a\u65f6\u8ba1\u65f6</li> <li>\u9875\u9762\u9500\u6bc1\u81ea\u52a8\u53d6\u6d88</li> </ul> <p></p> \u9650\u5236\u6b21\u6570/\u95f4\u9694\u65e0\u9650\u6267\u884c\u5012\u8ba1\u65f6 <pre><code>interval = Interval(100, 1, TimeUnit.SECONDS).life(this) // \u81ea\u5b9a\u4e49\u8ba1\u6570\u5668\u4e2a\u6570\u7684\u8f6e\u8be2\u5668\n</code></pre> <pre><code> interval = Interval(1, TimeUnit.SECONDS) // \u6bcf\u79d2\u56de\u8c03\u4e00\u6b21, \u4e0d\u4f1a\u81ea\u52a8\u7ed3\u675f\n</code></pre> <pre><code>// \u5012\u8ba1\u65f6\u8f6e\u8be2\u5668, \u5f53[start]]\u6bd4[end]\u503c\u5927, \u4e14end\u4e0d\u7b49\u4e8e-1\u65f6, \u5373\u4e3a\u5012\u8ba1\u65f6\ninterval = Interval(1, 1, TimeUnit.SECONDS, 5).life(this)\n</code></pre> <p>\u76d1\u542c\u8f6e\u8be2\u5668 <pre><code>interval.subscribe {\n tv.text = it.toString()\n}.finish {\n tv.text = \"\u8ba1\u65f6\u5b8c\u6210\" // \u6700\u540e\u4e00\u4f4d\u6570\u65f6\u540c\u65f6\u56de\u8c03 subscribe/finish\n}.start()\n</code></pre></p> Interval \u63cf\u8ff0 start \u5f00\u59cb\u8f6e\u8be2\u5668 stop \u505c\u6b62 cancel \u53d6\u6d88, \u533a\u522b\u4e8estop, \u6b64\u51fd\u6570\u6267\u884c\u540e\u5e76\u4e0d\u4f1a\u56de\u8c03finish pause \u6682\u505c resume \u7ee7\u7eed reset \u91cd\u7f6e switch \u5207\u6362\u5f00\u5173 subscribe \u6bcf\u6b21\u8ba1\u65f6\u90fd\u4f1a\u6267\u884c\u8be5\u56de\u8c03 finish \u5f53\u8ba1\u65f6\u5668\u5b8c\u6210\u65f6\u6267\u884c\u8be5\u56de\u8c03, \u6267\u884cstop\u540e\u4e5f\u4f1a\u56de\u8c03 life \u6307\u5b9a\u751f\u547d\u5468\u671f\u81ea\u52a8\u53d6\u6d88\u8f6e\u8be2\u5668 onlyResumed \u5f53\u754c\u9762\u4e0d\u53ef\u89c1\u65f6\u6682\u505c, \u5f53\u754c\u9762\u53ef\u89c1\u65f6\u7ee7\u7eed <p>\u540e\u53f0\u8fd0\u884c</p> <p>\u7531\u4e8e\u7cfb\u7edf\u9650\u5236, \u672c\u5de5\u5177\u65e0\u6cd5\u4fdd\u8bc1\u4e00\u76f4\u540e\u53f0\u8fd0\u884c</p>"},{"location":"issues.html","title":"\u5e38\u89c1\u95ee\u9898","text":"<p>Net\u6700\u5927\u7684\u7279\u70b9\u5728\u4e8e\u5b8c\u7f8e\u652f\u6301OkHttp\u7684\u6240\u6709\u529f\u80fd\u7ec4\u4ef6, \u800cOkHttp\u662fAndroid\u4e3b\u6d41\u7f51\u7edc\u89e3\u51b3\u65b9\u6848</p> <p>\u6240\u4ee5\u5982\u679c\u5b58\u5728Net\u6ca1\u6709\u5b9e\u73b0\u7684\u529f\u80fd\u53ef\u4ee5\u8c37\u6b4c\u641c\u7d22<code>\"OkHttp\u5982\u4f55\u5b9e\u73b0XX\"</code>, \u7136\u540e\u53ef\u4ee5\u5f88\u5bb9\u6613\u5728Net\u4e2d\u4f7f\u7528</p>"},{"location":"issues.html#_1","title":"\u4f4e\u7248\u672c\u517c\u5bb9","text":"<p>\u5982\u679c\u5f00\u53d1\u8981\u6c42\u4f4e\u81f3 Android 4.4 (API level 19) \u8bf7\u4f7f\u7528\u517c\u5bb9\u7248\u672c: Net-okhttp3</p> <p>\u5982\u679c\u9700\u66f4\u4f4e\u7248\u672c\u652f\u6301\u8bf7\u62c9\u53d6\u4ed3\u5e93\u4fee\u6539<code>minSdkVersion</code>\u540e\u7f16\u8bd1\u6210aar\u4f7f\u7528</p>"},{"location":"issues.html#_2","title":"\u5f00\u53d1\u8005\u4ea4\u6d41","text":"<ul> <li>\u53cd\u9988\u95ee\u9898</li> <li>\u5176\u4ed6\u5f00\u53d1\u8005\u63d0\u53ca\u95ee\u9898</li> <li>\u4ea4\u6d41\u793e\u533a</li> <li></li> </ul>"},{"location":"kotlin-serialization.html","title":"Kotlin-Serialization","text":"<ol> <li>\u4eceNet3\u5f00\u59cb\u652f\u6301\u4f7f\u7528 Kotlin-Serialization (\u4ee5\u4e0b\u7b80\u79f0ks)</li> <li>\u66f4\u591a\u4e86\u89e3\u8bf7\u9605\u8bfb: Kotlin\u6700\u5f3a\u89e3\u6790\u5e93 - kotlin-serialization</li> </ol>"},{"location":"kotlin-serialization.html#_1","title":"\u7279\u70b9","text":"<ul> <li>\u5b98\u65b9\u5e93</li> <li>\u52a8\u6001\u6570\u636e\u7c7b\u578b\u89e3\u6790</li> <li>\u81ea\u5b9a\u4e49\u5e8f\u5217\u5316\u5668</li> <li>\u652f\u6301ProtoBuf/JSON\u7b49\u6570\u636e\u7ed3\u6784\u5e8f\u5217\u5316</li> <li>\u975e\u7a7a\u8986\u76d6(\u5373JSON\u5b57\u6bb5\u4e3anull\u5219\u4f7f\u7528\u53d8\u91cf\u9ed8\u8ba4\u503c)</li> <li>\u542f\u7528\u5bbd\u677e\u6a21\u5f0f, JSON\u548c\u6570\u636e\u7c7b\u7ed3\u6784\u65e0\u9700\u4e00\u81f4</li> <li>\u89e3\u6790\u4efb\u4f55\u7c7b\u578b(Map/List/Pair...)</li> </ul> <p>\u5f3a\u5236\u6ce8\u89e3</p> <p>ks\u7684\u6570\u636e\u7c7b\u90fd\u8981\u6c42\u4f7f\u7528\u6ce8\u89e3<code>@Serializable</code>(\u9664\u975e\u81ea\u5b9a\u4e49\u89e3\u6790), \u7236\u7c7b\u548c\u5b50\u7c7b\u90fd\u9700\u8981</p> <p>\u751f\u6210\u9ed8\u8ba4\u503c</p> <p>\u4f7f\u7528\u63d2\u4ef6\u751f\u6210\u6570\u636eModel, \u652f\u6301\u81ea\u52a8\u751f\u6210\u9ed8\u8ba4\u503c\u548c\u6ce8\u89e3</p> <p>\u751f\u6210\u9ed8\u8ba4\u503c\u53ef\u907f\u514d\u540e\u7aef\u8fd4\u56de\u5f02\u5e38\u6570\u636e\u5bfc\u81f4\u89e3\u6790\u5d29\u6e83, \u4ee5\u53ca\u53cd\u590d\u7f16\u5199\u5224\u7a7a\u4ee3\u7801</p>"},{"location":"kotlin-serialization.html#_2","title":"\u4f9d\u8d56","text":"<p>Project build.gradle</p> <pre><code>classpath \"org.jetbrains.kotlin:kotlin-serialization:$kotlin_version\"\n// \u548cKotlin\u63d2\u4ef6\u540c\u4e00\u4e2a\u7248\u672c\u53f7\u5373\u53ef\n</code></pre> <p>Model build.gradle</p> <pre><code>apply plugin: \"kotlin-kapt\"\napply plugin: 'kotlinx-serialization'\nimplementation \"org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.0\"\n</code></pre>"},{"location":"kotlin-serialization.html#_3","title":"\u914d\u7f6e\u8f6c\u6362\u5668","text":"<p>\u8fd9\u91cc\u4f7f\u7528\u793a\u4f8b\u4ee3\u7801\u4e2d SerializationConvert \u4f5c\u4e3a\u6f14\u793a</p> \u5168\u5c40\u914d\u7f6e\u5355\u4f8b\u914d\u7f6e <pre><code>NetConfig.initialize(Api.HOST, this) {\n setConverter(SerializationConvert())\n // ... \u5176\u4ed6\u914d\u7f6e\n}\n</code></pre> <pre><code>val userList = Get&lt;List&lt;UserModel&gt;&gt;(Api.PATH) {\n converter = SerializationConvert() // \u5355\u4f8b\u8f6c\u6362\u5668, \u6b64\u65f6\u4f1a\u5ffd\u7565\u5168\u5c40\u8f6c\u6362\u5668\n}.await()\n</code></pre>"},{"location":"kotlin-serialization.html#_4","title":"\u4f7f\u7528","text":"<pre><code>scopeNetLife {\n val userList = Get&lt;List&lt;UserModel&gt;&gt;(Api.PATH) {\n converter = SerializationConvert()\n }.await()\n\n tv.text = userList[0].name\n}\n</code></pre> <pre><code>@Serializable\ndata class UserModel(var name: String, var age: Int, var height: Int)\n</code></pre>"},{"location":"kotlin-serialization.html#_5","title":"\u5e38\u7528\u914d\u7f6e","text":"<p>\u4ee5\u4e0b\u4e3a\u53cd\u5e8f\u5217\u5316Json\u5e38\u7528\u914d\u7f6e</p> <pre><code>val jsonDecoder = Json {\n ignoreUnknownKeys = true // \u6570\u636e\u7c7b\u53ef\u4ee5\u4e0d\u7528\u58f0\u660eJson\u7684\u6240\u6709\u5b57\u6bb5\n coerceInputValues = true // \u5982\u679cJson\u5b57\u6bb5\u662fNull\u5219\u4f7f\u7528\u6570\u636e\u7c7b\u5b57\u6bb5\u9ed8\u8ba4\u503c\n}\n</code></pre> <p>\u6570\u636e\u7c7b\u4f7f\u7528\u9ed8\u8ba4\u503c <pre><code>@Serializable\ndata class Data(var name:String = \"\", var age:Int = 0)\n</code></pre></p>"},{"location":"kotlin-serialization.html#_6","title":"\u542f\u7528\u9ed8\u8ba4\u503c","text":"<p>\u5f53<code>coerceInputValues = true</code>\u65f6, json\u5b57\u6bb5\u4e3anull\u6570\u636e\u7c7b\u5b57\u6bb5\u4e3a\u975e\u7a7a\u7c7b\u578b\u60c5\u51b5\u4e0b\u91c7\u7528\u5b57\u6bb5\u9ed8\u8ba4\u503c, \u6ca1\u6709\u9ed8\u8ba4\u503c\u8bf7<code>explicitNulls = false</code>\u5219\u8d4b\u503c\u4e3anull</p> <p>\u540c\u65f6\u5f53\u51fa\u73b0\u672a\u77e5\u7684\u679a\u4e3e\u7c7b\u578b\u4e5f\u4f1a\u4f7f\u7528\u9ed8\u8ba4\u503c</p>"},{"location":"kotlin-serialization.html#_7","title":"\u5b57\u6bb5\u7f3a\u5931","text":"<p>\u901a\u8fc7<code>explicitNulls</code>\u6765\u914d\u7f6e\u5b57\u6bb5\u7f3a\u65f6\u5904\u7406\u65b9\u5f0f</p> <ul> <li>\u53cd\u5e8f\u5217\u5316\u65f6, \u5982\u679c\u6570\u636e\u7c7b\u7f3a\u5931\u5b57\u6bb5, \u4f7f\u7528<code>ignoreUnknownKeys = true</code>\u5c31\u4f1a\u81ea\u52a8\u4f7f\u7528\u9ed8\u8ba4\u503c, \u6ca1\u6709\u9ed8\u8ba4\u503c\u8bf7<code>explicitNulls = false</code>\u8d4b\u503c\u4e3anull</li> <li>\u5e8f\u5217\u5316\u65f6, \u6570\u636e\u7c7b\u5982\u679c\u5b57\u6bb5\u4e3anull\u4e5f\u4f1a\u88ab\u8d4b\u503c\u5230json\u4e2d, <code>explicitNulls = false</code>\u53ef\u4ee5\u5ffd\u7565\u6389</li> </ul>"},{"location":"kotlin-serialization.html#_8","title":"\u81ea\u52a8\u751f\u6210","text":"<p>\u624b\u52a8\u5199\u9ed8\u8ba4\u503c\u592a\u9ebb\u70e6, \u63a8\u8350\u4f7f\u7528\u63d2\u4ef6\u751f\u6210\u9ed8\u8ba4\u503c</p> <p></p> <p>\u63d2\u4ef6\u5177\u4f53\u914d\u7f6e\u4f7f\u7528\u8bf7\u67e5\u770b: \u6570\u636e\u6a21\u578b\u751f\u6210\u63d2\u4ef6</p>"},{"location":"log-notice.html","title":"\u65e5\u5fd7\u901a\u77e5","text":"<p>\u4f7f\u7528\u4e09\u65b9\u5e93 Chucker \u5728\u901a\u77e5\u680f\u8bb0\u5f55\u7f51\u7edc\u8bf7\u6c42\u65e5\u5fd7</p> <p> Chucker</p> <p>\u4f9d\u8d56</p> <pre><code>implementation \"com.github.chuckerteam.chucker:library:3.5.2\"\n</code></pre> <p>\u6dfb\u52a0\u62e6\u622a\u5668</p> <pre><code>NetConfig.initialize(Api.HOST, this) {\n // ...\n if (BuildConfig.DEBUG) {\n addInterceptor(\n ChuckerInterceptor.Builder(this@App)\n .collector(ChuckerCollector(this@App))\n .maxContentLength(250000L)\n .redactHeaders(emptySet())\n .alwaysReadResponseBody(false)\n .build()\n )\n }\n}\n</code></pre> <p>\u81ea\u5b9a\u4e49\u529f\u80fd\u6d4f\u89c8 Chucker \u5b98\u7f51</p>"},{"location":"log-recorder.html","title":"\u65e5\u5fd7\u63d2\u4ef6","text":"<p>\u4ee5\u4e0b\u4e24\u79cd\u65e5\u5fd7\u63d2\u4ef6</p> Okhttp Profiler Profiler \u5217\u8868\u663e\u793a \u52a8\u6001\u66f2\u7ebf\u56fe \u6dfb\u52a0<code>LogRecordInterceptor</code>\u62e6\u622a\u5668 \u9ed8\u8ba4\u8bb0\u5f55\u6240\u6709OkHttp\u7684\u8bf7\u6c42 \u539f\u7406\u662f\u63d2\u4ef6\u6355\u83b7LogCat\u65e5\u5fd7, \u7ebf\u4e0a\u73af\u5883\u9700\u5173\u95ed \u65e0\u6cd5\u6355\u83b7\u542f\u52a8\u4e00\u77ac\u95f4\u7684\u8bf7\u6c42"},{"location":"log-recorder.html#logrecordinterceptor","title":"LogRecordInterceptor","text":"<p>\u6dfb\u52a0\u65e5\u5fd7\u62e6\u622a\u5668</p> <pre><code>NetConfig.initialize(Api.HOST, this) {\n addInterceptor(LogRecordInterceptor(BuildConfig.DEBUG))\n}\n</code></pre> \u6784\u9020\u53c2\u6570 \u63cf\u8ff0 enabled \u662f\u5426\u542f\u7528\u65e5\u5fd7 requestByteCount \u8bf7\u6c42\u65e5\u5fd7\u4fe1\u606f\u6700\u5927\u5b57\u8282\u6570, \u9ed8\u8ba41MB responseByteCount \u54cd\u5e94\u65e5\u5fd7\u4fe1\u606f\u6700\u5927\u5b57\u8282\u6570, \u9ed8\u8ba44MB <p>\u6b64\u65f6\u4ec5LogCat\u8f93\u51fa\u65e5\u5fd7, \u8981\u9884\u89c8\u8bf7\u5b89\u88c5\u63d2\u4ef6</p>"},{"location":"log-recorder.html#_1","title":"\u5b89\u88c5\u63d2\u4ef6","text":""},{"location":"log-recorder.html#1","title":"1. \u5b89\u88c5\u63d2\u4ef6","text":"<p>\u5728\u63d2\u4ef6\u5e02\u573a\u641c\u7d22: \"<code>Okhttp Profiler</code>\"</p> <p></p>"},{"location":"log-recorder.html#2","title":"2. \u6253\u5f00\u7a97\u53e3","text":"<p>\u5b89\u88c5\u4ee5\u540e\u5728AndroidStudio\u53f3\u4e0b\u89d2\u6253\u5f00\u7a97\u53e3</p> <p></p> <p>\u4e0d\u663e\u793a\u65e5\u5fd7</p> <p>\u8bf7\u5728\u8bf7\u6c42\u524d\u786e\u4fdd\u6709\u6253\u5f00\u8fc7\u63d2\u4ef6\u7a97\u53e3, \u5982\u679c\u4f9d\u7136\u4e0d\u663e\u793a\u53ef\u4ee5\u53cd\u590d\u6253\u5f00/\u5173\u95ed\u7a97\u53e3</p> <p>\u6bcf\u6b21AS\u66f4\u65b0\u53ef\u80fd\u8981\u8be5\u63d2\u4ef6\u4f5c\u8005\u9002\u914d, \u53d1\u73b0\u65e0\u6548\u8bf7\u53cd\u9988\u7ed9\u4f5c\u8005\u66f4\u65b0</p> <p>\u4f7f\u7528\u6548\u679c</p> <p></p> \u6807\u9898 \u63cf\u8ff0 Device \u9009\u62e9\u8c03\u8bd5\u8bbe\u5907 Process \u9009\u62e9\u5c55\u793a\u8bb0\u5f55\u7684\u8fdb\u7a0b \u6293\u53d6 \u4e00\u822c\u60c5\u51b5\u4e0d\u9700\u8981\u4f7f\u7528, \u5047\u8bbe\u6ca1\u6709\u53ca\u65f6\u66f4\u65b0\u8bf7\u70b9\u51fb\u56fe\u6807 \u6e05\u7a7a \u6e05\u7a7a\u8bb0\u5f55"},{"location":"log-recorder.html#_2","title":"\u81ea\u5b9a\u4e49\u65e5\u5fd7","text":"<p>\u7ee7\u627f<code>LogRecordInterceptor</code>\u590d\u5199\u51fd\u6570\u5b9e\u73b0\u81ea\u5b9a\u4e49</p> <ol> <li>\u590d\u5199<code>getRequestLog</code>\u8fd4\u56de\u8bf7\u6c42\u53c2\u6570</li> <li>\u590d\u5199<code>getResponseLog</code>\u8fd4\u56de\u54cd\u5e94\u53c2\u6570</li> </ol> <p>\u521d\u59cb\u5316\u65f6\u6dfb\u52a0\u81ea\u5df1\u7684\u62e6\u622a\u5668</p> <pre><code>NetConfig.initialize(Api.HOST, this) {\n addInterceptor(MyLogRecordInterceptor(BuildConfig.DEBUG))\n}\n</code></pre>"},{"location":"log-recorder.html#_3","title":"\u65e5\u5fd7\u8fc7\u6ee4","text":"<p>\u4e0d\u60f3\u7f51\u7edc\u65e5\u5fd7\u5f71\u54cd\u5176\u4ed6\u65e5\u5fd7\u67e5\u770b, \u53ef\u4ee5\u6dfb\u52a0<code>OKPREL_</code>\u4e3a\u65e5\u5fd7\u6298\u53e0\u89c4\u5219 </p>"},{"location":"log-recorder.html#_4","title":"\u5176\u4ed6\u7f51\u7edc\u6846\u67b6","text":"<p><code>LogRecordInterceptor</code>\u5c5e\u4e8eOkHttp\u62e6\u622a\u5668, \u5176\u4ed6\u7f51\u7edc\u8bf7\u6c42\u6846\u67b6\u4e5f\u53ef\u4ee5\u4f7f\u7528</p> <p>\u6216\u8005\u76f4\u63a5\u4f7f\u7528<code>LogRecorder</code>\u8f93\u51fa\u65e5\u5fd7</p> LogRecorder \u63cf\u8ff0 generateId \u4ea7\u751f\u4e00\u4e2a\u552f\u4e00\u6807\u8bc6\u7b26, \u7528\u4e8e\u5224\u65ad\u4e3a\u540c\u4e00\u7f51\u7edc\u8bf7\u6c42 recordRequest \u8bb0\u5f55\u8bf7\u6c42\u4fe1\u606f recordResponse \u8bb0\u5f55\u54cd\u5e94\u4fe1\u606f recordException \u8bb0\u5f55\u8bf7\u6c42\u5f02\u5e38\u4fe1\u606f"},{"location":"model-generate.html","title":"\u6570\u636e\u7c7b\u751f\u6210\u63d2\u4ef6","text":"<p>\u5e94\u8be5\u6ca1\u4eba\u4f1a\u5b8c\u5168\u624b\u5199\u6570\u636e\u6a21\u578b\u5427? \u5efa\u8bae\u4f7f\u7528<code>JSON To Kotlin Class</code> \u63d2\u4ef6\u5b8c\u6210</p>"},{"location":"model-generate.html#_1","title":"\u5b89\u88c5\u63d2\u4ef6","text":"<p>\u5728Plugins\u91cc\u9762\u641c\u7d22kotlin\u5173\u952e\u8bcd\u4e0b\u8f7d\u5b89\u88c5 </p>"},{"location":"model-generate.html#_2","title":"\u4f7f\u7528\u63d2\u4ef6","text":"<p>\u9009\u4e2d\u5206\u5305\u540e, \u4f7f\u7528\u5feb\u6377\u952e\u6216\u8005\u9f20\u6807\u53f3\u952e\u6253\u5f00\u586b\u5199Json\u754c\u9762</p> <p></p> <p>\u6dfb\u52a0Json\u7136\u540e\u70b9\u51fb<code>Generate</code>\u751f\u6210</p> <p></p> <p>\u7136\u540e\u5c31\u4f1a\u5728\u9009\u4e2d\u7684\u5206\u5305\u4e0b\u751f\u6210\u4e00\u4e2a\u6570\u636e\u6a21\u578b\u7c7b\u4e86</p> <p>\u4e0d\u8981\u751f\u6210\u6570\u7ec4</p> <p>\u4e0d\u8981\u8f93\u5165JSON\u6570\u7ec4\u751f\u6210(\u5426\u5219\u751f\u6210\u7684\u7c7b\u4f1a\u7ee7\u627fArrayList), \u8f93\u5165JSON\u5bf9\u8c61, \u8bf7\u6c42\u4f7f\u7528<code>Get&lt;List&lt;\u5bf9\u8c61&gt;&gt;</code></p>"},{"location":"model-generate.html#_3","title":"\u9ad8\u7ea7\u8bbe\u7f6e","text":"<p>\u70b9\u51fb<code>Advanced</code>\u6253\u5f00\u8bbe\u7f6e\u754c\u9762</p>"},{"location":"model-generate.html#_4","title":"\u53ef\u7a7a\u9009\u9879","text":"<p>\u622a\u56fe\u5373\u4e3a\u6211\u7684\u63a8\u8350\u914d\u7f6e</p> <p></p> <ol> <li>Keyword \u521b\u5efa\u7684\u6570\u636e\u6a21\u578b\u7684\u5b57\u6bb5\u662f Val\u8fd8\u662fVar</li> <li>Type \u5b57\u6bb5\u662f\u5426\u662f\u53ef\u7a7a\u7c7b\u578b, \u6700\u540e\u9009\u9879\u8868\u793a\u6839\u636eJson\u7684\u503c\u5224\u65ad\u662f\u5426\u53ef\u7a7a</li> <li>\u9ed8\u8ba4\u503c\u7684\u7b56\u7565, \u65e0\u6cd5\u9009\u62e9\u4e0d\u4ecb\u7ecd</li> </ol>"},{"location":"model-generate.html#_5","title":"\u4f7f\u7528\u7684\u6846\u67b6","text":"<p>\u751f\u6210\u6570\u636e\u6a21\u578b\u65f6\u4f1a\u517c\u5bb9\u4f60\u4f7f\u7528\u7684\u6846\u67b6, \u4f8b\u5982Moshi\u548cks\u53ef\u80fd\u9700\u8981\u6ce8\u89e3, \u7136\u540e\u4f1a\u81ea\u52a8\u751f\u6210SerialName\u8fd9\u4e9b\u540d\u79f0\u6ce8\u89e3 </p>"},{"location":"model-generate.html#_6","title":"\u5176\u4ed6","text":"<p>\u622a\u56fe\u5373\u4e3a\u6211\u7684\u63a8\u8350\u914d\u7f6e</p> <p></p> <ol> <li>\u662f\u5426\u4f7f\u7528\u6ce8\u91ca, \u65e2\u4f1a\u5c06Json\u5b57\u7b26\u4e32\u4f5c\u4e3a\u6ce8\u91ca\u4fdd\u7559\u5728\u6570\u636e\u6a21\u578b\u7c7b\u4e2d</li> <li>\u6839\u636e\u5b57\u6bcd\u6392\u5e8f\u6570\u636e\u6a21\u578b\u7684\u5b57\u6bb5</li> <li>\u4f7f\u7528\u5185\u90e8\u7c7b. \u4f8b\u5982Json\u4e2d\u7684Json\u5bf9\u8c61\u4f1a\u4f5c\u4e3a\u5185\u90e8\u7c7b\u88ab\u521b\u5efa\u5728\u6570\u636e\u6a21\u578b\u7c7b\u4e2d (\u63a8\u8350\u5f00\u542f, \u4fdd\u6301\u9ad8\u5185\u805a\u4f4e\u8026\u5408)</li> <li>\u5982\u679cJson\u5bf9\u8c61\u7684\u5b57\u6bb5\u90fd\u662f\u539f\u59cb\u7c7b\u578b\u5219\u4f7f\u7528Map\u6765\u8868\u793a</li> <li>\u53ea\u5728\u9700\u8981\u65f6\u521b\u5efa\u6ce8\u89e3</li> <li>\u81ea\u52a8\u9a8c\u8bc1Json\u6b63\u786e\u6027(\u5728\u586b\u5199\u65f6)</li> <li>Json\u683c\u5f0f\u5316\u65f6\u4f7f\u7528\u7684\u7a7a\u683c\u6570\u91cf</li> <li>\u6307\u5b9a\u4e00\u4e2a\u7c7b\u4f5c\u4e3a\u7236\u7c7b\u6a21\u677f(\u65e2\u521b\u5efa\u7684\u6570\u636e\u6a21\u578b\u90fd\u4f1a\u7ee7\u627f\u8be5\u7c7b)</li> </ol>"},{"location":"model-generate.html#_7","title":"\u6269\u5c55","text":"<p>\u622a\u56fe\u5373\u4e3a\u6211\u7684\u63a8\u8350\u914d\u7f6e</p> <p></p> <ol> <li>\u6dfb\u52a0@Keep\u6ce8\u89e3, \u4e3a\u9632\u6b62\u88ab\u4ee3\u7801\u6df7\u6dc6</li> <li>\u6ce8\u89e3\u548c\u5b57\u6bb5\u5904\u4e8e\u540c\u4e00\u884c, \u4fbf\u4e8e\u7f8e\u89c2</li> <li>\u4f7f\u7528Parcelable\u5e8f\u5217\u5316</li> <li>\u4e3a\u5b57\u6bb5\u6dfb\u52a0\u524d\u7f00/\u540e\u7f00</li> <li>\u4e3a\u6570\u636e\u6a21\u578b\u7c7b\u6dfb\u52a0\u524d\u7f00/\u540e\u7f00</li> </ol>"},{"location":"okhttp-client.html","title":"OkHttpClient","text":"<p>Net\u5168\u5c40\u6301\u6709\u4e00\u4e2a<code>OkHttpClient</code>\u5bf9\u8c61\u53d1\u8d77\u8bf7\u6c42</p> <pre><code>object NetConfig {\n var okHttpClient: OkHttpClient\n}\n</code></pre>"},{"location":"okhttp-client.html#_1","title":"\u5168\u5c40","text":"<pre><code>NetConfig.initialize(Api.HOST, this) {\n // \u6b64\u5904this\u5373\u4e3aOkHttpClient.Builder\n}\n</code></pre>"},{"location":"okhttp-client.html#_2","title":"\u5355\u4f8b","text":"<p>\u5355\u72ec\u6307\u5b9a\u5f53\u524d\u8bf7\u6c42\u5ba2\u6237\u7aef</p> \u4fee\u6539\u5168\u5c40\u5ba2\u6237\u7aef\u521b\u5efa\u65b0\u5ba2\u6237\u7aef <p><pre><code>scopeNetLife {\n tv_response.text = Get&lt;String&gt;(Api.PATH) {\n setClient {\n // \u6b64\u5904this\u5373\u4e3aOkHttpClient.Builder\n trustCertificate()\n }\n }.await()\n}\n</code></pre> \u5728\u5168\u5c40<code>OkHttpClient</code>\u57fa\u7840\u4e0a\u4fee\u6539</p> <p><pre><code>scopeNetLife {\n tv_response.text = Get&lt;String&gt;(Api.PATH) {\n okHttpClient = OkHttpClient.Builder().build()\n }.await()\n}\n</code></pre> \u521b\u5efa\u65b0\u7684OkHttpClient, \u4e00\u822c\u4e0d\u4f7f\u7528, \u56e0\u4e3a\u65b0OkHttpClient\u4f1a\u91cd\u65b0\u521b\u5efa\u7ebf\u7a0b\u6c60/\u8fde\u63a5\u6c60\u7b49\u9020\u6210\u5185\u5b58\u6d88\u8017</p>"},{"location":"progress.html","title":"\u8fdb\u5ea6\u76d1\u542c","text":"<p>Net\u652f\u6301\u4e0a\u4f20/\u4e0b\u8f7d\u7684\u8fdb\u5ea6\u76d1\u542c, \u4e14\u5177\u5907\u5b8c\u5584\u7684\u8fdb\u5ea6\u4fe1\u606f</p>"},{"location":"progress.html#_1","title":"\u4e0a\u4f20\u8fdb\u5ea6\u76d1\u542c","text":"<pre><code>scopeNetLife {\n Post&lt;String&gt;(Api.UPLOAD) {\n param(\"file\", assetsFile())\n addUploadListener(object : ProgressListener() {\n override fun onProgress(p: Progress) {\n seek.post {\n seek.progress = p.progress()\n tvProgress.text =\n \"\u4e0a\u4f20\u8fdb\u5ea6: ${p.progress()}% \u4e0a\u4f20\u901f\u5ea6: ${p.speedSize()} \" +\n \"\\n\\n\u6587\u4ef6\u5927\u5c0f: ${p.totalSize()} \u5df2\u4e0a\u4f20: ${p.currentSize()} \u5269\u4f59\u5927\u5c0f: ${p.remainSize()}\" +\n \"\\n\\n\u5df2\u4f7f\u7528\u65f6\u95f4: ${p.useTime()} \u5269\u4f59\u65f6\u95f4: ${p.remainTime()}\"\n }\n }\n })\n }.await()\n}\n</code></pre>"},{"location":"progress.html#_2","title":"\u4e0b\u8f7d\u8fdb\u5ea6\u76d1\u542c","text":"<pre><code>scopeNetLife {\n val file =\n Get&lt;File&gt;(\"https://github.com/liangjingkanji/Net/releases/latest/download/net-sample.apk\") {\n setDownloadFileName(\"net.apk\")\n setDownloadDir(requireContext().filesDir)\n\n addDownloadListener(object : ProgressListener() {\n override fun onProgress(p: Progress) {\n seek?.post {\n val progress = p.progress()\n seek.progress = progress\n tvProgress.text =\n \"\u4e0b\u8f7d\u8fdb\u5ea6: $progress% \u4e0b\u8f7d\u901f\u5ea6: ${p.speedSize()} \" +\n \"\\n\\n\u6587\u4ef6\u5927\u5c0f: ${p.totalSize()} \u5df2\u4e0b\u8f7d: ${p.currentSize()} \u5269\u4f59\u5927\u5c0f: ${p.remainSize()}\" +\n \"\\n\\n\u5df2\u4f7f\u7528\u65f6\u95f4: ${p.useTime()} \u5269\u4f59\u65f6\u95f4: ${p.remainTime()}\"\n }\n }\n })\n }.await()\n}\n</code></pre> <p>\u76d1\u542c\u4efb\u4f55\u8fdb\u5ea6</p> <p>\u4e0d\u4ec5\u662f\u6cdb\u578b\u4e3aFile\u624d\u6709\u6548, \u4efb\u4f55\u8bf7\u6c42\u4f53/\u54cd\u5e94\u4f53\u90fd\u53ef\u4ee5\u76d1\u542c\u8fdb\u5ea6</p> <p><code>Net.addXXListener()</code>\u53ef\u4ee5\u6839\u636e<code>Id</code>\u4efb\u610f\u4f4d\u7f6e\u76d1\u542c\u8bf7\u6c42</p>"},{"location":"progress.html#_3","title":"\u76d1\u542c\u5668","text":"<p>\u5b9e\u73b0<code>ProgressListener</code>\u76d1\u542c\u8fdb\u5ea6\u4fe1\u606f, \u8fdb\u5ea6\u4fe1\u606f\u4e3a<code>Progress</code></p>"},{"location":"progress.html#_4","title":"\u8fdb\u5ea6\u95f4\u9694\u65f6\u95f4","text":"<p>ProgressListener\u7684\u6784\u9020\u53c2\u6570<code>interval</code>\u63a7\u5236\u89e6\u53d1\u8fdb\u5ea6\u76d1\u542c\u5668\u7684\u95f4\u9694\u65f6\u95f4</p>"},{"location":"progress.html#_5","title":"\u8fdb\u5ea6\u4fe1\u606f","text":"\u51fd\u6570 \u63cf\u8ff0 currentBytes \u5df2\u5b8c\u6210\u5b57\u8282\u6570 totalBytes \u5168\u90e8\u5927\u5c0f\u5b57\u8282\u6570 intervalBytes \u8fdb\u5ea6\u95f4\u9694\u65f6\u95f4\u5185\u5b8c\u6210\u7684\u5b57\u8282\u6570 intervalTime \u8ddd\u79bb\u4e0a\u6b21\u8fdb\u5ea6\u53d8\u5316\u95f4\u9694\u65f6\u95f4 startElapsedRealtime \u5f00\u59cb\u4e0b\u8f7d\u65f6\u95f4(\u8be5\u65f6\u95f4\u503c\u5f00\u673a\u5230\u73b0\u5728\u7684\u6beb\u79d2\u6570) speedBytes \u6bcf\u79d2\u4e0b\u8f7d\u5b57\u8282\u6570 progress \u8fdb\u5ea6, 1-100 finish \u6b64\u6b21\u4e0b\u8f7d/\u4e0a\u4f20\u662f\u5426\u5b8c\u6210 useTimeSeconds \u5df2\u7ecf\u4f7f\u7528\u65f6\u95f4, \u5355\u4f4d\u79d2 remainTimeSeconds \u4f30\u7b97\u7684\u5269\u4f59\u65f6\u95f4, \u5355\u4f4d\u79d2"},{"location":"progress.html#_6","title":"\u683c\u5f0f\u5316\u5b57\u7b26\u4e32","text":"\u51fd\u6570 \u63cf\u8ff0 currentSize \u5df2\u5b8c\u6210\u5927\u5c0f, \u4f8b\u5982: <code>120kB</code> \u6216\u8005 <code>1.5MB</code> totalSize \u5168\u90e8\u5927\u5c0f remainSize \u5269\u4f59\u5927\u5c0f speedSize \u6bcf\u79d2\u4e0b\u8f7d\u5927\u5c0f useTime \u5df2\u4f7f\u7528\u65f6\u95f4, \u683c\u5f0f\u4e3a: <code>01:23:04</code> remainTime \u4f30\u7b97\u7684\u5269\u4f59\u65f6\u95f4, \u683c\u5f0f\u4e3a: <code>01:23:04</code>"},{"location":"repeat-request.html","title":"\u91cd\u590d\u8bf7\u6c42","text":"<p>\u5e38\u7528\u4e8e\u7b5b\u9009\u5217\u8868\u8bf7\u6c42, \u9009\u62e9\u65b0\u7684\u7b5b\u9009\u6761\u4ef6\u65f6\u5e94\u5c06\u4e0a\u6b21\u672a\u5b8c\u6210\u7684\u53d6\u6d88\u540e\u518d\u53d1\u8d77\u8bf7\u6c42</p> <p>\u5728Net\u7981\u6b62\u91cd\u590d\u8bf7\u6c42\u4ec52\u884c\u4ee3\u7801</p> <pre><code>var scope: AndroidScope? = null\n\nbtnFilter.setOnClickListener {\n scope?.cancel()\n\n scope = scopeNetLife {\n val result = Post&lt;String&gt;(Api.PATH).await()\n }\n}\n</code></pre> <p>\u5f53<code>scope</code>\u4e0d\u4e3a\u7a7a\u65f6\u8868\u793a\u5b58\u5728\u65e7\u8bf7\u6c42, \u65e0\u8bba\u65e7\u8bf7\u6c42\u662f\u5426\u5b8c\u6210\u90fd\u53ef\u4ee5\u8c03\u7528<code>cancel()</code>\u4fdd\u8bc1\u53d6\u6d88\u5373\u53ef</p> <ol> <li>\u53d6\u6d88\u8bf7\u6c42 </li> <li>\u9650\u5236\u65f6\u95f4\u5f3a\u5236\u4f7f\u7528\u7f13\u5b58, \u914d\u7f6e\u7f13\u5b58\u6709\u6548\u671f</li> </ol>"},{"location":"request.html","title":"\u8bf7\u6c42\u53c2\u6570","text":"<p>\u8bf7\u6c42\u53c2\u6570</p> <p>\u6839\u636e\u8bf7\u6c42\u65b9\u5f0f\u4e0d\u540c\u8bf7\u6c42\u53c2\u6570\u5206\u4e3a\u4e24\u7c7b</p> <p><code>UrlRequest</code>: GET, HEAD, OPTIONS, TRACE // Query(\u8bf7\u6c42\u53c2\u6570\u4f4d\u4e8eUrl\u4e2d) <code>BodyRequest</code>: POST, DELETE, PUT, PATCH // Body(\u8bf7\u6c42\u4f53\u4e3a\u6d41)</p> <p>\u4f7f\u7528\u793a\u4f8b</p> <pre><code>scopeNetLife {\n val userInfo = Post&lt;UserInfoModel&gt;(Api.LOGIN) {\n param(\"username\", \"\u7528\u6237\u540d\")\n param(\"password\", \"6f2961eb44b12123393fff7e449e50b9de2499c6\")\n }.await()\n}\n</code></pre> \u51fd\u6570 \u63cf\u8ff0 <code>param</code> Url\u8bf7\u6c42\u65f6\u4e3aQuery, Body\u8bf7\u6c42\u65f6\u4e3a\u8868\u5355/\u6587\u4ef6 <code>json</code> JSON\u5b57\u7b26\u4e32 <code>setQuery/addQuery</code> Url\u4e2d\u7684Query\u53c2\u6570, \u5982\u679c\u5f53\u4e3aUrl\u8bf7\u6c42\u5219\u8be5\u51fd\u6570\u7b49\u6548<code>param</code> <code>setHeader/addHeader</code> \u8bbe\u7f6e/\u6dfb\u52a0\u8bf7\u6c42\u5934"},{"location":"request.html#json","title":"JSON\u8bf7\u6c42","text":"<p>\u4e09\u79cd\u53c2\u6570\u7c7b\u578b\u4e0a\u4f20JSON\u793a\u4f8b, \u66f4\u591a\u8bf7\u9605\u8bfb\u65b9\u6cd5\u6ce8\u91ca</p> \u952e\u503c\u5bf9JSONObject\u81ea\u5b9a\u4e49RequestBody <pre><code>val name = \"\u91d1\u57ce\u6b66\"\nval age = 29\nval measurements = listOf(100, 100, 100)\n\nscopeNetLife {\n tv.text = Post&lt;String&gt;(Api.PATH) {\n // \u53ea\u652f\u6301\u57fa\u7840\u7c7b\u578b\u7684\u503c, \u5982\u679c\u503c\u4e3a\u5bf9\u8c61\u6216\u8005\u5305\u542b\u5bf9\u8c61\u7684\u96c6\u5408/\u6570\u7ec4\u4f1a\u5bfc\u81f4\u5176\u503c\u4e3anull\n json(\"name\" to name, \"age\" to age, \"measurements\" to measurements)\n }.await()\n}\n</code></pre> <pre><code>val name = \"\u91d1\u57ce\u6b66\"\nval age = 29\nval measurements = listOf(100, 100, 100) // \u53ea\u652f\u6301\u57fa\u7840\u7c7b\u578b\u7684\u503c, \u5982\u679c\u503c\u4e3a\u5bf9\u8c61\u6216\u8005\u5305\u542b\u5bf9\u8c61\u7684\u96c6\u5408/\u6570\u7ec4\u4f1a\u5bfc\u81f4\u5176\u503c\u4e3anull\n\nscopeNetLife {\n tv.text = Post&lt;String&gt;(Api.PATH) {\n json(JSONObject().run {\n put(\"name\", name)\n put(\"age\", age)\n put(\"measurements\", JSONArray(measurements))\n })\n }.await()\n}\n</code></pre> <pre><code>val name = \"\u91d1\u57ce\u6b66\"\nval age = 29\nval measurements = listOf(100, 100, 100)\n\nscopeNetLife {\n tv.text = Post&lt;String&gt;(Api.PATH) {\n body = CustomizerJSONBody(name, age, measurements)\n }.await()\n}\n</code></pre> <p>\u5982\u679cJSON\u9700\u8981\u5168\u5c40\u53c2\u6570</p> <ol> <li>\u81ea\u5b9a\u4e49<code>RequestBody</code>\u6dfb\u52a0\u5168\u5c40\u53c2\u6570</li> <li>\u4f7f\u7528\u8bf7\u6c42\u62e6\u622a\u5668\u6765\u6dfb\u52a0\u5168\u5c40\u53c2\u6570 RequestInterceptor</li> </ol>"},{"location":"request.html#_1","title":"\u81ea\u5b9a\u4e49\u8bf7\u6c42\u51fd\u6570","text":"<p>\u6bd4\u5982\u7531\u4e8e<code>json()</code>\u4f7f\u7528\u7684<code>org.json.JSONObject</code>\u4e0d\u652f\u6301\u5e8f\u5217\u5316\u5bf9\u8c61</p> <p>\u53ef\u4ee5\u521b\u5efa\u6269\u5c55\u51fd\u6570\u6765\u4f7f\u7528\u81ea\u5b9a\u4e49\u5e8f\u5217\u5316\u6846\u67b6\u6765\u89e3\u51b3, \u5982\u4e0b</p> GsonFastJson <pre><code>fun BodyRequest.gson(vararg body: Pair&lt;String, Any?&gt;) {\n this.body = Gson().toJson(body.toMap()).toRequestBody(MediaConst.JSON)\n}\n</code></pre> <pre><code>fun BodyRequest.fastJson(obj: Any) {\n this.body = JSON.toJSON(obj).toRequestBody(MediaConst.JSON)\n}\n</code></pre> <p>\u4f7f\u7528</p> <pre><code>scopeNetLife {\n tv.text = Post&lt;String&gt;(Api.PATH) {\n gson(\"name\" to name, \"data\" to Data())\n // fastJson(data)\n }.await()\n}\n</code></pre>"},{"location":"request.html#_2","title":"\u81ea\u5b9a\u4e49\u8bf7\u6c42\u4f53","text":"<p>\u8981\u6c42\u5b9e\u73b0<code>RequestBody</code>\u63a5\u53e3, \u53ef\u53c2\u8003Net\u4e0a\u4f20Uri/File\u7684\u5b9e\u73b0\u6e90\u7801</p> FileRequestBody <pre><code>fun File.toRequestBody(contentType: MediaType? = null): RequestBody {\n val fileMediaType = contentType ?: mediaType()\n return object : RequestBody() {\n\n // \u6587\u4ef6\u7c7b\u578b\n override fun contentType(): MediaType? {\n return fileMediaType\n }\n\n // \u6587\u4ef6\u957f\u5ea6, \u4e0d\u786e\u5b9a\u8fd4\u56de-1\n override fun contentLength() = length()\n\n // \u5199\u5165\u6570\u636e\n override fun writeTo(sink: BufferedSink) {\n source().use { source -&gt;\n sink.writeAll(source)\n }\n }\n }\n}\n</code></pre> UriRequestBody <pre><code>fun Uri.toRequestBody(): RequestBody {\n val document = DocumentFile.fromSingleUri(NetConfig.app, this)\n val contentResolver = NetConfig.app.contentResolver\n val contentLength = document?.length() ?: -1L\n val contentType = mediaType()\n return object : RequestBody() {\n override fun contentType(): MediaType? {\n return contentType\n }\n\n override fun contentLength() = contentLength\n\n override fun writeTo(sink: BufferedSink) {\n contentResolver.openInputStream(this@toRequestBody)?.use {\n sink.writeAll(it.source())\n }\n }\n }\n}\n</code></pre> <p>\u4f7f\u7528 <pre><code>scopeNetLife {\n tv.text = Post&lt;String&gt;(Api.PATH) {\n // \u5b8c\u5168\u81ea\u5b9a\u4e49\u8bf7\u6c42\u4f53, \u4f1a\u5ffd\u7565\u5176\u4ed6\u8bf7\u6c42\u53c2\u6570\n body = CustomizerRequestBody()\n }.await()\n}\n</code></pre></p>"},{"location":"request.html#_3","title":"\u5168\u5c40\u8bf7\u6c42\u53c2\u6570","text":"<p>\u4f7f\u7528<code>RequestInterceptor</code>\u8bf7\u6c42\u62e6\u622a\u5668\u6dfb\u52a0\u5168\u5c40\u53c2\u6570/\u8bf7\u6c42\u5934, \u66f4\u590d\u6742\u8bf7\u5b9e\u73b0<code>Interceptor</code></p> <pre><code>class GlobalHeaderInterceptor : RequestInterceptor {\n\n // \u6bcf\u6b21\u8bf7\u6c42\u90fd\u4f1a\u56de\u8c03, \u53ef\u4ee5\u662f\u52a8\u6001\u53c2\u6570\n override fun interceptor(request: BaseRequest) {\n request.setHeader(\"client\", \"Android\")\n request.setHeader(\"token\", UserConfig.token)\n }\n}\n</code></pre> <pre><code>NetConfig.initialize(Api.HOST, this) {\n setRequestInterceptor(GlobalHeaderInterceptor())\n}\n</code></pre> <p>\u66f4\u591a\u8bf7\u6c42\u53c2\u6570\u76f8\u5173\u8bf7\u9605\u8bfbApi\u6587\u6863/\u51fd\u6570\u5217\u8868</p>"},{"location":"scope.html","title":"\u4f5c\u7528\u57df","text":"<p>\u521b\u5efa\u4e0d\u540c\u534f\u7a0b\u4f5c\u7528\u57df\u53ef\u4ee5\u5b9e\u73b0\u4e0d\u540c\u7684\u529f\u80fd</p> <p>\u51cf\u5c11\u5d29\u6e83</p> <p>Net\u6240\u6709\u4f5c\u7528\u57df\u5185\u629b\u51fa\u5f02\u5e38\u90fd\u4f1a\u88ab\u6355\u83b7\u5230, \u53ef\u4ee5\u9632\u6b62\u5e94\u7528\u5d29\u6e83 </p>"},{"location":"scope.html#_1","title":"\u5f02\u6b65\u4efb\u52a1\u7684\u4f5c\u7528\u57df","text":"<p>\u53ef\u4ee5\u6355\u6349\u5f02\u5e38\u7684\u534f\u7a0b\u4f5c\u7528\u57df, \u7528\u4e8e\u6784\u5efa\u666e\u901a\u5f02\u6b65\u4efb\u52a1</p> \u51fd\u6570 \u63cf\u8ff0 <code>scope</code> \u521b\u5efa\u6700\u57fa\u7840\u7684\u4f5c\u7528\u57df <code>scopeLife</code> \u521b\u5efa\u8ddf\u968f\u751f\u547d\u5468\u671f\u81ea\u52a8\u53d6\u6d88\u7684\u4f5c\u7528\u57df <code>ViewModel.scopeLife</code> \u521b\u5efa\u8ddf\u968fViewModel\u751f\u547d\u5468\u671f\u7684\u4f5c\u7528\u57df, \u5982\u4f55\u5728ViewModel\u521b\u5efa\u4f5c\u7528\u57df"},{"location":"scope.html#_2","title":"\u7f51\u7edc\u8bf7\u6c42\u7684\u4f5c\u7528\u57df","text":"<p>\u9664\u5f02\u6b65\u4efb\u52a1\u5916\u8fd8\u9002\u7528\u4e8e\u7f51\u7edc\u8bf7\u6c42\u573a\u666f\u7684\u4f5c\u7528\u57df, \u5bf9\u6bd4\u4e0a\u9762<code>\u5f02\u6b65\u4efb\u52a1\u7684\u4f5c\u7528\u57df</code>\u533a\u522b:</p> <ol> <li>\u53d1\u751f\u9519\u8bef\u81ea\u52a8\u5410\u53f8(\u53ef\u4ee5\u81ea\u5b9a\u4e49\u6216\u8005\u53d6\u6d88)</li> <li>\u53d1\u751f\u9519\u8bef\u4f1a\u89e6\u53d1\u5168\u5c40\u9519\u8bef\u5904\u7406<code>NetErrorHandler</code></li> <li>\u5177\u5907\u4e00\u4e9b\u7279\u6b8a\u573a\u666f\u529f\u80fd, \u6bd4\u5982\u6839\u636e\u7f51\u7edc\u8bf7\u6c42\u7ed3\u679c\u81ea\u52a8\u5904\u7406\u4e0b\u62c9\u5237\u65b0/\u4e0a\u62c9\u52a0\u8f7d/\u7f3a\u7701\u9875/\u52a0\u8f7d\u6846\u7684\u72b6\u6001</li> </ol> \u51fd\u6570 \u63cf\u8ff0 <code>scopeNet</code> \u521b\u5efa\u81ea\u52a8\u5904\u7406\u7f51\u7edc\u9519\u8bef\u7684\u4f5c\u7528\u57df <code>scopeNetLife</code> \u521b\u5efa\u81ea\u52a8\u5904\u7406\u7f51\u7edc\u9519\u8bef\u7684\u4f5c\u7528\u57df, \u4e14\u5305\u542b\u8ddf\u968fActivity\u6216\u8005Fragment\u751f\u547d\u5468\u671f <code>scopeDialog</code> \u521b\u5efa\u81ea\u52a8\u52a0\u8f7d\u5bf9\u8bdd\u6846\u7684\u4f5c\u7528\u57df, \u751f\u547d\u5468\u671f\u8ddf\u968f\u5bf9\u8bdd\u6846 <code>ViewModel.scopeNetLife</code> \u521b\u5efa\u8ddf\u968fViewModel\u751f\u547d\u5468\u671f\u7684\u4f5c\u7528\u57df, \u5982\u4f55\u5728ViewModel\u521b\u5efa\u4f5c\u7528\u57df <code>PageRefreshLayout.scope</code> \u521b\u5efa\u8ddf\u968fPageRefreshLayout\u751f\u547d\u5468\u671f\u7684\u4f5c\u7528\u57df <code>StateLayout.scope</code> \u521b\u5efa\u8ddf\u968fStateLayout\u751f\u547d\u5468\u671f\u7684\u4f5c\u7528\u57df <p>\u533a\u5206\u51fd\u6570\u63a5\u53d7\u8005</p> <p>\u4f18\u5148\u8ddf\u968f\u5e03\u5c40\u800c\u975eActivity\u751f\u547d\u5468\u671f, \u6240\u4ee5PageRefreshLayout\u7b49onRefresh\u51fd\u6570\u5185\u8bf7\u4f7f\u7528<code>scope</code></p> <p>\u7b2c\u4e09\u65b9\u5e93\u652f\u6301</p> <p>PageRefreshLayout/StateLayout \u5c5e\u4e8e\u7b2c\u4e09\u65b9\u5f00\u6e90\u9879\u76ee BRV \u6846\u67b6\u4e2d\u7684\u5e03\u5c40, \u53ef\u7528\u4e8e\u652f\u6301\u81ea\u52a8\u5316\u7f3a\u7701\u9875/\u4e0b\u62c9\u5237\u65b0</p> <p>\u5982\u679c\u60f3\u66f4\u4e86\u89e3\u534f\u7a0b\u4f7f\u7528\u65b9\u5f0f, \u53ef\u4ee5\u9605\u8bfb\u4e00\u7bc7\u6587\u7ae0: \u6700\u5168\u9762\u7684Kotlin\u534f\u7a0b: Coroutine/Channel/Flow \u4ee5\u53ca\u5b9e\u9645\u5e94\u7528</p>"},{"location":"scope.html#_3","title":"\u5d4c\u5957\u4f5c\u7528\u57df","text":"<p>\u6709\u65f6\u5019\u53ef\u80fd\u9762\u4e34\u5185\u5d4c<code>scopeXX</code>\u51fd\u6570(\u5d4c\u5957\u4f5c\u7528\u57df), \u8fd9\u65f6\u5019\u751f\u547d\u5468\u671f\u5982\u4e0b</p> <pre><code>scopeNetLife {\n val task = Post&lt;String&gt;(\"path\").await()\n\n scopeNetLife {\n val task = Post&lt;String&gt;(\"path/error\").await() // \u6b64\u65f6\u53d1\u751f\u8bf7\u6c42\u9519\u8bef\n }.catch {\n // A\n }\n}.catch {\n // B\n}\n</code></pre> <ul> <li>\u9519\u8bef\u5c06\u5728<code>A</code>\u5904\u53ef\u4ee5\u83b7\u53d6\u5230, \u4e14\u4e0d\u5f71\u54cd\u5916\u90e8<code>scopeNetLife</code>\u7684\u8bf7\u6c42</li> <li>\u4e24\u4e2a<code>scopeNetLife</code>\u7684\u5f02\u5e38\u629b\u51fa\u548c\u6355\u83b7\u4e92\u4e0d\u5f71\u54cd</li> <li><code>scopeXX()</code>\u7b49\u51fd\u6570\u540c\u7406</li> </ul>"},{"location":"scope.html#_4","title":"\u5b50\u4f5c\u7528\u57df","text":"<pre><code>scopeNet {\n val await = Post&lt;String&gt;(\"path\").await()\n\n launch {\n val task = Post&lt;String&gt;(\"path/error\").await() // \u6b64\u65f6\u53d1\u751f\u8bf7\u6c42\u9519\u8bef\n }.invokeOnCompletion {\n // A\n }\n}.catch {\n // B\n}\n</code></pre> <ul> <li>\u8fd9\u79cd\u60c5\u51b5 \u5148\u6267\u884c<code>A</code>\u7136\u540e\u6267\u884c<code>B</code>, \u5e76\u4e14\u90fd\u80fd\u6355\u83b7\u5f02\u5e38.</li> <li>\u540c\u65f6<code>scopeNet</code>\u53d1\u751f\u9519\u8bef\u4e5f\u4f1a\u5bfc\u81f4<code>launch</code>\u5185\u7684\u8bf7\u6c42\u88ab\u53d6\u6d88, <code>launch</code>\u53d1\u751f\u9519\u8bef\u4e5f\u4f1a\u5bfc\u81f4<code>scopeNet</code>\u53d1\u751f\u9519\u8bef</li> </ul>"},{"location":"sync-request.html","title":"\u540c\u6b65\u8bf7\u6c42","text":"<p>Net\u652f\u6301\u5728\u5f53\u524d\u7ebf\u7a0b\u6267\u884c\u963b\u585e\u7ebf\u7a0b\u7684\u540c\u6b65\u8bf7\u6c42</p> <p>\u4ec0\u4e48\u662f\u540c\u6b65\u8bf7\u6c42</p> <p>\u5373\u4e0a\u4e2a\u8bf7\u6c42\u7ed3\u675f\u624d\u4f1a\u53d1\u8d77\u4e0b\u4e2a\u8bf7\u6c42, \u5b9e\u9645\u4e0a\u534f\u7a0b\u4e5f\u53ef\u4ee5\u5b9e\u73b0\u4f46\u662f\u4ed6\u4e0d\u4f1a\u963b\u585e\u7ebf\u7a0b</p> <p>\u540c\u6b65\u8bf7\u6c42\u5e94\u7528\u573a\u666f\u4e00\u822c\u662f\u5728\u62e6\u622a\u5668(\u6267\u884c\u5728\u5b50\u7ebf\u7a0b)\u4e2d\u4f7f\u7528</p> <p>\u56e0\u4e3aAndroid\u4e3b\u7ebf\u7a0b\u4e0d\u5141\u8bb8\u53d1\u8d77\u7f51\u7edc\u8bf7\u6c42, \u8fd9\u91cc\u521b\u5efa\u4e00\u4e2a\u5b50\u7ebf\u7a0b\u6765\u6f14\u793a</p> \u8fd4\u56de\u6570\u636e\u8fd4\u56deResult <pre><code>thread {\n val result = Net.post(Api.PATH).execute&lt;String&gt;() // \u7f51\u7edc\u8bf7\u6c42\u4e0d\u5141\u8bb8\u5728\u4e3b\u7ebf\u7a0b\n tv?.post {\n tv?.text = result // view\u8981\u6c42\u5728\u4e3b\u7ebf\u7a0b\u66f4\u65b0\n }\n}\n</code></pre> <pre><code>thread {\n val result = Net.post(Api.PATH).toResult&lt;String&gt;().getOrDefault(\"\u8bf7\u6c42\u53d1\u751f\u9519\u8bef, \u6211\u662f\u9ed8\u8ba4\u503c\")\n tv?.post {\n tv?.text = result // view\u8981\u6c42\u5728\u4e3b\u7ebf\u7a0b\u66f4\u65b0\n }\n}\n</code></pre> <ol> <li><code>execute</code>\u5728\u8bf7\u6c42\u9519\u8bef\u65f6\u4f1a\u76f4\u63a5\u629b\u51fa\u5f02\u5e38</li> <li><code>toResult</code>\u4e0d\u4f1a\u629b\u51fa\u5f02\u5e38, \u53ef<code>getOrThrow/exceptionOrNull</code>\u7b49\u8fd4\u56de\u5f02\u5e38\u5bf9\u8c61</li> </ol>"},{"location":"tag.html","title":"\u6807\u7b7e/\u989d\u5916","text":"<p>Net\u652f\u6301\u4e24\u79cd\u65b9\u5f0f\u643a\u5e26\u6570\u636e, \u8d2f\u7a7f\u6574\u4e2a\u8bf7\u6c42\u6d41\u7a0b(\u8bf7\u6c42/\u62e6\u622a\u5668/\u8f6c\u6362\u5668)</p> <ul> <li>tag: <code>HashMap&lt;Class&lt;*&gt;, Any?&gt;</code> \u6807\u7b7e</li> <li>extra: <code>HashMap&lt;String, Any?&gt;</code> \u989d\u5916\u6570\u636e</li> </ul> <p>\u4e24\u8005\u533a\u522b\u4e3a\u5b58\u50a8\u65f6key\u662f<code>Class</code>\u8fd8\u662f<code>String</code>, \u81ea\u7531\u9009\u62e9</p>"},{"location":"tag.html#_1","title":"\u6807\u7b7e\u4f7f\u7528","text":""},{"location":"tag.html#1","title":"1. \u5199\u5165\u6807\u7b7e","text":"<pre><code>scopeNetLife {\n tv.text = Get&lt;String&gt;(Api.PATH, \"\u6807\u7b7eA\"){ // \u4f7f\u7528Any::class.java\u4f5c\u4e3a\u952e\u540d\n // tag(\"\u6807\u7b7eA\") \u7b49\u6548\u4e0a\u4e00\u884c\u7684\u53c2\u6570 \"\u6807\u7b7eA\"\n setExtra(\"tagName\", \"\u6807\u7b7eB\") // \u5199\u5165\u989d\u5916\u6570\u636e\n }.await()\n}\n</code></pre>"},{"location":"tag.html#2","title":"2. \u62e6\u622a\u5668\u4e2d\u8bfb\u53d6\u6807\u7b7e","text":"<pre><code>class MyInterceptor : Interceptor {\n override fun intercept(chain: Chain): Response {\n val request = chain.request()\n request.tag()?.let {\n // \u8bfb\u53d6\u6807\u7b7e\n }\n request.extra(\"tagName\")?.let {\n // \u8bfb\u53d6\u989d\u5916\u6570\u636e\n }\n return chain.proceed(request)\n }\n}\n</code></pre>"},{"location":"tag.html#3","title":"3. \u8f6c\u6362\u5668\u4e2d\u8bfb\u53d6\u6807\u7b7e","text":"<pre><code>class MyConvert : NetConvert {\n\n override fun &lt;R&gt; onConvert(succeed: Type, response: Response ): R? {\n response.request.tag()?.let{\n // \u8bfb\u53d6\u6807\u7b7e\n }\n }\n}\n</code></pre> <p>\u901a\u8fc7<code>Request</code>\u53ef\u4ee5\u8bfb\u5199\u6570\u636e</p> \u65b9\u6cd5 \u63cf\u8ff0 setExtra \u5199\u5165\u989d\u5916\u6570\u636e extra \u8bfb\u53d6\u989d\u5916\u6570\u636e extras \u5168\u90e8\u989d\u5916\u6570\u636e tag \u8bfb\u53d6/\u5199\u5165\u6807\u7b7e tagOf \u8bfb\u53d6/\u5199\u5165\u6807\u7b7e, \u4e3a<code>tag()</code>\u7684\u6cdb\u578b\u66ff\u4ee3 tags \u5168\u90e8\u6807\u7b7e"},{"location":"tag.html#_2","title":"\u591a\u4e2a\u6807\u7b7e","text":"<pre><code>scopeNetLife {\n Get&lt;String&gt;(Api.PATH){\n setExtra(\"person\", Person()) // \u4f7f\u7528Request.extra(\"person\")\u8bfb\u53d6\n tag(User()) // \u7b49\u540c\u4e8etag(Any::class.java, User()), \u4f7f\u7528Request.tag()\u8bfb\u53d6\n tag(User::class.java, User()) // \u4f7f\u7528Request.tag(User::class.java)\u8bfb\u53d6\n }.await()\n}\n</code></pre> <p>\u5f97\u5230\u6807\u7b7e</p> <pre><code>class MyInterceptor : Interceptor {\n override fun intercept(chain: Chain): Response {\n val request = chain.request()\n request.extra(\"person\")?.let {\n // it\u65e2\u4e3aPerson\u5bf9\u8c61\n }\n request.tagOf&lt;User&gt;() // \u7ed3\u679c\u4e3aUser()\n request.tag() // \u7ed3\u679c\u4e3aUser()\n return chain.proceed(request)\n }\n}\n</code></pre>"},{"location":"thread.html","title":"\u5207\u6362\u7ebf\u7a0b","text":"<p>\u6240\u6709<code>scopeXX</code>\u4f5c\u7528\u57df\u5185\u4e3a\u4e3b\u7ebf\u7a0b, \u53ef\u76f4\u63a5\u66f4\u65b0\u89c6\u56fe</p> <p>\u8c03\u5ea6\u5668</p> <p>\u534f\u7a0b\u4e2d\u7684\u8c03\u5ea6\u5668\u5b9e\u9645\u4e0a\u4e3a\u7ebf\u7a0b\u6c60, \u901a\u8fc7\u5207\u6362\u8c03\u5ea6\u5668\u53ef\u4ee5\u5207\u6362\u5230\u4e0d\u540c\u7ebf\u7a0b\u4e0a</p>"},{"location":"thread.html#_1","title":"\u5207\u6362\u8c03\u5ea6\u5668","text":"<pre><code>scopeNetLife(dispatcher = Dispatchers.IO) {\n tv.text = Get&lt;String&gt;(Api.PATH).await()\n}\n</code></pre> <p>\u7981\u6b62\u7684\u8c03\u5ea6\u5668</p> <p><code>Dispatchers.Main.immediate</code>\u4f1a\u7acb\u5373\u540c\u6b65\u6267\u884c, \u5bfc\u81f4<code>catch/finally</code>\u51fd\u6570\u65e0\u6548</p>"},{"location":"thread.html#_2","title":"\u4f5c\u7528\u57df\u5185\u90e8\u5207\u6362","text":"<p>\u6709\u65f6\u9700\u5f00\u542f\u65b0\u7684\u7ebf\u7a0b\u5904\u7406\u8017\u65f6\u4efb\u52a1</p> \u4e3b\u7ebf\u7a0b\u4f5c\u7528\u57df\u5185\u5207\u6362\u5b50\u7ebf\u7a0b\u5b50\u7ebf\u7a0b\u4f5c\u7528\u57df\u5185\u5207\u6362\u4e3b\u7ebf\u7a0b <pre><code>scopeNetLife {\n tv.text = withIO {\n // \u5047\u8bbe\u6b64\u5904\u662f\u4e00\u4e2aIO\u8bfb\u5199\u963b\u585e\u4efb\u52a1\n return \"\u8bfb\u51fa\u7ed3\u679c\"\n }\n}\n</code></pre> <pre><code>scopeNetLife(dispatcher = Dispatchers.IO) {\n tv.text = withMain {\n // \u5047\u8bbe\u6b64\u5904\u662f\u4e00\u4e2aIO\u8bfb\u5199\u963b\u585e\u4efb\u52a1\n return \"\u8bfb\u51fa\u7ed3\u679c\"\n }\n}\n</code></pre> \u51fd\u6570 \u63cf\u8ff0 withMain \u5207\u6362\u5230\u4e3b\u7ebf\u7a0b withIO \u5207\u6362\u5230IO\u7ebf\u7a0b withDefault \u5207\u6362\u5230\u5b50\u7ebf\u7a0b withUnconfined \u5207\u6362\u5230\u65e0\u9650\u5236\u8c03\u5ea6\u5668, \u5176\u53d6\u51b3\u4e8e\u4e0a\u4e00\u4e2a\u6267\u884c\u7684\u7ebf\u7a0b\u5207\u6362 launch \u65e0\u8fd4\u56de\u503c\u7684\u6302\u8d77\u51fd\u6570, \u53ef\u6307\u5b9a\u7ebf\u7a0b async \u6709\u8fd4\u56de\u503c\u7684\u6302\u8d77\u51fd\u6570, \u901a\u8fc7<code>await()</code>\u8fd4\u56de\u503c, \u53ef\u6307\u5b9a\u7ebf\u7a0b runMain \u5207\u6362\u5230\u4e3b\u7ebf\u7a0b, \u8be5\u51fd\u6570\u4e0d\u5c5e\u4e8e\u534f\u7a0b\u53ef\u4ee5\u5728\u4efb\u4f55\u5730\u65b9\u8c03\u7528 <ul> <li><code>withXX()</code> \u534f\u7a0b\u963b\u585e\u6302\u8d77</li> <li><code>launch()/async()</code> \u975e\u963b\u585e\u6267\u884c, \u4e24\u8005\u533a\u522b\u662f\u6709\u65e0\u8fd4\u56de\u503c</li> </ul>"},{"location":"timing.html","title":"\u9650\u65f6/\u5b9a\u65f6\u8bf7\u6c42","text":"<p>\u4ee5\u4e0b\u4e3a\u63d0\u4f9b\u5b9e\u73b0\u5b9a\u65f6/\u9650\u65f6\u8bf7\u6c42\u601d\u8def, \u5e76\u4e0d\u9650\u5b9a\u53ea\u6709\u4ee5\u4e0b\u65b9\u5f0f</p>"},{"location":"timing.html#_1","title":"\u9650\u65f6\u8bf7\u6c42","text":"<p>\u5373\u8d85\u8fc7\u6307\u5b9a\u65f6\u95f4\u540e\u7acb\u5373\u53d6\u6d88\u8bf7\u6c42</p> <pre><code>scopeDialog {\n // \u5f53\u63a5\u53e3\u8bf7\u6c42\u5728100\u6beb\u79d2\u5185\u6ca1\u6709\u5b8c\u6210\u4f1a\u629b\u51fa\u5f02\u5e38TimeoutCancellationException\n withTimeout(100) {\n Get&lt;String&gt;(Api.PATH).await()\n }\n}.catch {\n Log.e(\"\u65e5\u5fd7\", \"\u8bf7\u6c42\u9519\u8bef\", it) // catch\u65e0\u6cd5\u63a5\u6536\u5230CancellationException\u5f02\u5e38\n}.finally {\n Log.e(\"\u65e5\u5fd7\", \"\u8bf7\u6c42\u5b8c\u6210\", it) // TimeoutCancellationException\u5c5e\u4e8eCancellationException\u5b50\u7c7b\u6545\u53ea\u4f1a\u88abfinally\u63a5\u6536\u5230\n if (it is TimeoutCancellationException) {\n toast(\"\u7531\u4e8e\u672a\u5728\u6307\u5b9a\u65f6\u95f4\u5b8c\u6210\u8bf7\u6c42\u5219\u53d6\u6d88\u8bf7\u6c42\")\n }\n}\n</code></pre>"},{"location":"timing.html#_2","title":"\u5b9a\u65f6\u8bf7\u6c42","text":"<p>\u6307\u5b9a\u8bf7\u6c4210\u6b21</p> <pre><code>scopeNetLife {\n // \u6bcf\u79d2\u8bf7\u6c42\u4e00\u6b21, \u603b\u5171\u6267\u884c10\u6b21\n repeat(20) {\n delay(1000)\n val data = Get&lt;String&gt;(Api.PATH).await()\n if(it = 10) {\n return@repeat\n }\n }\n}\n</code></pre> <p>\u6bcf\u79d2\u65e0\u9650\u5faa\u73af\u8bf7\u6c42, \u6839\u636e\u67d0\u4e2a\u6761\u4ef6<code>break</code>\u9000\u51fa</p> <pre><code>scopeNetLife {\n while (true) {\n delay(1.toDuration(DurationUnit.SECONDS))\n val data = Get&lt;Config&gt;(Api.PATH).await()\n if(data.type = 3) {\n break\n }\n }\n}\n</code></pre>"},{"location":"track.html","title":"\u5f02\u5e38\u8ffd\u8e2a","text":"<p>Net\u4e2d\u7f51\u7edc\u8bf7\u6c42\u5f02\u5e38\u4f1aLogCat\u8f93\u51fa, \u9664\u975e\u5f00\u53d1\u8005\u4fee\u6539\u5168\u5c40\u9519\u8bef\u5904\u7406</p> <p>\u6f14\u793a\u8bbf\u95ee\u4e00\u4e2a\u4e0d\u5b58\u5728\u7684\u8bf7\u6c42\u8def\u5f84 <pre><code>scopeNetLife {\n tv.text = Get&lt;String&gt;(\"https://error.com/net/\").await()\n}\n</code></pre></p> <p>LogCat\u53ef\u4ee5\u770b\u5230\u5f02\u5e38\u5806\u6808\u4fe1\u606f, \u5305\u542b\u5177\u4f53Url\u548c\u4ee3\u7801\u4f4d\u7f6e</p> <p></p>"},{"location":"track.html#_1","title":"\u5173\u95ed\u65e5\u5fd7","text":"<p>\u53ef\u4ee5\u5173\u95ed\u65e5\u5fd7\u6253\u5370</p> <pre><code>NetConfig.initialize(Api.HOST, this) {\n setDebug(false) // \u5173\u95ed\u65e5\u5fd7, \u4e00\u822c\u4f7f\u7528 BuildConfig.DEBUG\n}\n</code></pre>"},{"location":"updates.html","title":"\u66f4\u65b0\u65e5\u5fd7","text":""},{"location":"updates.html#370","title":"3.7.0","text":"<ul> <li>fix: #233 \u652f\u6301\u6700\u65b0\u7684lifecycle-runtime-ktx</li> <li>perf: \u4f18\u5316 runMain \u65b9\u6cd5\u7684 Handler \u4f7f\u7528\u5355\u4f8b</li> </ul>"},{"location":"updates.html#364","title":"3.6.4","text":"<ul> <li>feat: \u4f18\u5316\u8f6c\u6362\u5668ConvertException\u9519\u8bef\u4fe1\u606f</li> </ul>"},{"location":"updates.html#363","title":"3.6.3","text":"<ul> <li>fix: #205 \u5220\u9664MultiPart\u4e0a\u4f20RequestBody\u9ed8\u8ba4\u6dfb\u52a0filename</li> </ul>"},{"location":"updates.html#362","title":"3.6.2","text":"<ul> <li>fix: #203 \u9002\u914dAGPv8\u7684\u4ee3\u7801\u6df7\u6dc6Gson\u65e0\u6cd5\u83b7\u53d6\u6cdb\u578b\u95ee\u9898</li> </ul>"},{"location":"updates.html#361","title":"3.6.1","text":"<ul> <li>fix: #197 \u4fee\u590dscopeDialog\u7684\u53ef\u53d6\u6d88\u5bf9\u8bdd\u6846\u9ed8\u8ba4\u503c</li> </ul>"},{"location":"updates.html#360","title":"3.6.0","text":"<ul> <li>pref: Optimize code</li> <li>feat: contentLength\u672a\u77e5\u7684\u4e0a\u4f20\u5bf9\u8c61finish\u4e5f\u6709\u6548</li> <li>pref: RunningCalls\u904d\u5386\u4f18\u5316</li> <li>pref: \u8003\u8651\u5230Uri.toRequestBody\u8bfb\u53d6\u4e0d\u5230\u6587\u4ef6\u6216\u957f\u5ea6</li> <li>refactor: \u5220\u9664\u5e9f\u5f03\u51fd\u6570</li> <li>refactor: \u4e0b\u8f7d\u4e34\u65f6\u6587\u4ef6\u540d\u540e\u7f00\u6539\u6210.downloading</li> <li>refactor: \u5220\u9664param(RequestBody, Header)</li> <li>refactor: LogRecordInterceptor.kt</li> <li>refactor: \u5220\u9664\u6709\u95ee\u9898\u7684\u53d6\u6d88\u8bf7\u6c42\u51fd\u6570</li> <li>refactor: peekBytes\u7684\u9ed8\u8ba4\u8bfb\u53d6\u5927\u5c0f\u7edf\u4e00\u4e3a1MB</li> <li>fix: \u4fee\u590d\u83b7\u53d6\u8bf7\u6c42\u5bf9\u8c61\u83b7\u53d6ID/Group\u9519\u8bef</li> <li>fix: \u5168\u5c40\u53d6\u6d88\u8bf7\u6c42\u65f6\u53d1\u751fConvertException\u9519\u8bef\u63d0\u793a</li> <li>fix: #187 \u4e0a\u4f20\u8fdb\u5ea6\u76d1\u542cfinish\u5b57\u6bb5\u65e0\u6548</li> </ul>"},{"location":"updates.html#359","title":"3.5.9","text":"<ul> <li>fix: \u4fee\u590dJava\u57fa\u7840\u7c7b\u578b\u6cdb\u578b\u89e3\u6790</li> </ul>"},{"location":"updates.html#358","title":"3.5.8","text":"<ul> <li>fix: \u5220\u9664\u6743\u9650 ACCESS_NETWORK_STATE, \u89e3\u51b3\u4e2a\u522b\u673a\u578b\u91cd\u590d\u7533\u8bf7\u95ee\u9898</li> <li>upgrade: BRV 1.4.0</li> </ul>"},{"location":"updates.html#357","title":"3.5.7","text":"<ul> <li>fix: #165 \u6cdb\u578b\u64e6\u9664</li> </ul>"},{"location":"updates.html#356","title":"3.5.6","text":"<ul> <li>feat: \u65b0\u589e BaseRequest.execute \u975e\u5185\u8054\u51fd\u6570\u91cd\u8f7d</li> <li>feat: Net.kt\u652f\u6301Java\u9759\u6001\u8c03\u7528</li> <li>refactor: LogRecordInterceptor @JvmOverloads</li> <li>fix: Interval.onlyResumed \u7ed3\u675f\u8f6e\u8be2</li> <li>pref: \u5220\u9664\u8f6c\u6362\u5668\u83b7\u53d6\u7684\u53cd\u5c04\u8c03\u7528</li> </ul>"},{"location":"updates.html#355","title":"3.5.5","text":"<ul> <li>fix: #157 \u65e5\u5fd7\u62e6\u622a\u5668\u5931\u6548</li> </ul>"},{"location":"updates.html#354","title":"3.5.4","text":"<ul> <li>refactor: peekString rename to peekBytes, remove logString</li> <li>fix: \u53ef\u80fd\u5b58\u5728\u7684\u5185\u5b58\u6cc4\u6f0f</li> </ul>"},{"location":"updates.html#353","title":"3.5.3","text":"<ul> <li>feat: \u9ed8\u8ba4\u4f7f\u7528NetDialogFactory\u7684setCancelable\u914d\u7f6e</li> <li>fix: #150 scopeDialog\u9884\u89c8\u6a21\u5f0f</li> </ul>"},{"location":"updates.html#352","title":"3.5.2","text":"<ul> <li>fix: #135 Content-MD5\u672a\u4f7f\u7528Base64\u89e3\u7801</li> <li>feat: \u65b0\u589e BaseRequest.headers</li> </ul>"},{"location":"updates.html#351","title":"3.5.1","text":"<ul> <li>feat: \u65b0\u589eparam\u65b9\u6cd5\u53c2\u6570Uri</li> <li>feat: \u65b0\u589eaddQuery\u65b9\u6cd5</li> <li>pref: \u4e0d\u6df7\u6dc6exception\u5305</li> <li>fix: #129 \u8bf7\u6c42URL\u4e0d\u540c\u5bfc\u81f4setCacheKey\u65e0\u6548</li> </ul>"},{"location":"updates.html#350","title":"3.5.0","text":"<ul> <li>refactor: \u5220\u9664\u6743\u9650REQUEST_INSTALL_PACKAGES(\u8c37\u6b4c\u5546\u5e97\u6743\u9650\u8981\u6c42)</li> <li>refactor: \u5220\u9664File.install</li> <li>pref: \u6539\u4e3a\u4f7f\u7528AppStartup\u9ed8\u8ba4\u521d\u59cb\u5316</li> </ul>"},{"location":"updates.html#3414","title":"3.4.14","text":"<ul> <li>fix: Fragment\u672a\u521d\u59cb\u5316View\u6267\u884cscopeNetLife\u5bfc\u81f4\u7a7a\u6307\u9488</li> </ul>"},{"location":"updates.html#3413","title":"3.4.13","text":"<ul> <li>fix: #110 \u7f13\u5b58\u6a21\u5f0f\u4e0bRequest\u4fe1\u606f\u4e22\u5931</li> </ul>"},{"location":"updates.html#3412","title":"3.4.12","text":"<ul> <li>fix: FlowUtils.kt #102</li> </ul>"},{"location":"updates.html#3411","title":"3.4.11","text":"<ul> <li>fix: \u7f3a\u5931trace\u8bf7\u6c42\u65b9\u5f0f #99</li> </ul>"},{"location":"updates.html#3410","title":"3.4.10","text":"<ul> <li>fix: #91 \u4fee\u590dViewPager2\u7684\u89c6\u56fe\u751f\u547d\u5468\u671f\u5bfc\u81f4\u7f51\u7edc\u8bf7\u6c42\u88ab\u53d6\u6d88</li> <li>fix: LogCat\u9519\u8bef\u53d1\u751f\u4f4d\u7f6e\u9ad8\u4eae</li> <li>feat: brv 1.3.76</li> <li>pref: DialogCoroutineScope</li> </ul>"},{"location":"updates.html#348","title":"3.4.8","text":"<ul> <li>fix: \u4e0d\u63d0\u4ea4null\u8bf7\u6c42\u53c2\u6570</li> </ul>"},{"location":"updates.html#347","title":"3.4.7","text":"<ul> <li>\u5347\u7ea7\u4f9d\u8d56</li> <li>\u652f\u6301\u534f\u7a0b1.6.0</li> <li>optimize Interval</li> <li>EditText.debounce\u4e8b\u4ef6\u7c7b\u578b\u6539\u4e3aEditable</li> </ul>"},{"location":"updates.html#346","title":"3.4.6","text":"<ul> <li>\u65b0\u589e\u5f3a\u5236\u7f13\u5b58\u6709\u6548\u671f</li> </ul>"},{"location":"updates.html#345","title":"3.4.5","text":"<ul> <li>Fixed #88</li> <li>Interval.life(Fragment)\u6539\u4e3aonDestroyView\u65f6\u9500\u6bc1</li> </ul>"},{"location":"updates.html#344","title":"3.4.4","text":"<ul> <li>\u65b0\u589eCookie\u7ba1\u7406</li> </ul>"},{"location":"updates.html#343","title":"3.4.3","text":"<ul> <li>\u4fee\u590dgzip\u5bfc\u81f4\u7684\u5f3a\u5236\u7f13\u5b58\u8bfb\u53d6\u5931\u8d25</li> <li>\u4fee\u590dNoCacheException\u65e0\u6cd5\u6355\u83b7</li> <li>\u54cd\u5e94\u53ef\u4ee5\u5224\u65ad\u662f\u5426\u6765\u81ea\u4e8e\u7f13\u5b58</li> <li>\u4f18\u5316\u7f13\u5b58\u76f8\u5173\u4ee3\u7801</li> </ul>"},{"location":"updates.html#342","title":"3.4.2","text":"<ul> <li>\u4fee\u590dHttp\u7f13\u5b58\u534f\u8bae\u65e0\u6548</li> <li>\u65e5\u5fd7\u62e6\u622a\u5668\u9519\u8bef\u4fe1\u606f\u7b80\u7565</li> </ul>"},{"location":"updates.html#341","title":"3.4.1","text":"<ul> <li>\u7981\u7528\u5931\u8d25\u7f13\u5b58</li> </ul>"},{"location":"updates.html#340","title":"3.4.0","text":"<ul> <li>\u65b0\u589e\u5f3a\u5236\u7f13\u5b58\u6a21\u5f0f</li> <li>\u65b0\u589e\u9884\u89c8\u6a21\u5f0f(\u53ef\u5b9e\u73b0\u7f13\u5b58+\u7f51\u7edc)</li> </ul>"},{"location":"updates.html#331","title":"3.3.1","text":"<ul> <li>\u5e9f\u5f03\u90e8\u5206\u65e5\u5fd7\u76f8\u5173\u51fd\u6570</li> <li>\u65b0\u589eNet.debug\u65e5\u5fd7\u8f93\u51fa\u51fd\u6570</li> <li>\u4fee\u590dQuery\u7f16\u7801\u95ee\u9898</li> </ul>"},{"location":"updates.html#330","title":"3.3.0","text":"<ul> <li>\u5220\u9664Callback/onResult(\u7834\u574f\u6027\u8fc1\u79fb)</li> <li>\u5220\u9664requestById/requestByGroup(\u7834\u574f\u6027\u8fc1\u79fb)</li> <li>Add View.scopeNetLife</li> <li>\u7f51\u7edc\u8bf7\u6c42\u5f02\u5e38\u4f4d\u7f6e\u8ffd\u8e2a</li> </ul>"},{"location":"updates.html#322","title":"3.2.2","text":"<ul> <li>Fixed #77</li> <li>\u4fee\u590dgzip\u542f\u7528\u60c5\u51b5\u4e0b\u8f7d\u8fdb\u5ea6\u59cb\u7ec8\u4e3a0</li> <li><code>Progress.finish()</code>\u65b9\u6cd5\u6539\u4e3a\u5c5e\u6027</li> </ul>"},{"location":"updates.html#321","title":"3.2.1","text":"<ul> <li>Fixed #76</li> <li><code>RequestBody?.peekString()</code>\u51fd\u6570\u63a5\u53d7\u8005\u6539\u4e3a\u975e\u53ef\u7a7a\u7c7b\u578b</li> </ul>"},{"location":"updates.html#320","title":"3.2.0","text":"<ul> <li>\u66f4\u6539tag\u76f8\u5173\u51fd\u6570</li> <li>\u66f4\u6539<code>NetConfig.app</code>\u7c7b\u578b\u6539\u4e3aContext</li> <li>\u5220\u9664\u654f\u611f\u6743\u9650(\u5916\u90e8\u5b58\u50a8\u8bfb\u5199)</li> <li>\u5220\u9664\u5e9f\u5f03\u51fd\u6570/\u63d0\u9ad8\u51fd\u6570\u5e9f\u5f03\u7b49\u7ea7</li> <li>\u5e9f\u5f03<code>NetConfig.init</code></li> <li>\u5220\u9664fastest\u51fd\u6570\u63a5\u53d7\u8005</li> <li>\u5220\u9664logRecord\u5c5e\u6027</li> <li>\u4f18\u5316\u57df\u540d\u89e3\u6790\u9519\u8bef\u5f02\u5e38\u4fe1\u606f</li> <li>\u65b0\u589e\u65e0\u7f51\u7edc\u4e0d\u53ef\u7528\u5f02\u5e38<code>NetworkingException</code></li> <li>\u65b0\u589e\u8f93\u51faMultiPart\u53c2\u6570\u65e5\u5fd7</li> <li>\u66f4\u6539RetryInterceptor/LogRecordInterceptor\u5c5e\u6027\u8bbf\u95ee\u6743\u9650</li> </ul>"},{"location":"updates.html#312","title":"3.1.2","text":"<ul> <li>\u5347\u7ea7BRV\u81f31.3.51, \u5176\u5185\u90e8\u5347\u7ea7SmartRefreshLayout\u81f32.0.5. SmartRefreshLayout\u76f8\u5173\u4f9d\u8d56\u9700\u8981\u8fc1\u79fb</li> <li>Interval\u6dfb\u52a0<code>onlyResumed</code>\u51fd\u6570</li> <li>Interval\u4fee\u6539<code>life</code>\u51fd\u6570\u53c2\u6570\u4e3aFragmentActivity\u60c5\u51b5\u4e0b\u7684\u81ea\u52a8\u53d6\u6d88\u8f6e\u8be2\u5668\u7684\u751f\u547d\u5468\u671f</li> </ul>"},{"location":"updates.html#311","title":"3.1.1","text":"<p>\u5185\u5d4c\u6df7\u6dc6\u89c4\u5219, \u4e0d\u9700\u8981\u624b\u52a8\u6dfb\u52a0</p>"},{"location":"updates.html#310","title":"3.1.0","text":"<ul> <li>\u4fee\u590d\u90e8\u5206\u5b50\u7ebf\u7a0b\u5f00\u542f\u4f5c\u7528\u57df\u5d29\u6e83</li> <li>\u7f51\u7edc\u5f02\u5e38\u5806\u6808\u4f7f\u7528 NetConfig.TAG \u4f5c\u4e3a\u6807\u7b7e, \u4f7f\u7528debug\u65e5\u5fd7\u7c7b\u578b\u8f93\u51fa</li> <li>\u9ed8\u8ba4\u8f6c\u6362\u5668\u73b0\u5728\u8981\u6c42HTTP\u72b6\u6001\u7801\u4e3a\u6210\u529f\u624d\u8fd4\u56de\u6570\u636e(\u6cdb\u578bResponse\u8bf7\u6c42\u5b8c\u6210\u90fd\u8fd4\u56de)</li> <li>\u5f00\u542f\u7f16\u8bd1\u5668\u5f3a\u5236\u66ff\u6362\u5e9f\u5f03\u51fd\u6570(\u53ef\u67e5\u770b\u51fd\u6570\u6ce8\u91ca\u66ff\u6362\u89c4\u5219)</li> <li>\u7981\u6b62\u66b4\u9732\u5197\u4f59\u51fd\u6570</li> </ul>"},{"location":"updates.html#3027","title":"3.0.27","text":"<ul> <li>setDownloadDir\u51fd\u6570\u540c\u65f6\u652f\u6301\u5b8c\u6574\u8def\u5f84(\u5373\u5305\u542b\u6587\u4ef6\u540d\u79f0)\u548c\u4e0b\u8f7d\u76ee\u5f55</li> </ul>"},{"location":"updates.html#3026","title":"3.0.26","text":"<ul> <li>\u4f18\u5316\u8fd4\u56deByteArray\u7c7b\u578b\u6027\u80fd</li> <li>setQuery\u51fd\u6570\u652f\u6301Number/Boolean\u7c7b\u578b</li> <li>\u65b0\u589e\u4e00\u4e2a\u9519\u8bef\u63d0\u793a HttpFailureException</li> </ul>"},{"location":"updates.html#3025","title":"3.0.25","text":"<ul> <li>\u8f6e\u8be2\u5668\u652f\u6301ViewModel\u53d6\u6d88</li> <li>\u4fee\u590d\u65e0\u6cd5\u8fd4\u56deByteArray\u7c7b\u578b\u95ee\u9898</li> <li>\u95f4\u63a5\u4f9d\u8d56 update brv 1.3.37</li> <li>\u66f4\u65b0\u51fd\u6570\u6ce8\u91ca</li> </ul>"},{"location":"updates.html#3024","title":"3.0.24","text":"<p>\u4fee\u590d\u4e0a\u4f20\u6587\u4ef6\u5305\u542b\u53c2\u6570\u65f6, \u7f16\u7801\u95ee\u9898\u5bfc\u81f4\u7684\u53c2\u6570\u9519\u8bef</p>"},{"location":"updates.html#3023","title":"3.0.23","text":"<ul> <li>\u4fee\u590d\u8f6e\u8be2\u5668\u91cd\u590dstart\u65e0\u6548\u95ee\u9898</li> <li>Interval\u5176\u4ed6\u4f18\u5316</li> </ul>"},{"location":"updates.html#3021","title":"3.0.21","text":"<ul> <li>Interval\u6dfb\u52a0cancel\u51fd\u6570\u7528\u4e8e\u53d6\u6d88\u8ba1\u65f6\u5668, \u53d6\u6d88\u5b8c\u6210\u4e0d\u4f1a\u8c03\u7528finish</li> </ul>"},{"location":"updates.html#3020","title":"3.0.20","text":"<ul> <li>\u65b0\u589e<code>HttpFailureException</code>\u53ca\u5176\u5b50\u7c7b\u8868\u793a\u8bf7\u6c42\u5931\u8d25\u5f02\u5e38</li> <li>\u65b0\u589e<code>HttpResponseException</code>\u53ca\u5176\u5b50\u7c7b\u8868\u793a\u8bf7\u6c42\u6210\u529f\u540e\u53d1\u751f\u7684\u5f02\u5e38</li> <li>\u66f4\u65b0\u4f9d\u8d56\u5e93BRV\u81f31.3.31</li> </ul>"},{"location":"updates.html#3019","title":"3.0.19","text":"<ul> <li>\u66f4\u65b0\u4f9d\u8d56\u5e93BRV\u81f31.3.30</li> </ul>"},{"location":"updates.html#3018","title":"3.0.18","text":"<ul> <li>\u4fee\u590dResponse\u6d41\u5f02\u5e38\u5173\u95ed\u95ee\u9898</li> </ul>"},{"location":"updates.html#3017","title":"3.0.17","text":"<ul> <li>\u4fee\u590dProfiler\u5bfc\u81f4\u7684\u8bf7\u6c42\u95ee\u9898</li> </ul>"},{"location":"updates.html#3016","title":"3.0.16","text":"<ul> <li>\u65e5\u5fd7\u8bb0\u5f55\u5668\u4e2d\u8bf7\u6c42\u53c2\u6570\u9ed8\u8ba4\u4f7f\u7528URLDecoder\u89e3\u7801</li> </ul>"},{"location":"updates.html#3015","title":"3.0.15","text":"<ul> <li>\u4fee\u590dFileProvider\u51b2\u7a81</li> <li>\u4e0a\u4f20\u6587\u4ef6\u65f6\u9ed8\u8ba4\u751f\u6210filename(\u5f53\u4f60\u672a\u6307\u5b9a\u6587\u4ef6\u540d\u60c5\u51b5\u4e0b)</li> <li>NetCallback\u7f51\u7edc\u8bf7\u6c42\u88ab\u53d6\u6d88\u4e0d\u4f1a\u56de\u8c03onError</li> <li>\u4e3aNetCallback\u6dfb\u52a0Request\u5bf9\u8c61</li> <li>\u5220\u9664\u5185\u90e8Tooltip\u4f9d\u8d56</li> </ul>"},{"location":"updates.html#3014","title":"3.0.14","text":"<ul> <li>\u4fee\u590dKType\u7c7b\u578b\u95ee\u9898</li> <li>\u652f\u6301<code>File.install</code>\u51fd\u6570\u5b89\u88c5\u5e94\u7528</li> </ul>"},{"location":"updates.html#3013","title":"3.0.13","text":"<ul> <li>\u4f18\u5316\u6807\u7b7e\u76f8\u5173\u51fd\u6570. \u6574\u4e2a\u7f51\u7edc\u751f\u547d\u5468\u671f\u53ef\u4ee5\u5b8c\u7f8e\u4f20\u9012\u53c2\u6570</li> <li>NetCallback\u5177\u5907\u8ddf\u968f\u751f\u547d\u5468\u671f\u81ea\u52a8\u53d6\u6d88\u7f51\u7edc\u8bf7\u6c42</li> <li>\u6269\u5c55NetCallback\u6765\u6dfb\u52a0DialogCallback/StateCallback/PageCallback</li> <li>\u5e9f\u5f03\u90e8\u5206\u51fd\u6570, \u4f8b\u5982onDialog\u88ab\u5e9f\u5f03, \u73b0\u5728\u7531<code>NetConfig.dialogFactory</code>\u6784\u5efa\u5168\u5c40\u52a0\u8f7d\u5bf9\u8bdd\u6846</li> <li>initNet\u73b0\u5728\u5e9f\u5f03, \u7531<code>NetConfig.initialize</code>\u53d6\u4ee3. \u6240\u6709\u914d\u7f6e\u4fe1\u606f\u7531NetConfig\u627f\u8f7d</li> <li>RequestParamsException\u6dfb\u52a0\u9519\u8bef\u7801\u4fe1\u606f</li> </ul>"},{"location":"updates.html#3012","title":"3.0.12","text":"<ul> <li>\u4fee\u590d\u8f6c\u6362\u5668\u629b\u51fa\u7684\u5f02\u5e38\u5168\u90e8\u88ab<code>ConvertException</code>\u5305\u88f9\u7684\u95ee\u9898</li> <li>NetException\u5b50\u7c7b\u4e0d\u4f1a\u88abConvertException\u5305\u88f9, \u6240\u4ee5\u8981\u6355\u83b7\u8f6c\u6362\u5668\u4e2d\u7684\u81ea\u5b9a\u4e49\u5f02\u5e38\u8bf7\u5176\u7ee7\u627fNetException</li> </ul>"},{"location":"updates.html#3011","title":"3.0.11","text":"<ul> <li>\u4fee\u590d\u4e34\u65f6\u4e0b\u8f7d\u6587\u4ef6\u9519\u8bef\u95ee\u9898</li> <li>\u4fee\u590dViewModel\u4f5c\u7528\u57df\u590d\u7528\u95ee\u9898</li> </ul>"},{"location":"updates.html#3010","title":"3.0.10","text":"<ul> <li>\u5347\u7ea7Tooltip\u4f9d\u8d56, \u89e3\u51b3\u4f7f\u7528Tooltip_V1.1.1\u4f9d\u8d56\u65f6Net\u5b58\u5728\u5d29\u6e83\u95ee\u9898</li> </ul>"},{"location":"updates.html#309","title":"3.0.9","text":"<ul> <li>\u4f18\u5316\u8f6c\u6362\u5668\u5f02\u5e38\u5904\u7406</li> <li>\u8f6c\u6362\u5668\u652f\u6301\u975e\u56fa\u5b9a\u683c\u5f0fJson\u89e3\u6790</li> </ul>"},{"location":"updates.html#307","title":"3.0.7","text":"<ul> <li>\u4fee\u590d\u672a\u77e5\u7684TypeToken\u8bbf\u95ee\u6743\u9650\u95ee\u9898</li> </ul>"},{"location":"updates.html#306","title":"3.0.6","text":"<ul> <li>\u6240\u6709Json\u89e3\u6790\u6846\u67b6\u90fd\u53ef\u4ee5\u89e3\u6790<code>List&lt;UserModel&gt;</code>\u7b49\u5d4c\u5957\u6cdb\u578b\u6570\u636e\u7ed3\u6784</li> </ul>"},{"location":"updates.html#305","title":"3.0.5","text":"<ul> <li>\u4fee\u590dPath\u7f16\u7801\u95ee\u9898</li> <li>\u4e0a\u4f20File\u81ea\u52a8\u8bc6\u522bMediaType</li> </ul>"},{"location":"updates.html#304","title":"3.0.4","text":"<ul> <li>\u6dfb\u52a0MediaConst\u8868\u793a\u5e38\u7528MediaType</li> <li>OkHttpBuilder\u6dfb\u52a0<code>setErrorHandler</code>\u53d6\u4ee3onError/onStateError: \u5168\u5c40\u9519\u8bef\u5904\u7406</li> <li>\u63d0\u4f9b\u517c\u5bb9Android4.4(API level 19)\u7684\u7248\u672c: Net-okhttp3</li> </ul>"},{"location":"updates.html#303","title":"3.0.3","text":"<ul> <li>\u6dfb\u52a0<code>onResult</code>\u51fd\u6570\u6765\u6267\u884c\u961f\u5217\u8bf7\u6c42: \u961f\u5217\u8bf7\u6c42</li> <li>\u6dfb\u52a0<code>toResult</code>\u51fd\u6570\u6765\u6267\u884c\u540c\u6b65\u8bf7\u6c42: \u540c\u6b65\u8bf7\u6c42</li> <li>\u8bf7\u6c42\u4f53\u65e5\u5fd7\u652f\u6301JSON/\u6587\u672c\u7c7b\u578b</li> <li>LogRecordInterceptor\u66b4\u9732<code>requestString/responseString</code>\u5b9e\u73b0\u51fd\u6570\u7528\u4e8e\u7ee7\u627f\u5b9e\u73b0\u81ea\u5b9a\u4e49\u9700\u6c42</li> </ul>"},{"location":"updates.html#302","title":"3.0.2","text":"<p>\u4fee\u590d\u591a\u6e20\u9053\u65e0\u6cd5\u5b89\u88c5\u95ee\u9898</p>"},{"location":"updates.html#301","title":"3.0.1","text":"<ul> <li>\u8f6c\u6362\u5668\u652f\u6301KType, \u89e3\u51b3JAVA\u6cdb\u578b\u64e6\u9664\u95ee\u9898</li> <li>\u652f\u6301kotlin-serialization\u8f6c\u6362\u5668</li> <li>\u4fee\u590dJSON\u8bf7\u6c42\u53c2\u6570\u7c7b\u578b\u95ee\u9898</li> </ul>"},{"location":"updates.html#30","title":"3.0","text":"<ul> <li>\u91cd\u6784\u4ee3\u7801, \u63d0\u5347\u7a33\u5b9a\u6027\u548c\u5b89\u5168\u6027.</li> <li>\u652f\u6301OkHttp\u7684\u6240\u6709\u51fd\u6570/\u7ec4\u4ef6, \u53ef\u72ec\u7acb\u5347\u7ea7OkHttp\u7248\u672c</li> <li>\u66f4\u52a0\u5f3a\u5927\u7684\u4e0b\u8f7d\u529f\u80fd</li> <li>\u6240\u6709IO\u8bfb\u5199\u4f7f\u7528OKIO</li> <li>\u66f4\u52a0\u4f18\u96c5\u7684\u51fd\u6570\u8bbe\u8ba1</li> </ul>"},{"location":"upload-file.html","title":"\u4e0a\u4f20\u6587\u4ef6","text":"<pre><code>scopeNetLife {\n Post&lt;String&gt;(Api.UPLOAD) {\n param(\"fileName\", assetsFile())\n }.await()\n}\n</code></pre> <p>\u4f7f\u7528<code>addUploadListener</code>\u6dfb\u52a0\u4e0a\u4f20\u8fdb\u5ea6\u76d1\u542c\u5668, \u9605\u8bfb\u8fdb\u5ea6\u76d1\u542c\u7ae0\u8282</p>"},{"location":"upload-file.html#_1","title":"\u6307\u5b9a\u7c7b\u578b","text":"<p>\u9ed8\u8ba4\u6839\u636e\u6587\u4ef6\u540e\u7f00\u540d\u751f\u6210<code>MediaType</code>, \u5982\u679c\u60f3\u81ea\u5b9a\u4e49MediaType\u53ef\u4ee5\u76f4\u63a5\u521b\u5efa<code>RequestBody</code></p> <pre><code>scopeNetLife {\n Post&lt;String&gt;(Api.UPLOAD) {\n param(\"file\", assetsFile().toRequestBody(\"image/webp\".toMediaType()))\n }.await()\n}\n</code></pre>"},{"location":"upload-file.html#_2","title":"\u4e0a\u4f20\u7c7b\u578b","text":"<p>\u81ea\u5b9a\u4e49RequestBody\u53ef\u4ee5\u5b9e\u73b0\u4efb\u4f55\u6570\u636e\u7c7b\u578b\u7684\u4e0a\u4f20</p> <pre><code>scopeNetLife {\n Post&lt;String&gt;(Api.UPLOAD) {\n // \u8868\u5355\u4e0a\u4f20\n param(\"file\", Uri)\n param(\"file\", File)\n }.await()\n}\n</code></pre> <p>\u76f4\u63a5\u4e0a\u4f20<code>InputStream</code>\u53ef\u80fd\u5185\u5b58\u6cc4\u9732, \u5efa\u8bae\u4f60\u4fdd\u5b58\u5230\u6587\u4ef6\u540e\u4e0a\u4f20</p> <ol> <li>\u4f7f\u7528\u6587\u4ef6\u6d41\u4e0a\u4f20\u6587\u4ef6</li> </ol>"},{"location":"view-model.html","title":"ViewModel","text":"<p>Net\u652f\u6301\u5728ViewModel\u4e2d\u521b\u5efa\u7f51\u7edc\u8bf7\u6c42/\u5f02\u6b65\u4efb\u52a1</p> <p>\u4e0d\u63a8\u8350</p> <ol> <li>\u7f51\u7edc\u8bf7\u6c42\u4e0d\u4e00\u5b9a\u8981\u5199\u5728ViewModel </li> <li>\u7f51\u7edc\u8bf7\u6c42\u4e0d\u8981\u5199\u63a5\u53e3\u56de\u8c03</li> <li>\u53ef\u4ee5\u5728Activity\u4e2d\u76f4\u63a5\u8fd4\u56de\u8bf7\u6c42\u7ed3\u679c</li> </ol>"},{"location":"view-model.html#_1","title":"\u81ea\u52a8\u751f\u547d\u5468\u671f","text":"<ul> <li>\u793a\u4f8b\u4ee3\u7801</li> </ul> <p>\u4f7f\u7528<code>scopeXXLife()</code>\u521b\u5efa\u4f5c\u7528\u57df, \u5728ViewModel\u88ab\u9500\u6bc1\u65f6\u81ea\u52a8\u53d6\u6d88\u8bf7\u6c42</p> <pre><code>class UserViewModel : ViewModel() {\n\n // \u7528\u6237\u4fe1\u606f\n var userInfo: MutableLiveData&lt;String&gt; = MutableLiveData()\n\n /**\n * \u4f7f\u7528LiveData\u63a5\u53d7\u8bf7\u6c42\u7ed3\u679c, \u5c06\u8be5liveData\u76f4\u63a5\u4f7f\u7528DataBinding\u7ed1\u5b9a\u5230\u9875\u9762\u4e0a, \u4f1a\u5728\u8bf7\u6c42\u6210\u529f\u81ea\u52a8\u66f4\u65b0\u89c6\u56fe\n */\n fun fetchUserInfo() = scopeNetLife {\n userInfo.value = Get&lt;String&gt;(Api.GAME).await()\n }\n\n /**\n * \u5f00\u59cb\u975e\u963b\u585e\u5f02\u6b65\u4efb\u52a1\n * \u8fd4\u56deDeferred, \u8c03\u7528await()\u624d\u4f1a\u8fd4\u56de\u7ed3\u679c\n */\n fun fetchList(scope: CoroutineScope) = scope.Get&lt;String&gt;(Api.TEST)\n\n /**\n * \u5f00\u59cb\u963b\u585e\u5f02\u6b65\u4efb\u52a1\n * \u76f4\u63a5\u8fd4\u56de\u7ed3\u679c\n */\n suspend fun fetchPrecessData() = coroutineScope {\n val response = Get&lt;String&gt;(Api.TEST).await()\n response + \"\u5904\u7406\u6570\u636e\"\n }\n}\n</code></pre>"}]}