前言:最近做一个安卓应用,实现安卓端从服务器端获取电影列表的功能,于是自己搭建了asp.net服务端并实现安卓代码,之前就用这种方式实现安卓和服务器通信,但是之前后端使用java编写,通过这个应用才知道,okhttp还能和asp.net的服务端通信。本着分享精神和记录作用,本文分享如何使用okhttp3+retroft2+rxjava实现网络通信功能。本文结合上一篇服务端程序,即可进行本地测试(测试时使用真机,且手机网络和服务端网络在同一局域网),文章地址:使用asp.net core web api创建web后台,并连接和使用Sql Server数据库_Zafir2023的博客-CSDN博客

一、引入okhttp3+retroft2+rxjava程序包

在模块build.gradle的依赖中加入如下依赖:

    // 和网络请求相关的几个依赖库 @{
    implementation 'com.squareup.okhttp3:okhttp:3.7.0'
    implementation 'com.squareup.retrofit2:retrofit:2.0.2'
    implementation 'com.squareup.retrofit2:converter-gson:2.0.2'
    implementation 'com.squareup.retrofit2:adapter-rxjava:2.0.2'
    implementation 'com.squareup.okhttp3:logging-interceptor:3.5.0'
    implementation 'com.umeng.analytics:analytics:6.1.4'
    implementation 'io.reactivex:rxjava:1.1.1'
    implementation 'io.reactivex:rxandroid:1.0.1'
    // @}

二、增加网络安全配置文件并配置到清单文件

1、新增网络安全配置文件,在res/xml目录增加network_security_config.xml文件,内容如下:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config cleartextTrafficPermitted="true" />
</network-security-config>

2、在app/main目录AndroidManifest.xml文件中的application标签中添加属性。

android:networkSecurityConfig="@xml/network_security_config"

三、防止在访问服务器时出现SSLHandshakeException

在Activity的onCreate方法中调用如下方法。

// 忽略https的证书校验
public static void handleSSLHandshake() {
        try {
            TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {
                @Override
                public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
                    Log.d("TAG", "checkClientTrusted authType:" + authType);
                }

                @Override
                public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
                    Log.d("TAG", "checkServerTrusted authType:" + authType);
                }

                @Override
                public X509Certificate[] getAcceptedIssuers() {
                    Log.d("TAG", "checkServerTrusted getAcceptedIssuers");
                    return new X509Certificate[0];
                }
            }};

            SSLContext sc = SSLContext.getInstance("TLS");
            // trustAllCerts信任所有的证书
            sc.init(null, trustAllCerts, new SecureRandom());
            HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
            HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
                @Override
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            });
        } catch (Exception ignored) {
        }
    }

四、定义网络通信接口和实体类

本文涉及到的实体类是Film电影信息类,此处先定义,切记,接口中的实体类和服务端的返回的实体类变量名和变量类型要一致(可以比服务器多,但是不能更少),这样才能正确接收服务端返回的所有数据。
Film.java

import android.graphics.Bitmap;

// 接收服务器下发的数据使用,服务器端返回的字段必须有,且变量名一样。可以增加一些变量,但是不能少于服务端返回类
public class Film {
    public String film_name;
    // 影片类型,战争片,爱情片...
    public String film_type;

    public String film_desc;
    // base64格式的图片,接收服务端数据时用
    public String film_pic;

    // 显示到界面上时用
    public Bitmap film_pic_bitmap;
    // 影片评分,平均分
    public String avg_score;
    // 视频位置
    public String film_video_url;
    // 上架状态,待上架、已上架、已下架
    public String film_status;

    public String film_up_time;
    public String film_down_time;
    public String create_time;
    public String update_time;

    public String create_oper;
    public String update_oper;
}
ApiService.java和服务端通信的接口,注意注解的名称和函数参数名、函数返回值类型和服务端程序对应上。
import java.util.List;
// import xxx.Film;
import retrofit2.Call;
import retrofit2.http.POST;
import retrofit2.http.Query;

/**
 * Created by zzh
 */
public interface ApiService {
    // 和服务端对应上,包括URL,返回值类型,参数名及参数类型
    @POST("/FilmList")
    Call<List<Film>> getFilmList(/*@Query("filmStatus")int filmStatus 此处可以添加请求参数,参数名和参数类型和服务器对应上即可*/);
}
RestClient.java类,初始化okhttp,设置转化库等,转化库使用retrofit2库中的gson。
// package xxx

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;

import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.Date;
import java.util.concurrent.TimeUnit;

import okhttp3.OkHttpClient;
import okhttp3.ResponseBody;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Converter;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

/**
 * Created by zzh
 */

public class RestClient {
    private static RestClient instance = new RestClient();
    private ApiService api;

    private RestClient() {
        HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();

        /*HttpLoggingInterceptor.Level共包含四个级别:NONE、BASIC、HEADER、BODY
        NONE       不记录
        BASIC      请求/响应行--> POST /greeting HTTP/1.1 (3-byte body)<-- HTTP/1.1 200 OK (22ms, 6-byte body)
        HEADER  请求/响应行 + 头--> Host: example.comContent-Type: plain/textContent-Length: 3<-- HTTP/1.1 200 OK (22ms)Content-Type: plain/textContent-Length: 6
        BODY       请求/响应行 + 头 + 体*/
        //设置打印数据的级别,要打印所有log,可设置成BODY级别
        interceptor.setLevel(HttpLoggingInterceptor.Level.NONE);
        OkHttpClient okHttpClient = new OkHttpClient.Builder().readTimeout(30,TimeUnit.SECONDS).connectTimeout(30, TimeUnit.SECONDS).addInterceptor(interceptor).build();
//        OkHttpClient okHttpClient = new OkHttpClient();

        GsonBuilder builder = new GsonBuilder();

// Register an adapter to manage the date types as long values
        builder.registerTypeAdapter(Date.class, new JsonDeserializer<Date>() {
            public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
                return new Date(json.getAsJsonPrimitive().getAsLong());
            }
        });

        Gson gson = builder.create();
        // baseUrl根据服务端IP地址做修改
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("http://192.168.31.197:7049/")
                .client(okHttpClient)
                .addConverterFactory(new NullOnEmptyConverterFactory())
                .addConverterFactory(GsonConverterFactory.create(gson))
                .build();
        api = retrofit.create(ApiService.class);

    }

    public static ApiService api() {
        return instance.api;
    }

}

    //处理返回为空的情况
    class NullOnEmptyConverterFactory extends Converter.Factory {

    @Override
    public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
        final Converter<ResponseBody, ?> delegate = retrofit.nextResponseBodyConverter(this, type, annotations);
        return new Converter<ResponseBody, Object>() {
            @Override
            public Object convert(ResponseBody body) throws IOException {
                if (body.contentLength() == 0) return null;
                return delegate.convert(body);                }
        };
    }
}

五、程序中调用服务端接口获取数据方法

网络请求已经使用rxJava异步方式,无需在子线程中调用

/*** 获取影片信息列表 **/
    private void getFilmItemList() {
        // 取全部电影
        RestClient.api().getFilmList()
            .enqueue(new retrofit2.Callback<List<Film>>() {
                @Override
                public void onResponse(retrofit2.Call<List<Film>> call, retrofit2.Response<List<Film>> response) {
					// 返回的数据自动转化成本地实体类数据
                    List<Film> filmItems = response.body();
                    if (filmItems != null)
                        Log.d(TAG, "getFilmList filmItems.size()=" + filmItems.size());
                    if(filmItems != null && filmItems.size() > 0) {
                        // 获取到的数据处理
                    }
                }

                @Override
                public void onFailure(retrofit2.Call<List<Film>> call, Throwable t) {
                    Toast.makeText(getApplication(), "未获取到电影数据,请确认网络是否正常",Toast.LENGTH_SHORT).show();
                }
            });
    }

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐