在Android上使用gRPC

1.Hello

syntax = "proto3";

option java_multiple_files = true;

package hello;

service Hello {
  rpc SayHello (HelloRequest) returns (HelloReply);
}

message HelloRequest {
  string name = 1;
}

message HelloReply {
  string message = 1;
}

2.gRPCService

import hello.HelloGrpc;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;

public class gRPCService {
    private static final String gRPC_HOST = "isilent.me";
    private static final int gRPC_PORT = 80;
    private static gRPCService instance;
    private ManagedChannel mChannel;

    public static gRPCService getInstance() {
        if (instance == null) {
            instance = new gRPCService();
        }
        return instance;
    }

    private gRPCService() {

    }

    /**
     * 获取Channel
     *
     * @return
     */
    private ManagedChannel getChannel() {
        if (mChannel == null || mChannel.isShutdown()) {
            // 设置最大接收消息大小为20M
            mChannel = ManagedChannelBuilder.forAddress(gRPC_HOST, gRPC_PORT).usePlaintext().maxInboundMessageSize(20 * 1024 * 1024).build();
        }
        return mChannel;
    }

    /**
     * 获取Hello存根
     *
     * @return
     */
    public HelloGrpc.HelloStub getHelloStub() {
        return HelloGrpc.newStub(getChannel());
    }
}

3.SimpleStreamObserver

import android.os.Handler;
import android.os.Looper;

import io.grpc.stub.StreamObserver;

public abstract class SimpleStreamObserver<T> implements StreamObserver<T> {
    private static Handler handler = new Handler(Looper.getMainLooper());

    @Override
    public void onCompleted() {

    }

    @Override
    public void onNext(final T value) {
        // 返回主线程
        handler.post(new Runnable() {
            @Override
            public void run() {
                onSuccess(value);
            }
        });
    }

    /**
     * 请求成功的回调
     *
     * @param value
     */
    protected abstract void onSuccess(T value);
}

4.Main

public static void Main() {
    HelloRequest request = HelloRequest.newBuilder().setName("hello").build();
    gRPCService.getInstance().getHelloStub().sayHello(request, new SimpleStreamObserver<HelloReply>() {
        @Override
        protected void onSuccess(HelloReply value) {
            System.out.println(value.getMessage());
        }

        @Override
        public void onError(Throwable t) {

        }
    });
}

在Android上配置gRPC的环境

1.下载安装Protobuf Support插件,如图所示:

2.在项目根目录的 build.gradle 的 buildscript 中加入 protobuf-gradle-plugin 插件:

buildscript {
    ...
    dependencies {
        ...
        classpath "com.google.protobuf:protobuf-gradle-plugin:0.8.12"
    }
}

3.在应用Module的 build.gradle 中进行如下配置

apply plugin: 'com.android.application'
apply plugin: 'com.google.protobuf'

protobuf {
    protoc { artifact = 'com.google.protobuf:protoc:3.11.0' }
    plugins {
        grpc { artifact = 'io.grpc:protoc-gen-grpc-java:1.29.0' }
    }
    generateProtoTasks {
        all().each { task ->
            task.builtins {
                java { option 'lite' }
            }
            task.plugins {
                grpc { option 'lite' }
            }
        }
    }
}

dependencies {
    // gRPC
    implementation 'io.grpc:grpc-okhttp:1.29.0'
    implementation 'io.grpc:grpc-protobuf-lite:1.29.0'
    implementation 'io.grpc:grpc-stub:1.29.0'
    implementation 'javax.annotation:javax.annotation-api:1.2'
}

4.最后将 .proto 协议文件放在 src/main/proto/ 文件夹下,点击build进行编译,如果出现如下图,则证明环境配置成功!


参考链接:

教你如何使用ProtoBuf,通过gRPC服务在android上进行网络请求。

gRPC快速入门

GRPC原理解析

官方示例

【转】Win10 LTSC 恢复照片查看器

转载自:WIN10 LTSC 使用照片查看器打开图片教程


新装的WIN10 LTSC 2019,发现默认看图则是画图,并不是照片查看器。

对WIN10 不太了解,不知道现在WIN10正确的看图方式还是不是照片查看器,但不管怎么样,照片查看器用的习惯了,所以想用回照片查看器,以下是操作教程:

新建一个文本文件,并复制以下代码粘贴保存,修改后缀为.bat

@echo off&cd\&color 0a&cls

echo 恢复Win10照片查看器

reg add "HKLM\SOFTWARE\Microsoft\Windows Photo Viewer\Capabilities\FileAssociations" /v ".jpg" /t REG_SZ /d PhotoViewer.FileAssoc.Tiff /f

reg add "HKLM\SOFTWARE\Microsoft\Windows Photo Viewer\Capabilities\FileAssociations" /v ".jpeg" /t REG_SZ /d PhotoViewer.FileAssoc.Tiff /f

reg add "HKLM\SOFTWARE\Microsoft\Windows Photo Viewer\Capabilities\FileAssociations" /v ".bmp" /t REG_SZ /d PhotoViewer.FileAssoc.Tiff /f

reg add "HKLM\SOFTWARE\Microsoft\Windows Photo Viewer\Capabilities\FileAssociations" /v ".png" /t REG_SZ /d PhotoViewer.FileAssoc.Tiff /f

echo 请双击或右击图片,选择“照片查看器”即可

pause

如果不会创建操作的,可以直接点击下载,然后一定要点击鼠标右键,以管理员身份运行,运行完毕后,随便找一张照片,右键,打开方式,选择照片查看器即可。

点击下载

【转】Java Thread的关于Join,wait,sleep的解释

转载自:Java Thread的关于Join,wait,sleep的解释


Java线程中的Thread.wait()方法
说句实话,在Thread中,我wait方法我从来没有用过,当线程需要休息时,我只是用到了sleep。今天花了点时间研究了一些wait和join方法。

首先,学习要从追问开始。
wait()这个方法它的功能是什么?它的功能是使当前线程阻塞以等待另外一个线程的方法。只有等待的线程里,调用了notify的方法,当前线程便会继续进行。

关于wait()方法,我认为以下这一点概念最为重要:
一:下面这段代码,并且不是使thread1线程阻塞,而是阻塞当前线程,去等待thread1线程调用nofity方法,要注意一开始我一直理解成thread1线程阻塞。

synchronized(thread1){
    thread1.wait();
}

其实只要理解了上面的概念,几乎已经理解wait方法的精髓,还剩一些小概念。
一、wait(long timeout); 这个方法的意思便是,阻塞当前线程timeout毫秒,如果在timeou毫秒之后被等待的线程没有调用notify方法,则结束阻塞。

二、当前每一个线程执行完之后,在C++层,会自动调用了notify。也就是说,假如我们等待的线程执行完毕了,当前等待的线程会自动结束阻塞。

三、wait需要在锁之内被调用。这一块我觉得这片文章写到点上了:https://blog.csdn.net/qq_39907763/article/details/79301813,经过测试,锁只能锁当前的线程的对象,锁其他对象会报监视器异常。

关于notify()方法
notify方法的意思就是,就是通知在等待的线程,你们可以执行的。假如有多个线程调用wait()而阻塞,则他们会相互竞争出一个。

关于notifyAll()方法
notifiyAll就是通知所有调用wait()而阻塞的线程,都继续进行

关于join方法
关于join方法,其实本质上就是判断了一些条件之后调用了wait(0),只要把wait方法理解透了,join自然就理解了。