最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Android使用GRPC進(jìn)行通信過(guò)程解析

 更新時(shí)間:2023年02月28日 10:49:56   作者:haohulala  
這篇文章主要給大家介紹了在Android上使用grpc的方法教程,文中通過(guò)示例代碼給大家詳細(xì)介紹了在android上使用grpc的方法以及可能遇到的種種問(wèn)題的解決方法,對(duì)大家具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起看看吧

引言

Android作為一個(gè)開(kāi)發(fā)平臺(tái),本身是使用java進(jìn)行封裝的,因此java可以調(diào)用的庫(kù),在Android中同樣可以進(jìn)行調(diào)用,這樣就使得Android設(shè)備具有豐富的功能,可以進(jìn)行各種類(lèi)型的開(kāi)發(fā)。

這篇文章就介紹如何在Android設(shè)備中使用GRPC進(jìn)行通信。

環(huán)境搭建

工欲善其事,必先利其器。首先我們先來(lái)進(jìn)行開(kāi)發(fā)環(huán)境的搭建。這里先要強(qiáng)調(diào)一下,Android開(kāi)發(fā)中使用的項(xiàng)目管理工具Gradle對(duì)于版本的要求非常嚴(yán)格,如果不使用正確的版本號(hào),可能導(dǎo)致程序報(bào)錯(cuò),因此這一點(diǎn)需要特別注意。

我們?cè)趧?chuàng)建完一個(gè)項(xiàng)目后,需要修改一些文件的信息,具體需要修改的文件信息如下

對(duì)于上面的修改我們一個(gè)一個(gè)來(lái)看。

修改項(xiàng)目的setting.gradle信息

這個(gè)文件里面指定了gradle去哪個(gè)倉(cāng)庫(kù)中去找插件和第三方依賴(lài)庫(kù),我以及項(xiàng)目引入的模塊信息。

我找到的一個(gè)可行的配置信息如下

pluginManagement {
    repositories {
        gradlePluginPortal()
        google()
        mavenCentral()
    }
}
dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
        maven { url 'https://jitpack.io' }
        maven { url 'https://repo.eclipse.org/content/repositories/paho-releases/'}
    }
}
rootProject.name = "gprc_learn"
include ':app'

修改項(xiàng)目的build.gralde信息

項(xiàng)目目錄下的build.gradle文件主要指定了項(xiàng)目中需要引入的插件,當(dāng)然在這個(gè)文件中主要是下載插件,我們需要到具體的模塊的build.gralde中去引入插件。

在這個(gè)項(xiàng)目中,主要指定gradle插件和protobuf插件,我找到的一個(gè)可行配置如下

// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
    repositories {
        maven{ url 'https://maven.aliyun.com/repository/jcenter'}
        maven { url 'https://maven.aliyun.com/repository/google' }
        maven { url 'https://maven.aliyun.com/repository/gradle-plugin' }
        maven { url 'https://maven.aliyun.com/repository/public' }
        google()
        mavenCentral()
    }
    dependencies {
        classpath "com.android.tools.build:gradle:7.2.0"
        classpath "com.google.protobuf:protobuf-gradle-plugin:0.8.17"
    }
}
task clean(type: Delete) {
    delete rootProject.buildDir
}

修改gradle版本號(hào)

這一步需要和你引入的gradle插件相關(guān)聯(lián),插件的版本和你引入的gradle版本必須要匹配才行,我引入的插件版本是7.2.0,引入的gralde版本是7.4。

修改gradle版本一共有兩種方式,第一種就是在projectstructure中進(jìn)行修改。

第二種方法就是直接在配置文件中進(jìn)行修改

你需要哪個(gè)版本的gradle就直接在配置文件中指定對(duì)應(yīng)版本的壓縮包。

這兩種修改方式都是等效的。

修改模塊的build.gradle信息

模塊的build.gradle中引入了插件,同時(shí)對(duì)插件做了一些配置,最最重要的就是引入第三方庫(kù)。

我的配置信息如下

plugins {
    id 'com.android.application'
    id 'com.google.protobuf'
}
android {
    namespace 'com.example.grpc_learn'
    compileSdk 32
    defaultConfig {
        applicationId "com.example.grpc_learn"
        minSdk 29
        targetSdk 32
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    configurations.all {
        resolutionStrategy.force 'com.google.code.findbugs:jsr305:3.0.1'
        exclude group: 'com.google.guava', module: 'listenablefuture'
    }
    sourceSets {
        main {
            proto {
                srcDir 'src/main/proto'
            }
        }
    }
    packagingOptions {
        pickFirst 'META-INF/INDEX.LIST'
        pickFirst 'META-INF/LICENSE'
        pickFirst 'META-INF/io.netty.versions.properties'
    }
}
protobuf {
    protoc {
        artifact = 'com.google.protobuf:protoc:3.17.2'
    }
    plugins {
        grpc {
            artifact = 'io.grpc:protoc-gen-grpc-java:1.39.0' // CURRENT_GRPC_VERSION
        }
    }
    generateProtoTasks {
        all().each { task ->
            task.builtins {
                java { option 'lite' }
            }
            task.plugins {
                grpc {
                    option 'lite' }
            }
        }
    }
}
dependencies {
    implementation 'androidx.appcompat:appcompat:1.4.1'
    implementation 'com.google.android.material:material:1.5.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
    testImplementation 'junit:junit:4.13.2'
    androidTestImplementation 'androidx.test.ext:junit:1.1.3'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
    implementation 'io.grpc:grpc-netty:1.39.0'
    implementation 'io.grpc:grpc-okhttp:1.39.0' // CURRENT_GRPC_VERSION
    implementation 'io.grpc:grpc-protobuf-lite:1.39.0' // CURRENT_GRPC_VERSION
    implementation 'io.grpc:grpc-stub:1.39.0' // CURRENT_GRPC_VERSION
    implementation 'org.apache.tomcat:annotations-api:6.0.53'
}

模塊編譯的時(shí)候會(huì)根據(jù)這個(gè)文件指定的信息進(jìn)行操作。這里最好根據(jù)你自己的配置文件,然后對(duì)比看看和上述文件有哪些缺失的信息,一般只需要添加缺失的信息即可,如果完全照搬上面的內(nèi)容可能導(dǎo)致項(xiàng)目報(bào)錯(cuò),因?yàn)槔锩嬗涗浟四惚旧淼捻?xiàng)目信息,可能和我的項(xiàng)目信息產(chǎn)生沖突。

在main目錄下創(chuàng)建proto目錄

我們需要?jiǎng)?chuàng)建一個(gè)和java目錄同級(jí)的proto文件夾,里面存放proto文件,這樣做是因?yàn)樵赽uild.gradle文件中指定了去proto文件夾中找到*.proto文件,并且編譯成java代碼。

測(cè)試一下

做完上述的幾個(gè)步驟后,我們可以編寫(xiě)一個(gè)簡(jiǎn)單的grpc通信模型,測(cè)試一下環(huán)境是否搭建成功。

首先在proto文件夾下編寫(xiě)hello.proto文件

syntax = "proto3";
option java_multiple_files = true;
option java_package = "io.grpc.examples.helloworld";
option java_outer_classname = "HelloWorldProto";
option objc_class_prefix = "HLW";
package helloworld;
// The greeting service definition.
service Greeter {
    // Sends a greeting
    rpc SayHello (HelloRequest) returns (HelloReply) {}
}
// The request message containing the user's name.
message HelloRequest {
    string name = 1;
}
// The response message containing the greetings
message HelloReply {
    string message = 1;
}

然后編譯項(xiàng)目,我們可以在build目錄下看到對(duì)應(yīng)的java文件

最后,我們可以使用一段簡(jiǎn)單的grpc通信代碼看看是否可以正常通信,我們直接修改MainActivity文件即可

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "GrpcDemo";
    private static final int PROT = 56322;
    private static final String NAME = "hello world";
    private static final String HOST = "localhost";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d(TAG, "start");
        startServer(PROT);
        Log.d(TAG, "start server.");
        startClient(HOST, PROT, NAME);
        Log.d(TAG, "start client.");
    }
    private void startServer(int port){
        try {
            NettyServerBuilder.forPort(port)
                    .addService(new GreeterImpl())
                    .build()
                    .start();
        } catch (IOException e) {
            e.printStackTrace();
            Log.d(TAG, e.getMessage());
        }
    }
    private void startClient(String host, int port, String name){
        ManagedChannel mChannel = ManagedChannelBuilder.forAddress(host, port)
                .usePlaintext()
                .build();
        GreeterGrpc.GreeterStub stub = GreeterGrpc.newStub(mChannel);
        HelloRequest message = HelloRequest.newBuilder().setName(name).build();
        stub.sayHello(message, new StreamObserver<HelloReply>() {
            @Override
            public void onNext(HelloReply value) {
                //Log.d(TAG, "sayHello onNext.");
                Log.d(TAG, value.getMessage());
            }
            @Override
            public void onError(Throwable t) {
                Log.d(TAG, "sayHello onError.");
            }
            @Override
            public void onCompleted() {
                Log.d(TAG, "sayHello onCompleted.");
            }
        });
    }
    private class GreeterImpl extends GreeterGrpc.GreeterImplBase {
        public void sayHello(HelloRequest request, StreamObserver<HelloReply> responseObserver) {
            responseObserver.onNext(sayHello(request));
            responseObserver.onCompleted();
        }
        private HelloReply sayHello(HelloRequest request) {
            return HelloReply.newBuilder()
                    .setMessage(request.getName())
                    .build();
        }
    }
}

然后需要在AndroidManifest.xml文件中添加網(wǎng)絡(luò)權(quán)限

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">
    <!-- 添加網(wǎng)絡(luò)權(quán)限 -->
    <uses-permission android:name="android.permission.INTERNET"/>
    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.Gprc_learn"
        tools:targetApi="31">
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
            <meta-data
                android:name="android.app.lib_name"
                android:value="" />
        </activity>
    </application>
</manifest>

最后編譯運(yùn)行,如果能看到控制臺(tái)中有如下信息表示環(huán)境搭建成功了,好耶ヾ(??▽?)ノ

好了,到了這一步,我們可以將hello.proto和MainActivity中的代碼清除啦,這只是為了測(cè)試環(huán)境是否搭建成功而編寫(xiě)的文件。

GRPC的四種通信模式

GRPC針對(duì)不同的業(yè)務(wù)場(chǎng)景,一共提供了四種通信模式,分別是簡(jiǎn)單一元模式,客戶(hù)端流模式,服務(wù)端流模式和雙向流模式,接下來(lái)這個(gè)進(jìn)行介紹。

簡(jiǎn)單一元模式

所謂簡(jiǎn)單一元模式,實(shí)際上就是客戶(hù)端和服務(wù)端進(jìn)行一問(wèn)一答的通信。

這種通信模式是最簡(jiǎn)單的,應(yīng)用場(chǎng)景有無(wú)線設(shè)備之間和客戶(hù)端之間保持連接的心跳檢測(cè),每隔一段時(shí)間就給服務(wù)端發(fā)送一個(gè)心跳檢測(cè)包,服務(wù)端接收到心跳包后就知道相應(yīng)客戶(hù)端處于連接狀態(tài)。

在客戶(hù)端編寫(xiě)如下程序

    // 簡(jiǎn)單一元模式
    public void simpleHello() {
        // 構(gòu)建簡(jiǎn)單的消息發(fā)送
        Request request = Request.newBuilder().setReqInfo("simpleHello").build();
        stub.simpleHello(request, new StreamObserver<Reply>() {
            @Override
            public void onNext(Reply value) {
                Log.d(TAG, "simpleHello onNext.");
                String info = "[服務(wù)端->客戶(hù)端]" + value.getRepInfo();
                sendInfo(info);
            }
            @Override
            public void onError(Throwable t) {
                Log.d(TAG, "simpleHello onError.");
            }
            @Override
            public void onCompleted() {
                Log.d(TAG, "simpleHello onCompleted.");
            }
        });
    }

服務(wù)端也需要編寫(xiě)對(duì)應(yīng)的處理程序

    @Override
    public void simpleHello(Request request, StreamObserver<Reply> responseObserver) {
        Log.d(TAG, "服務(wù)端調(diào)用simpleHello.");
        String info = "[客戶(hù)端->服務(wù)端]" + request.getReqInfo();
        sendInfo(info);
        responseObserver.onNext(Reply.newBuilder().setRepInfo("simpleHello").build());
        responseObserver.onCompleted();
        super.simpleHello(request, responseObserver);
    }

客戶(hù)端流模式

客戶(hù)端流模式的意思就是客戶(hù)端可以一次性發(fā)送多個(gè)數(shù)據(jù)片段,當(dāng)然數(shù)據(jù)片段是一個(gè)類(lèi),具體的類(lèi)有哪些字段都是你在最開(kāi)始的proto文件中進(jìn)行指定的。這種模式的應(yīng)用場(chǎng)景就比如客戶(hù)端向服務(wù)端發(fā)送一連串的數(shù)據(jù),然后服務(wù)端最后發(fā)送一個(gè)響應(yīng)數(shù)據(jù)表示接收成功。

在客戶(hù)端流模式中,客戶(hù)端可以在onCompleted之前使用多個(gè)onNext進(jìn)行數(shù)據(jù)發(fā)送。

客戶(hù)端代碼如下

    // 客戶(hù)端流模式
    public void clientStream() {
        StreamObserver<Request> requestStreamObserver = stub.clientStream(new StreamObserver<Reply>() {
            @Override
            public void onNext(Reply value) {
                Log.d(TAG, "clientStream onNext.");
                String info = "[服務(wù)端->客戶(hù)端]" + value.getRepInfo();
                sendInfo(info);
            }
            @Override
            public void onError(Throwable t) {
                Log.d(TAG, "clientStream onError.");
            }
            @Override
            public void onCompleted() {
                Log.d(TAG, "clientStream onCompleted.");
            }
        });
        requestStreamObserver.onNext(Request.newBuilder().setReqInfo("clientStream1").build());
        requestStreamObserver.onNext(Request.newBuilder().setReqInfo("clientStream2").build());
        requestStreamObserver.onCompleted();
    }

服務(wù)端也需要編寫(xiě)相應(yīng)代碼

    @Override
    public StreamObserver<Request> clientStream(StreamObserver<Reply> responseObserver) {
        StreamObserver<Request> streamObserver = new StreamObserver<Request>() {
            @Override
            public void onNext(Request value) {
                Log.d(TAG, "clientStream onNext.");
                String info = "[服務(wù)端->客戶(hù)端]" + value.getReqInfo();
                sendInfo(info);
            }
            @Override
            public void onError(Throwable t) {
                Log.d(TAG, "clientStream onError.");
            }
            @Override
            public void onCompleted() {
                Log.d(TAG, "clientStream onCompleted.");
                // 接收完所有消息后給客戶(hù)端發(fā)送消息
                responseObserver.onNext(Reply.newBuilder().setRepInfo("clientStream").build());
                responseObserver.onCompleted();
            }
        };
        return streamObserver;
    }

服務(wù)端流模式

服務(wù)端流模式和客戶(hù)端流模式正好相反,本質(zhì)都是差不多的,應(yīng)用場(chǎng)景有客戶(hù)端發(fā)送一個(gè)數(shù)據(jù)包告訴服務(wù)端,我需要某某數(shù)據(jù),然后服務(wù)器將對(duì)應(yīng)的所有信息都發(fā)送給客戶(hù)端。

客戶(hù)端和服務(wù)端代碼分別如下所示

    // 服務(wù)端流模式
    public void serverStream() {
        Request request = Request.newBuilder().setReqInfo("serverStream").build();
        stub.serverStream(request, new StreamObserver<Reply>() {
            @Override
            public void onNext(Reply value) {
                Log.d(TAG, "serverStream onNext.");
                String info = "[服務(wù)端->客戶(hù)端]" + value.getRepInfo();
                sendInfo(info);
            }
            @Override
            public void onError(Throwable t) {
                Log.d(TAG, "serverStream onError.");
            }
            @Override
            public void onCompleted() {
                Log.d(TAG, "serverStream onCompleted.");
            }
        });
    }
    @Override
    public void serverStream(Request request, StreamObserver<Reply> responseObserver) {
        String info = "[客戶(hù)端->服務(wù)端]" + request.getReqInfo();
        sendInfo(info);
        responseObserver.onNext(Reply.newBuilder().setRepInfo("serverStream1").build());
        responseObserver.onNext(Reply.newBuilder().setRepInfo("serverStream2").build());
        responseObserver.onCompleted();
        super.serverStream(request, responseObserver);
    }

雙向流模式

雙向流模式是最后一種,也是最常用的一種,在這種模式中,客戶(hù)端和服務(wù)端的通信沒(méi)有什么限制,是比較理想的通信模式,應(yīng)用場(chǎng)景也最為廣泛,因?yàn)樵谶@種模式中,你也可以只發(fā)送一個(gè)數(shù)據(jù)包。

客戶(hù)端和服務(wù)端的代碼如下

    // 雙向流模式
    public void bothFlowStream() {
        StreamObserver<Request> streamObserver = stub.bothFlowStream(new StreamObserver<Reply>() {
            @Override
            public void onNext(Reply value) {
                Log.d(TAG, "bothFlowStream onNext.");
                String info = "[服務(wù)端->客戶(hù)端]" + value.getRepInfo();
                sendInfo(info);
            }
            @Override
            public void onError(Throwable t) {
                Log.d(TAG, "bothFlowStream onError.");
            }
            @Override
            public void onCompleted() {
                Log.d(TAG, "bothFlowStream onCompleted.");
            }
        });
        streamObserver.onNext(Request.newBuilder().setReqInfo("bothFlowStream1").build());
        streamObserver.onNext(Request.newBuilder().setReqInfo("bothFlowStream2").build());
        streamObserver.onCompleted();
    }
    @Override
    public StreamObserver<Request> bothFlowStream(StreamObserver<Reply> responseObserver) {
        StreamObserver<Request> streamObserver = new StreamObserver<Request>() {
            @Override
            public void onNext(Request value) {
                Log.d(TAG, "bothFlowStream onNext.");
                String info = "[客戶(hù)端->服務(wù)端]" + value.getReqInfo();
                sendInfo(info);
            }
            @Override
            public void onError(Throwable t) {
                Log.d(TAG, "bothFlowStream onError.");
            }
            @Override
            public void onCompleted() {
                Log.d(TAG, "bothFlowStream onCompleted.");
                responseObserver.onNext(Reply.newBuilder().setRepInfo("bothFlowStream1").build());
                responseObserver.onNext(Reply.newBuilder().setRepInfo("bothFlowStream2").build());
                responseObserver.onCompleted();
            }
        };
        return streamObserver;
    }

簡(jiǎn)單的GRPC客戶(hù)端服務(wù)端程序設(shè)計(jì)

上面介紹了GRPC的四種通信模式,以及各種模式中客戶(hù)端和服務(wù)端對(duì)應(yīng)的編寫(xiě)方法。

下面來(lái)介紹一下我們具體應(yīng)該如何編寫(xiě)客戶(hù)端服務(wù)端代碼。

我們一般會(huì)將客戶(hù)端和服務(wù)端分開(kāi)來(lái)編寫(xiě),具體的文件如下圖所示

首先需要編寫(xiě)hello.proto文件,并且編譯后生成對(duì)應(yīng)的java文件,我們?cè)趐roto文件中編寫(xiě)了兩個(gè)類(lèi)用來(lái)請(qǐng)求和相應(yīng),并且編寫(xiě)了四個(gè)接口方法,分別對(duì)應(yīng)GRPC請(qǐng)求響應(yīng)的四種模式

syntax = "proto3";
option java_multiple_files = true;
option java_package = "io.grpc.examples.helloworld";
option java_outer_classname = "HelloWorldProto";
option objc_class_prefix = "HLW";
package helloworld;
service Greeter {
    // 簡(jiǎn)單一元模式
    rpc simpleHello (Request) returns (Reply) {}
    // 客戶(hù)端流模式
    rpc clientStream (stream Request) returns (Reply) {}
    // 服務(wù)端流模式
    rpc serverStream (Request) returns (stream Reply) {}
    // 雙向流模式
    rpc bothFlowStream (stream Request) returns (stream Reply) {}
}
message Request {
    string reqInfo = 1;
}
message Reply {
    string repInfo = 1;
}

客戶(hù)端我們只需要編寫(xiě)一個(gè)文件即可

public class GRPCClient {
    private final String TAG = GRPCClient.class.toString();
    private final String host = "localhost";
    private final int port = 55056;
    private Context context;
    private ManagedChannel managedChannel;
    private GreeterGrpc.GreeterStub stub;
    // 在構(gòu)造函數(shù)中連接
    public GRPCClient(Context context) {
        this.context = context;
        managedChannel = ManagedChannelBuilder.forAddress(host, port)
                .usePlaintext()
                .build();
        stub = GreeterGrpc.newStub(managedChannel);
    }
    // 使用廣播的方法發(fā)送數(shù)據(jù)更新ui
    private void sendInfo(String info) {
        Intent intent = new Intent("main.info");
        intent.putExtra("info", info);
        context.sendBroadcast(intent);
    }
    // 簡(jiǎn)單一元模式
    public void simpleHello() {
        // 構(gòu)建簡(jiǎn)單的消息發(fā)送
        Request request = Request.newBuilder().setReqInfo("simpleHello").build();
        stub.simpleHello(request, new StreamObserver<Reply>() {
            @Override
            public void onNext(Reply value) {
                Log.d(TAG, "simpleHello onNext.");
                String info = "[服務(wù)端->客戶(hù)端]" + value.getRepInfo();
                sendInfo(info);
            }
            @Override
            public void onError(Throwable t) {
                Log.d(TAG, "simpleHello onError.");
            }
            @Override
            public void onCompleted() {
                Log.d(TAG, "simpleHello onCompleted.");
            }
        });
    }
    // 客戶(hù)端流模式
    public void clientStream() {
        StreamObserver<Request> requestStreamObserver = stub.clientStream(new StreamObserver<Reply>() {
            @Override
            public void onNext(Reply value) {
                Log.d(TAG, "clientStream onNext.");
                String info = "[服務(wù)端->客戶(hù)端]" + value.getRepInfo();
                sendInfo(info);
            }
            @Override
            public void onError(Throwable t) {
                Log.d(TAG, "clientStream onError.");
            }
            @Override
            public void onCompleted() {
                Log.d(TAG, "clientStream onCompleted.");
            }
        });
        requestStreamObserver.onNext(Request.newBuilder().setReqInfo("clientStream1").build());
        requestStreamObserver.onNext(Request.newBuilder().setReqInfo("clientStream2").build());
        requestStreamObserver.onCompleted();
    }
    // 服務(wù)端流模式
    public void serverStream() {
        Request request = Request.newBuilder().setReqInfo("serverStream").build();
        stub.serverStream(request, new StreamObserver<Reply>() {
            @Override
            public void onNext(Reply value) {
                Log.d(TAG, "serverStream onNext.");
                String info = "[服務(wù)端->客戶(hù)端]" + value.getRepInfo();
                sendInfo(info);
            }
            @Override
            public void onError(Throwable t) {
                Log.d(TAG, "serverStream onError.");
            }
            @Override
            public void onCompleted() {
                Log.d(TAG, "serverStream onCompleted.");
            }
        });
    }
    // 雙向流模式
    public void bothFlowStream() {
        StreamObserver<Request> streamObserver = stub.bothFlowStream(new StreamObserver<Reply>() {
            @Override
            public void onNext(Reply value) {
                Log.d(TAG, "bothFlowStream onNext.");
                String info = "[服務(wù)端->客戶(hù)端]" + value.getRepInfo();
                sendInfo(info);
            }
            @Override
            public void onError(Throwable t) {
                Log.d(TAG, "bothFlowStream onError.");
            }
            @Override
            public void onCompleted() {
                Log.d(TAG, "bothFlowStream onCompleted.");
            }
        });
        streamObserver.onNext(Request.newBuilder().setReqInfo("bothFlowStream1").build());
        streamObserver.onNext(Request.newBuilder().setReqInfo("bothFlowStream2").build());
        streamObserver.onCompleted();
    }
}

在構(gòu)造函數(shù)中,我們需要和服務(wù)端建立連接,所以一般需要服務(wù)端先啟動(dòng)。在連接建立完成后,無(wú)論調(diào)用什么方法都采用一個(gè)連接,然后分別編寫(xiě)GRPC對(duì)應(yīng)的不同服務(wù)接口。

服務(wù)端可以分成兩個(gè)類(lèi)來(lái)編寫(xiě),其中GRPCServer主要用來(lái)啟動(dòng)服務(wù)端,GRPCServiceImpl則是繼承了GreeterGrpc.GreeterImplBase,可以重寫(xiě)里面的方法,表示服務(wù)端如何處理GRPC請(qǐng)求。

public class GRPCServer {
    private final String TAG = GRPCServer.class.toString();
    private final int port = 55056;
    private Context context;
    public GRPCServer(Context context) {
        this.context = context;
        start();
        Log.d(TAG, "服務(wù)端啟動(dòng)");
        sendInfo("服務(wù)端啟動(dòng)");
    }
    // 使用廣播的方法發(fā)送數(shù)據(jù)更新ui
    private void sendInfo(String info) {
        Intent intent = new Intent("main.info");
        intent.putExtra("info", info);
        context.sendBroadcast(intent);
    }
    private void start() {
        try {
            NettyServerBuilder.forPort(port)
                    .addService(new GRPCServiceImpl(context))
                    .build()
                    .start();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
public class GRPCServiceImpl extends GreeterGrpc.GreeterImplBase {
    private final String TAG = GRPCServiceImpl.class.toString();
    private Context context;
    public GRPCServiceImpl(Context context) {
        this.context = context;
    }
    // 使用廣播的方法發(fā)送數(shù)據(jù)更新ui
    private void sendInfo(String info) {
        Intent intent = new Intent("main.info");
        intent.putExtra("info", info);
        context.sendBroadcast(intent);
    }
    @Override
    public void simpleHello(Request request, StreamObserver<Reply> responseObserver) {
        Log.d(TAG, "服務(wù)端調(diào)用simpleHello.");
        String info = "[客戶(hù)端->服務(wù)端]" + request.getReqInfo();
        sendInfo(info);
        responseObserver.onNext(Reply.newBuilder().setRepInfo("simpleHello").build());
        responseObserver.onCompleted();
        super.simpleHello(request, responseObserver);
    }
    @Override
    public StreamObserver<Request> clientStream(StreamObserver<Reply> responseObserver) {
        StreamObserver<Request> streamObserver = new StreamObserver<Request>() {
            @Override
            public void onNext(Request value) {
                Log.d(TAG, "clientStream onNext.");
                String info = "[服務(wù)端->客戶(hù)端]" + value.getReqInfo();
                sendInfo(info);
            }
            @Override
            public void onError(Throwable t) {
                Log.d(TAG, "clientStream onError.");
            }
            @Override
            public void onCompleted() {
                Log.d(TAG, "clientStream onCompleted.");
                // 接收完所有消息后給客戶(hù)端發(fā)送消息
                responseObserver.onNext(Reply.newBuilder().setRepInfo("clientStream").build());
                responseObserver.onCompleted();
            }
        };
        return streamObserver;
    }
    @Override
    public void serverStream(Request request, StreamObserver<Reply> responseObserver) {
        String info = "[客戶(hù)端->服務(wù)端]" + request.getReqInfo();
        sendInfo(info);
        responseObserver.onNext(Reply.newBuilder().setRepInfo("serverStream1").build());
        responseObserver.onNext(Reply.newBuilder().setRepInfo("serverStream2").build());
        responseObserver.onCompleted();
        super.serverStream(request, responseObserver);
    }
    @Override
    public StreamObserver<Request> bothFlowStream(StreamObserver<Reply> responseObserver) {
        StreamObserver<Request> streamObserver = new StreamObserver<Request>() {
            @Override
            public void onNext(Request value) {
                Log.d(TAG, "bothFlowStream onNext.");
                String info = "[客戶(hù)端->服務(wù)端]" + value.getReqInfo();
                sendInfo(info);
            }
            @Override
            public void onError(Throwable t) {
                Log.d(TAG, "bothFlowStream onError.");
            }
            @Override
            public void onCompleted() {
                Log.d(TAG, "bothFlowStream onCompleted.");
                responseObserver.onNext(Reply.newBuilder().setRepInfo("bothFlowStream1").build());
                responseObserver.onNext(Reply.newBuilder().setRepInfo("bothFlowStream2").build());
                responseObserver.onCompleted();
            }
        };
        return streamObserver;
    }
}

我們采用一個(gè)簡(jiǎn)單的布局,就是四個(gè)按鈕,分別對(duì)應(yīng)GRPC的四個(gè)接口,然后在顯示客戶(hù)端和服務(wù)端發(fā)送給MainActivity的信息。這里面我們?cè)谛畔鬟f的時(shí)候采用了廣播的方法,為了能夠發(fā)送廣播,在實(shí)例化客戶(hù)端和服務(wù)端類(lèi)的時(shí)候都需要傳遞Context作為參數(shù),這個(gè)Context就可以發(fā)送廣播了,然后在MainActivity中需要注冊(cè)一個(gè)廣播接收器,當(dāng)接收到具體信息的時(shí)候就更新ui。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <Button
            android:id="@+id/button1"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="一元模式" />
        <Button
            android:id="@+id/button2"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="客戶(hù)端流模式" />
    </LinearLayout>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <Button
            android:id="@+id/button3"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="服務(wù)端流模式" />
        <Button
            android:id="@+id/button4"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="雙向流模式" />
    </LinearLayout>
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/text_title" />
    <TextView
        android:id="@+id/text_info"
        android:layout_width="match_parent"
        android:layout_height="418dp" />
</LinearLayout>
public class MainActivity extends AppCompatActivity {
    private final String TAG = MainActivity.class.toString();
    private Button button1;
    private Button button2;
    private Button button3;
    private Button button4;
    private TextView text_info;
    // 服務(wù)端和客戶(hù)端
    private GRPCClient grpcClient;
    private GRPCServer grpcServer;
    // 注冊(cè)一個(gè)廣播用于更新ui
    private BroadcastReceiver broadcastReceiver;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // 初始化控件
        initView();
        // 注冊(cè)廣播接收器
        register();
        // 初始化服務(wù)端和客戶(hù)端
        grpcClient = new GRPCClient(MainActivity.this);
        grpcServer = new GRPCServer(MainActivity.this);
    }
    // 初始化控件
    private void initView() {
        button1 = findViewById(R.id.button1);
        button1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                grpcClient.simpleHello();
            }
        });
        button2 = findViewById(R.id.button2);
        button2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                grpcClient.clientStream();
            }
        });
        button3 = findViewById(R.id.button3);
        button3.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                grpcClient.serverStream();
            }
        });
        button4 = findViewById(R.id.button4);
        button4.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                grpcClient.bothFlowStream();
            }
        });
        text_info = findViewById(R.id.text_info);
        text_info.setMovementMethod(new ScrollingMovementMethod());
    }
    // 注冊(cè)廣播更新ui
    private void register() {
        broadcastReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                Log.d(TAG, "廣播收到消息" + intent.getStringExtra("info"));
                text_info.append(intent.getStringExtra("info") + "\n");
            }
        };
        IntentFilter filter = new IntentFilter("main.info");
        registerReceiver(broadcastReceiver, filter);
    }
}

最后在虛擬機(jī)上運(yùn)行程序,依次點(diǎn)擊四個(gè)按鈕,如果得到了下圖的結(jié)果,則表示程序跑通啦,好耶ヽ(??▽?)ノ

到此這篇關(guān)于Android使用GRPC進(jìn)行通信過(guò)程解析的文章就介紹到這了,更多相關(guān)Android使用GRPC內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Android中利用zxing實(shí)現(xiàn)自己的二維碼掃描識(shí)別詳解

    Android中利用zxing實(shí)現(xiàn)自己的二維碼掃描識(shí)別詳解

    這篇文章主要給大家介紹了關(guān)于Android中利用zxing實(shí)現(xiàn)自己的二維碼掃描識(shí)別的相關(guān)資料,文中通過(guò)圖文介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用zxing具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起看看吧。
    2017-09-09
  • Android 自定義Button控件實(shí)現(xiàn)按鈕點(diǎn)擊變色

    Android 自定義Button控件實(shí)現(xiàn)按鈕點(diǎn)擊變色

    這篇文章給大家介紹了android 自定義Button控件實(shí)現(xiàn)按鈕點(diǎn)擊變色的代碼,本文給大家附有注釋?zhuān)浅2诲e(cuò),代碼簡(jiǎn)單易懂,對(duì)android按鈕點(diǎn)擊變色的實(shí)現(xiàn)感興趣的朋友參考下吧
    2016-11-11
  • Handler實(shí)現(xiàn)線程之間的通信下載文件動(dòng)態(tài)更新進(jìn)度條

    Handler實(shí)現(xiàn)線程之間的通信下載文件動(dòng)態(tài)更新進(jìn)度條

    每一個(gè)線程對(duì)應(yīng)一個(gè)消息隊(duì)列MessageQueue,實(shí)現(xiàn)線程之間的通信,可通過(guò)Handler對(duì)象將數(shù)據(jù)裝進(jìn)Message中,再將消息加入消息隊(duì)列,而后線程會(huì)依次處理消息隊(duì)列中的消息。這篇文章主要介紹了Handler實(shí)現(xiàn)線程之間的通信下載文件動(dòng)態(tài)更新進(jìn)度條,需要的朋友可以參考下
    2017-08-08
  • Android通過(guò)Service實(shí)現(xiàn)簡(jiǎn)單的音樂(lè)播放

    Android通過(guò)Service實(shí)現(xiàn)簡(jiǎn)單的音樂(lè)播放

    這篇文章主要介紹了Android通過(guò)Service實(shí)現(xiàn)簡(jiǎn)單的音樂(lè)播放,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-05-05
  • Android View的事件分發(fā)機(jī)制深入分析講解

    Android View的事件分發(fā)機(jī)制深入分析講解

    事件分發(fā)從手指觸摸屏幕開(kāi)始,即產(chǎn)生了觸摸信息,被底層系統(tǒng)捕獲后會(huì)傳遞給Android的輸入系統(tǒng)服務(wù)IMS,通過(guò)Binder把消息發(fā)送到activity,activity會(huì)通過(guò)phoneWindow、DecorView最終發(fā)送給ViewGroup。這里就直接分析ViewGroup的事件分發(fā)
    2023-01-01
  • Android開(kāi)發(fā) Activity和Fragment詳解

    Android開(kāi)發(fā) Activity和Fragment詳解

    本文主要介紹Android開(kāi)發(fā) Activity和Fragment,這里對(duì)Activity和Fragment的知識(shí)做了詳細(xì)講解,并附簡(jiǎn)單代碼示例,有興趣的小伙伴可以參考下
    2016-08-08
  • Android ConstraintLayout約束布局使用實(shí)例介紹

    Android ConstraintLayout約束布局使用實(shí)例介紹

    ConstraintLayout是Google在Google I/O 2016大會(huì)上發(fā)布的一種新的布局容器(ViewGroup),它支持以靈活的方式來(lái)放置子控件和調(diào)整子控件的大小,下面這篇文章主要給大家介紹了關(guān)于Android中ConstraintLayout約束布局詳細(xì)解析的相關(guān)資料,需要的朋友可以參考下
    2022-10-10
  • Android實(shí)現(xiàn)手機(jī)震動(dòng)效果

    Android實(shí)現(xiàn)手機(jī)震動(dòng)效果

    這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)手機(jī)震動(dòng)效果的方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-02-02
  • Android自定義View實(shí)現(xiàn)抖音飄動(dòng)紅心效果

    Android自定義View實(shí)現(xiàn)抖音飄動(dòng)紅心效果

    這篇文章主要為大家詳細(xì)介紹了Android自定義View實(shí)現(xiàn)抖音飄動(dòng)紅心效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-05-05
  • Android垂直滾動(dòng)控件ScrollView使用方法詳解

    Android垂直滾動(dòng)控件ScrollView使用方法詳解

    這篇文章主要為大家詳細(xì)介紹了Android垂直滾動(dòng)控件ScrollView的使用方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-08-08

最新評(píng)論

岳普湖县| 宜丰县| 平利县| 邛崃市| 精河县| 固阳县| 那曲县| 遂川县| 济南市| 无锡市| 昌都县| 额尔古纳市| 金堂县| 东丽区| 平安县| 莱芜市| 尉氏县| 泰和县| 治多县| 介休市| 丘北县| 东丽区| 平阳县| 临泉县| 克拉玛依市| 来凤县| 濮阳市| 阆中市| 安仁县| 大悟县| 竹溪县| 张家口市| 唐河县| 南康市| 迁安市| 镇坪县| 铁岭县| 普格县| 义乌市| 高雄市| 开封县|