{"id":1937,"date":"2023-09-21T10:20:08","date_gmt":"2023-09-21T02:20:08","guid":{"rendered":"https:\/\/badgameshow.com\/fly\/?p=1937"},"modified":"2023-09-21T17:09:19","modified_gmt":"2023-09-21T09:09:19","slug":"%e3%80%90android%e3%80%91grpc-%e5%85%a5%e9%96%80%e6%95%99%e5%ad%b8-%e7%8f%be%e4%bb%a3%e7%9a%84%e8%b7%a8%e8%aa%9e%e8%a8%80%e9%81%a0%e7%a8%8b%e9%81%8e%e7%a8%8b%e5%91%bc%e5%8f%ab%e6%a1%86%e6%9e%b6","status":"publish","type":"post","link":"https:\/\/badgameshow.com\/fly\/%e3%80%90android%e3%80%91grpc-%e5%85%a5%e9%96%80%e6%95%99%e5%ad%b8-%e7%8f%be%e4%bb%a3%e7%9a%84%e8%b7%a8%e8%aa%9e%e8%a8%80%e9%81%a0%e7%a8%8b%e9%81%8e%e7%a8%8b%e5%91%bc%e5%8f%ab%e6%a1%86%e6%9e%b6\/","title":{"rendered":"\u3010Android\u3011gRPC \u5165\u9580\u6559\u5b78 \u73fe\u4ee3\u7684\u8de8\u8a9e\u8a00\u9060\u7a0b\u904e\u7a0b\u547c\u53eb\u6846\u67b6"},"content":{"rendered":"<h1>\u3010Android\u3011gRPC \u5165\u9580\u6559\u5b78 \u73fe\u4ee3\u7684\u8de8\u8a9e\u8a00\u9060\u7a0b\u904e\u7a0b\u547c\u53eb\u6846\u67b6<\/h1>\n<h4>gRPC\uff08Google Remote Procedure Call\uff09\u662f\u4e00\u7a2e\u7531 Google \u958b\u767c\u7684\u9ad8\u6548\u80fd\u3001\u8de8\u8a9e\u8a00\u7684\u9060\u7a0b\u904e\u7a0b\u547c\u53eb\uff08RPC\uff09\u6846\u67b6\u3002\u5b83\u5141\u8a31\u4e0d\u540c\u7684\u61c9\u7528\u7a0b\u5f0f\u548c\u670d\u52d9\u4e4b\u9593\u9032\u884c\u901a\u4fe1\uff0c\u4e26\u80fd\u5920\u5728\u591a\u7a2e\u7de8\u7a0b\u8a9e\u8a00\u4e4b\u9593\u5be6\u73fe\u4e92\u64cd\u4f5c\u6027\u3002<\/h4>\n<hr \/>\n<h4>\u6587\u7ae0\u76ee\u9304<\/h4>\n<ol>\n<li><a href=\"#a\">Protocaol Buffers<\/a><\/li>\n<li><a href=\"#b\">\u56db\u7a2e\u6a21\u5f0f<\/a><\/li>\n<li><a href=\"#c\">NodeJS \u5be6\u73fe Server \u7aef<\/a><\/li>\n<li><a href=\"#d\">NodeJS \u5be6\u73fe Clinet \u7aef<\/a><\/li>\n<li><a href=\"#e\">Android \u5be6\u73fe Client \u7aef<\/a><\/li>\n<li><a href=\"#f\">\u76f8\u95dc\u9023\u7d50<\/a><\/li>\n<\/ol>\n<hr \/>\n<p><a id=\"a\"><\/a><\/p>\n<h4>1.Protocaol Buffers<\/h4>\n<h5>Protocol Buffers\uff0c\u7c21\u7a31ProtoBuf\uff0c\u662f\u4e00\u7a2e\u7528\u65bc\u5e8f\u5217\u5316\u7d50\u69cb\u5316\u6578\u64da\u7684\u4ecb\u9762\u63cf\u8ff0\u8a9e\u8a00\uff08IDL\uff09\u548c\u5e95\u5c64\u6578\u64da\u5e8f\u5217\u5316\u683c\u5f0f\u3002\u5b83\u662f\u7531Google\u958b\u767c\u7684\u958b\u6e90\u6280\u8853\uff0c\u7528\u65bc\u89e3\u6c7a\u4e0d\u540c\u61c9\u7528\u7a0b\u5f0f\u6216\u4e0d\u540c\u7cfb\u7d71\u4e4b\u9593\u7684\u6578\u64da\u901a\u4fe1\u548c\u6301\u4e45\u5316\u5b58\u5132\u7684\u554f\u984c\u3002<\/h5>\n<h5>hello.proto<\/h5>\n<pre><code class=\"language-proto line-numbers\">syntax = \"proto3\";\n\npackage hello;\n\nservice Greeter {\n  \/\/ \u55ae\u5411\u547c\u53eb (Unary RPC)\n  rpc sayHelloUnary (HelloRequest) returns (HelloReply) {}\n\n  \/\/ \u4f3a\u670d\u5668\u6d41 (Server Streaming RPC)\n  rpc sayHelloServerStream (HelloRequest) returns (stream HelloReply) {}\n\n  \/\/ \u5ba2\u6236\u7aef\u6d41 (Client Streaming RPC)\n  rpc sayHelloClientStream (stream HelloRequest) returns (HelloReply) {}\n\n  \/\/ \u96d9\u5411\u6d41 (Bidirectional Streaming RPC)\n  rpc sayHellBidirectionalStream (stream HelloRequest) returns (stream HelloReply) {}\n}\n\nmessage HelloRequest {\n  string name = 1;\n}\n\nmessage HelloReply {\n  string message = 1;\n}\n<\/code><\/pre>\n<p><a id=\"b\"><\/a><\/p>\n<h4>2.\u56db\u7a2e\u6a21\u5f0f<\/h4>\n<h5>a.\u55ae\u5411\u547c\u53eb (Unary RPC)<\/h5>\n<p>\u5ba2\u6236\u7aef\u5411\u4f3a\u670d\u5668\u767c\u9001\u4e00\u500b\u8acb\u6c42\uff0c\u4e26\u7b49\u5f85\u4f3a\u670d\u5668\u7684\u56de\u8986\u3002\u9019\u662f\u6700\u7c21\u55ae\u7684 gRPC \u901a\u4fe1\u6a21\u5f0f\uff0c\u7528\u65bc\u55ae\u4e00\u7684\u8acb\u6c42-\u56de\u8986\u64cd\u4f5c\u3002\u985e\u4f3c\u65bc\u50b3\u7d71\u7684\u540c\u6b65\u51fd\u6578\u8abf\u7528\u3002<\/p>\n<h5>b.\u4f3a\u670d\u5668\u6d41 (Server Streaming RPC)<\/h5>\n<p>\u5ba2\u6236\u7aef\u5411\u4f3a\u670d\u5668\u767c\u9001\u4e00\u500b\u8acb\u6c42\uff0c\u4e26\u63a5\u6536\u4f86\u81ea\u4f3a\u670d\u5668\u7684\u6d41\u5f0f\u56de\u8986\u3002\u9019\u5141\u8a31\u4f3a\u670d\u5668\u5728\u4e00\u500b\u8acb\u6c42\u4e2d\u6301\u7e8c\u50b3\u9001\u591a\u500b\u6d88\u606f\uff0c\u5ba2\u6236\u7aef\u53ef\u4ee5\u7570\u6b65\u63a5\u6536\u548c\u8655\u7406\u9019\u4e9b\u6d88\u606f\u3002<\/p>\n<h5>c.\u5ba2\u6236\u7aef\u6d41 (Client Streaming RPC)<\/h5>\n<p>\u5ba2\u6236\u7aef\u5c07\u4e00\u500b\u6d41\u5f0f\u8acb\u6c42\uff08\u591a\u500b\u6d88\u606f\uff09\u767c\u9001\u5230\u4f3a\u670d\u5668\uff0c\u7136\u5f8c\u7b49\u5f85\u4f3a\u670d\u5668\u7684\u56de\u8986\u3002\u9019\u5141\u8a31\u5ba2\u6236\u7aef\u5411\u4f3a\u670d\u5668\u9023\u7e8c\u50b3\u9001\u6578\u64da\uff0c\u4e26\u7b49\u5f85\u4f3a\u670d\u5668\u5728\u8655\u7406\u5b8c\u6240\u6709\u6578\u64da\u5f8c\u56de\u8986\u3002<\/p>\n<h5>d.\u96d9\u5411\u6d41 (Bidirectional Streaming RPC)<\/h5>\n<p>\u5ba2\u6236\u7aef\u548c\u4f3a\u670d\u5668\u90fd\u53ef\u4ee5\u540c\u6642\u767c\u9001\u548c\u63a5\u6536\u6d41\u5f0f\u6d88\u606f\uff0c\u5be6\u73fe\u96d9\u5411\u7684\u975e\u540c\u6b65\u901a\u4fe1\u3002\u9019\u7a2e\u6a21\u5f0f\u9069\u7528\u65bc\u9700\u8981\u5be6\u6642\u4e92\u52d5\u6216\u9577\u6642\u9593\u9023\u63a5\u7684\u61c9\u7528\uff0c\u4f8b\u5982\u804a\u5929\u61c9\u7528\u6216\u904a\u6232\u591a\u4eba\u6a21\u5f0f\u3002<\/p>\n<p><a id=\"c\"><\/a><\/p>\n<h4>3.NodeJS \u5be6\u73fe Server \u7aef<\/h4>\n<h5>\u5b89\u88dd grpc \u51fd\u793a\u5eab<\/h5>\n<pre><code class=\"language-shell line-numbers\">npm i @grpc\/grpc-js\nnpm i @grpc\/proto-loader\n<\/code><\/pre>\n<h5>proto.js<\/h5>\n<pre><code class=\"language-javascript line-numbers\">const PROTO_PATH = 'hello.proto';\nconst grpc = require('@grpc\/grpc-js')\nconst protoLoader = require('@grpc\/proto-loader')\n\nconst packageDefinition = protoLoader.loadSync(PROTO_PATH, {\n    keepCase: true, longs: String, enums: String, defaults: true, oneofs: true\n})\n\nconst proto = grpc.loadPackageDefinition(packageDefinition).hello\n\nmodule.exports = proto\n<\/code><\/pre>\n<h5>\u55ae\u5411\u547c\u53eb UnaryRPCServer.js<\/h5>\n<pre><code class=\"language-javascript line-numbers\">const proto = require('.\/proto')\nconst grpc = require('@grpc\/grpc-js')\n\nfunction sayHelloUnary(call, callback) {\n    callback(null, {\n        message: 'Hello ' + call.request.name\n    });\n}\n\nasync function main() {\n    const server = new grpc.Server();\n    server.addService(proto.Greeter.service, {sayHelloUnary: sayHelloUnary});\n\n    server.bindAsync('0.0.0.0:30678', grpc.ServerCredentials.createInsecure(), () =&gt; {\n        server.start();\n        console.log('Server running at http:\/\/0.0.0.0:30678');\n    });\n}\n\nmain()\n<\/code><\/pre>\n<h5>\u4f3a\u670d\u5668\u6d41 ServerSideRPCServer.js<\/h5>\n<pre><code class=\"language-javascript line-numbers\">const grpc = require('@grpc\/grpc-js')\nconst proto = require('.\/proto')\n\nfunction sayHelloServerStream(call) {\n    setInterval(() =&gt; {\n        call.write({ message: `Hello <span class=\"katex math inline\">{call.request.name}<\/span>{new Date()}`});\n    }, 2000)\n}\n\nfunction main() {\n    let server = new grpc.Server()\n    server.addService(proto.Greeter.service, {sayHelloServerStream: sayHelloServerStream})\n    server.bindAsync('0.0.0.0:30678', grpc.ServerCredentials.createInsecure(), () =&gt; {\n        server.start()\n        console.log('Server running at http:\/\/0.0.0.0:30678')\n    });\n}\n\nmain();\n<\/code><\/pre>\n<h5>\u5ba2\u6236\u7aef\u6d41 ClientSideRPCServer.js<\/h5>\n<pre><code class=\"language-javascript line-numbers\">const grpc = require('@grpc\/grpc-js')\nconst proto = require('.\/proto')\n\nfunction sayHelloClientStream(call, callback) {\n    call.on('data', (response) =&gt; {\n        console.log('server receive:', response);\n    });\n\n    call.on('end', () =&gt; {\n        callback(null, { message: `Bye` })\n    });\n}\n\nfunction main() {\n    let server = new grpc.Server()\n    server.addService(proto.Greeter.service, {sayHelloClientStream: sayHelloClientStream})\n    server.bindAsync('0.0.0.0:30678', grpc.ServerCredentials.createInsecure(), () =&gt; {\n        server.start()\n        console.log('Server running at http:\/\/0.0.0.0:30678')\n    });\n}\n\nmain();\n<\/code><\/pre>\n<h5>\u96d9\u5411\u6d41 BidirectionalRPCServer.js<\/h5>\n<pre><code class=\"language-javascript line-numbers\">const grpc = require('@grpc\/grpc-js')\nconst proto = require('.\/proto')\n\nfunction sayHellBidirectionalStream(call) {\n    call.on('data', (response) =&gt; {\n        console.log('server receive:', response);\n    })\n\n    call.on('end', (callback) =&gt; {\n        callback(null, { message: `Bye` })\n    });\n\n    setInterval(() =&gt; {\n        call.write({ message: `Hello Client ${new Date()}` });\n    }, 2000)\n}\n\nfunction main() {\n    let server = new grpc.Server()\n    server.addService(proto.Greeter.service, {sayHellBidirectionalStream: sayHellBidirectionalStream})\n    server.bindAsync('0.0.0.0:30678', grpc.ServerCredentials.createInsecure(), () =&gt; {\n        server.start()\n        console.log('Server running at http:\/\/0.0.0.0:30678')\n    });\n}\n\nmain();\n<\/code><\/pre>\n<p><a id=\"d\"><\/a><\/p>\n<h4>4.NodeJS \u5be6\u73fe Clinet \u7aef<\/h4>\n<h5>\u55ae\u5411\u547c\u53eb UnaryRPCClient.js<\/h5>\n<pre><code class=\"language-javascript line-numbers\">const proto = require('.\/proto')\nconst grpc = require('@grpc\/grpc-js')\n\nasync function main() {\n    const client = new proto.Greeter('localhost:30678', grpc.credentials.createInsecure());\n    client.sayHelloUnary({\n        \"name\": \"Wade\"\n    }, (err, response) =&gt; {\n        if (err) {\n            console.log('Greeting:', err.message);\n            return\n        }\n        console.log('Greeting:', response.message);\n    });\n}\n\nmain()\n<\/code><\/pre>\n<h5>\u4f3a\u670d\u5668\u6d41 ServerSideRPCClient.js<\/h5>\n<pre><code class=\"language-javascript line-numbers\">const grpc = require('@grpc\/grpc-js')\nconst proto = require('.\/proto')\n\nfunction main() {\n    const client = new proto.Greeter('localhost:30678', grpc.credentials.createInsecure())\n    const call = client.sayHelloServerStream({\n        name: \"Wade\"\n    })\n\n    call.on('data', (response) =&gt; {\n        console.log('client receive:', response);\n    });\n\n    call.on('end', () =&gt; {\n        console.log('Bye');\n    });\n}\n\nmain();\n<\/code><\/pre>\n<h5>\u5ba2\u6236\u7aef\u6d41 ClientSideRPCClient.js<\/h5>\n<pre><code class=\"language-javascript line-numbers\">const grpc = require('@grpc\/grpc-js')\nconst proto = require('.\/proto')\n\nfunction main() {\n    const client = new proto.Greeter('localhost:30678', grpc.credentials.createInsecure())\n    const call = client.sayHelloClientStream(() =&gt; {\n\n    })\n\n    setInterval(() =&gt; {\n        call.write({ name: `Hello ${new Date()}`});\n    }, 2000)\n}\n\nmain();\n<\/code><\/pre>\n<h5>\u96d9\u5411\u6d41 BidirectionalRPCClient.js<\/h5>\n<pre><code class=\"language-javascript line-numbers\">const grpc = require('@grpc\/grpc-js')\nconst proto = require('.\/proto')\n\nfunction main() {\n    const client = new proto.Greeter('localhost:30678', grpc.credentials.createInsecure())\n    const call = client.sayHellBidirectionalStream()\n\n    call.on('data', (response) =&gt; {\n        console.log('client receive:', response);\n    });\n\n    call.on('end', (callback) =&gt; {\n        callback(null, { message: `Bye` })\n    });\n\n    setInterval(() =&gt; {\n        call.write({ name: `Hello Server ${new Date()}` });\n    }, 2000)\n}\n\nmain();\n<\/code><\/pre>\n<p><a id=\"e\"><\/a><\/p>\n<h4>5.Android \u5be6\u73fe Client \u7aef<\/h4>\n<h5>\u5c0e\u5165 grpc \u51fd\u793a\u5eab<\/h5>\n<pre><code class=\"language-gradle line-numbers\">dependencies {\n    implementation 'io.grpc:grpc-okhttp:1.42.1'\n    implementation 'io.grpc:grpc-protobuf-lite:1.42.1'\n    implementation 'io.grpc:grpc-stub:1.42.1'\n}\n<\/code><\/pre>\n<h5>\u8a2d\u5b9a build.gradle(Project)<\/h5>\n<pre><code class=\"language-gradle line-numbers\">plugins {\n    id 'com.google.protobuf' version '0.8.17' apply false\n}\n<\/code><\/pre>\n<h5>\u8a2d\u5b9a build.gradle(Module)<\/h5>\n<pre><code class=\"language-gradle line-numbers\">plugins {\n    id 'com.google.protobuf'\n}\n\nprotobuf {\n    protoc { artifact = 'com.google.protobuf:protoc:3.17.2' }\n\n    plugins {\n        javalite { artifact = \"com.google.protobuf:protoc-gen-javalite:3.0.0\" }\n        grpc {\n            artifact = 'io.grpc:protoc-gen-grpc-java:1.42.1' \/\/ CURRENT_GRPC_VERSION\n        }\n    }\n\n    generateProtoTasks {\n        all().each { task -&gt;\n            task.builtins {\n                java { option 'lite' }\n            }\n            task.plugins {\n                grpc { \/\/ Options added to --grpc_out\n                    option 'lite'\n                }\n            }\n        }\n    }\n\n    generatedFilesBaseDir = \"$projectDir\/src\/generated\"\n}\n<\/code><\/pre>\n<h5>\u8072\u660e\u7db2\u8def\u6b0a\u9650<\/h5>\n<pre data-language=XML><code class=\"language-markup line-numbers\">&lt;uses-permission android:name=\"android.permission.INTERNET\" \/&gt;\n<\/code><\/pre>\n<h5>\u5275\u5efa proto \u8cc7\u6599\u593e \u81ea\u52d5\u751f\u6210\u6a94\u6848<\/h5>\n<h6>app\\src\\main\\proto\\hello.proto<\/h6>\n<p><a class=\"wp-editor-md-post-content-link\" href=\"https:\/\/badgameshow.com\/fly\/wp-content\/uploads\/2023\/09\/Screenshot-2023-09-21-111421.png\"><img decoding=\"async\" src=\"https:\/\/badgameshow.com\/fly\/wp-content\/uploads\/2023\/09\/Screenshot-2023-09-21-111421.png\" alt=\"\" \/><\/a><\/p>\n<h6>\u9ede\u64ca Build > Rebuild Project \u81ea\u52d5\u7522\u751f<\/h6>\n<p><a class=\"wp-editor-md-post-content-link\" href=\"https:\/\/badgameshow.com\/fly\/wp-content\/uploads\/2023\/09\/Screenshot-2023-09-21-111745.png\"><img decoding=\"async\" src=\"https:\/\/badgameshow.com\/fly\/wp-content\/uploads\/2023\/09\/Screenshot-2023-09-21-111745.png\" alt=\"\" \/><\/a><\/p>\n<h5>\u55ae\u5411\u547c\u53eb MainActivity.kt<\/h5>\n<pre><code class=\"language-kotlin line-numbers\">class MainActivity : AppCompatActivity() {\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        setContentView(R.layout.activity_main)\n\n        val channel = OkHttpChannelBuilder.forTarget(\"192.168.100.142:30678\")\n            .usePlaintext()\n            .build()\n\n        val client = GreeterGrpc.newStub(channel)\n\n        val request = Hello.HelloRequest.newBuilder()\n            .setName(\"Wade\")\n            .build()\n\n        client.sayHelloUnary(request, object : StreamObserver&lt;Hello.HelloReply&gt; {\n            override fun onNext(value: Hello.HelloReply?) {\n                Log.e(\"GGGRPC\", value?.message.toString())\n            }\n\n            override fun onError(t: Throwable?) {\n                Log.e(\"GGGRPC\", \"onError $t\")\n            }\n\n            override fun onCompleted() {\n                Log.e(\"GGGRPC\", \"onCompleted\")\n            }\n        })\n    }\n}\n<\/code><\/pre>\n<h5>\u4f3a\u670d\u5668\u6d41 MainActivity.kt<\/h5>\n<pre><code class=\"language-kotlin line-numbers\">class MainActivity : AppCompatActivity() {\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        setContentView(R.layout.activity_main)\n\n        val channel = OkHttpChannelBuilder.forTarget(\"192.168.100.142:30678\")\n            .usePlaintext()\n            .build()\n\n        val client = GreeterGrpc.newStub(channel)\n\n        val request = Hello.HelloRequest.newBuilder()\n            .setName(\"Wade\")\n            .build()\n\n        client.sayHelloServerStream(request, object : StreamObserver&lt;Hello.HelloReply&gt; {\n            override fun onNext(value: Hello.HelloReply?) {\n                Log.e(\"GGGRPC\", value?.message.toString())\n            }\n\n            override fun onError(t: Throwable?) {\n                Log.e(\"GGGRPC\", \"onError $t\")\n            }\n\n            override fun onCompleted() {\n                Log.e(\"GGGRPC\", \"onCompleted\")\n            }\n        })\n    }\n}\n<\/code><\/pre>\n<h5>\u5ba2\u6236\u7aef\u6d41 MainActivity.kt<\/h5>\n<pre><code class=\"language-kotlin line-numbers\">class MainActivity : AppCompatActivity() {\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        setContentView(R.layout.activity_main)\n\n        val channel = OkHttpChannelBuilder.forTarget(\"192.168.100.142:30678\")\n            .usePlaintext()\n            .build()\n\n        val client = GreeterGrpc.newStub(channel)\n\n        val call = client.sayHelloClientStream(object : StreamObserver&lt;Hello.HelloReply&gt; {\n            override fun onNext(value: Hello.HelloReply?) {\n                Log.e(\"GGGRPC\", value?.message.toString())\n            }\n\n            override fun onError(t: Throwable?) {\n                Log.e(\"GGGRPC\", \"onError <span class=\"katex math inline\">t\")\n            }\n\n            override fun onCompleted() {\n                Log.e(\"GGGRPC\", \"onCompleted\")\n            }\n        })\n\n        setInterval {\n            val request = Hello.HelloRequest.newBuilder()\n                .setName(\"Hello<\/span>{Date()}\")\n                .build()\n\n            call.onNext(request)\n        }\n    }\n\n    private fun setInterval(handler: () -&gt; Unit) = CoroutineScope(Dispatchers.IO).launch {\n        while (true) {\n            delay(1000)\n            handler()\n        }\n    }\n}\n<\/code><\/pre>\n<h5>\u96d9\u5411\u6d41 MainActivity.kt<\/h5>\n<pre><code class=\"language-kotlin line-numbers\">class MainActivity : AppCompatActivity() {\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        setContentView(R.layout.activity_main)\n\n        val channel = OkHttpChannelBuilder.forTarget(\"192.168.100.142:30678\")\n            .usePlaintext()\n            .build()\n\n        val client = GreeterGrpc.newStub(channel)\n\n        val call = client.sayHellBidirectionalStream(object : StreamObserver&lt;Hello.HelloReply&gt; {\n            override fun onNext(value: Hello.HelloReply?) {\n                Log.e(\"GGGRPC\", value?.message.toString())\n            }\n\n            override fun onError(t: Throwable?) {\n                Log.e(\"GGGRPC\", \"onError <span class=\"katex math inline\">t\")\n            }\n\n            override fun onCompleted() {\n                Log.e(\"GGGRPC\", \"onCompleted\")\n            }\n        })\n\n        setInterval {\n            val request = Hello.HelloRequest.newBuilder()\n                .setName(\"Hello<\/span>{Date()}\")\n                .build()\n\n            call.onNext(request)\n        }\n    }\n\n    private fun setInterval(handler: () -&gt; Unit) = CoroutineScope(Dispatchers.IO).launch {\n        while (true) {\n            delay(1000)\n            handler()\n        }\n    }\n}\n<\/code><\/pre>\n<p><a id=\"f\"><\/a><\/p>\n<h4>6.\u76f8\u95dc\u9023\u7d50<\/h4>\n<p><a class=\"wp-editor-md-post-content-link\" href=\"https:\/\/grpc.github.io\/grpc\/core\/md_doc_statuscodes.html\" target=\"_blank\" rel=\"noopener\">gRPC Error Code<\/a><br \/>\n<a class=\"wp-editor-md-post-content-link\" href=\"https:\/\/juejin.cn\/post\/7135365943282122765\" target=\"_blank\" rel=\"noopener\">Protobuf<\/a><br \/>\n<a class=\"wp-editor-md-post-content-link\" href=\"https:\/\/docs.servicestack.net\/grpc\/android#android-java-protoc-grpc-insecure-example\" target=\"_blank\" rel=\"noopener\">Android gRPC<\/a><br \/>\n<a class=\"wp-editor-md-post-content-link\" href=\"https:\/\/github.com\/bloomrpc\/bloomrpc\/releases\" target=\"_blank\" rel=\"noopener\">BloomRPC<\/a><\/p>\n\n<div style=\"font-size: 0px; height: 0px; line-height: 0px; margin: 0; padding: 0; clear: both;\"><\/div>","protected":false},"excerpt":{"rendered":"<p>\u3010Android\u3011gRPC \u5165\u9580\u6559\u5b78 \u73fe\u4ee3\u7684\u8de8\u8a9e\u8a00\u9060\u7a0b\u904e\u7a0b\u547c\u53eb\u6846\u67b6 gRPC\uff08Google Remote Pr &hellip; <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"pgc_sgb_lightbox_settings":"","footnotes":""},"categories":[5],"tags":[],"class_list":["post-1937","post","type-post","status-publish","format-standard","hentry","category-android"],"_links":{"self":[{"href":"https:\/\/badgameshow.com\/fly\/wp-json\/wp\/v2\/posts\/1937","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/badgameshow.com\/fly\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/badgameshow.com\/fly\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/badgameshow.com\/fly\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/badgameshow.com\/fly\/wp-json\/wp\/v2\/comments?post=1937"}],"version-history":[{"count":7,"href":"https:\/\/badgameshow.com\/fly\/wp-json\/wp\/v2\/posts\/1937\/revisions"}],"predecessor-version":[{"id":1947,"href":"https:\/\/badgameshow.com\/fly\/wp-json\/wp\/v2\/posts\/1937\/revisions\/1947"}],"wp:attachment":[{"href":"https:\/\/badgameshow.com\/fly\/wp-json\/wp\/v2\/media?parent=1937"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/badgameshow.com\/fly\/wp-json\/wp\/v2\/categories?post=1937"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/badgameshow.com\/fly\/wp-json\/wp\/v2\/tags?post=1937"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}