美文网首页
Android 访问网络:方案一 OkHttp

Android 访问网络:方案一 OkHttp

作者: 栩檬 | 来源:发表于2023-05-04 19:29 被阅读0次

    本文使用登录场景来简单介绍 Android 应用中使用 OkHttp 访问网络的用法。

    • 数据交换协议 HTTP
    • 数据交换格式 JSON
    • HTTP 请求方法 POST

    访问网络的准备工作


    声明使用网络访问权限

    AndroidManifest.xml

    <uses-permission android:name="android.permission.INTERNET" />
    

    启用明文通信

    AndroidManifest.xml

    <application
            ...
            android:usesCleartextTraffic="true">
            ...
    </application>
    

    出于安全性的考虑,在 Android 9 (API 级别 28)及以上版本的系统上,默认禁止应用明文通信,即禁止使用 HTTP 交换数据,需要使用 HTTPS 。

    如果没有启用明文通信,应用在使用 HTTP 访问网络时会引发异常。

    HTTP FAILED : java.net.UnknownServiceException : CLEARTEXT communication to 192.168.43.218 not permitted by network security policy
    译:网络安全策略不允许和 192.168.43.218 进行明文通信

    关于 Android 9 中默认禁用 HTTP 通信的详细信息,可以参阅行为变更:以 API 级别 28 及更高级别为目标的应用一文的 框架安全性变更 部分。

    使用 OkHttp 访问网络


    1.引入依赖

    build.gradle(:app)

    dependencies {
        ...
        implementation 'com.squareup.okhttp3:okhttp:4.10.0'
        implementation 'com.squareup.okhttp3:logging-interceptor:4.10.0'
        implementation 'com.google.code.gson:gson:2.10.1'
    }
    

    2. 创建 OkHttpClient 。添加 Http 日志拦截器,以便调试。

    OkHttpClient client = new OkHttpClient.Builder()
        .addInterceptor(new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY))
        .build();
    

    3. 将请求参数转换为 JSON 字符串,创建 Request。

    • 将请求参数转换为 JSON 格式的字符串
    JsonObject requestParamJsonObject = new JsonObject();
    requestParamJsonObject.addProperty("userName", userName);
    requestParamJsonObject.addProperty("password", password);
    String requestParam = requestParamJsonObject.toString();
    
    • 创建 RequestBody,并将其作为请求体创建 Request
      Request 用来描述一个请求的相关信息,包括 url,请求方法Post/Get, 请求头,请求体等信息。
    MediaType mediaTypeJson = MediaType.parse("application/json; charset=utf-8");
    Request request = new Request.Builder()
        .url("http://192.168.43.218:8080/user/login")
        .post(RequestBody.create(requestParam, mediaTypeJson))
        .build();
    

    4. 创建 Call。

    然后可以使用同步execute()或异步enqueue(Callback)方式执行请求。本文中使用的是异步方式。

    Call call = client.newCall(request);
    

    由于这一步比较简单,通常的写法是和下一步连起来,将 Call 的实例作为匿名对象来使用。

    client.newCall(request).enqueue(new Callback(){...});
    

    5. 将 Call 加入队列,创建 Callback 用来处理网络访问的结果。

    • 将 Call 加入队列,使用 Callback 实例作为 enqueue() 方法的参数
    call.enqueue(new Callback() {
        @Override
        public void onFailure(@NonNull Call call, @NonNull IOException e) {
        
        }
    
        @Override
        public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
            
        }
    });
    
    • 为了方便对响应数据进行预处理,通常会定义统一的接口响应数据格式。
      响应数据示例
    // 登录失败的接口响应数据
    {
        "code": 701,
        "message": "密码错误",
        "data": ""
    }
    
    // 登录成功的接口响应数据
    {
        "code": 600,
        "message": "登录成功",
        "data": "token"
    }
    

    我们可以定义一个 Result 类型来描述响应数据。

    public class Result<DATA> {
    
        private static final int HTTP_REQUEST_SUCCESS_CODE = 600;
    
        public int code;
        public String message;
        public DATA data;
    
    
        public boolean isSuccessful() {
            return code == HTTP_REQUEST_SUCCESS_CODE;
        }
    
        @Override
        public String toString() {
            return "Result{" +
                "code=" + code +
                ", message='" + message + '\'' +
                ", data=" + data +
            '}';
        }
    
    }
    
    • 在 Callback 的 onResponse() 中将响应体的 JSON 字符串转换为期望的类型。
    @Override
    public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
        ResponseBody body = response.body();
        if (body == null) {
            onFailure(call, new IOException("body is null"));
            return;
        }
        Gson gson = new Gson();
        Result<String> result = gson.fromJson(body.string(), new TypeToken<Result<String>>() {
        }.getType());
    }
    

    6. 在 Callback 的回调方法中切换到主线程,进行后续处理。

    比较常用的线程切换方案如下。

    • Handler
    • LiveData
    • Retrofit

    后两种的实现还是使用了 Handler ,由于进行了封装,所以用起来相对简单。本文 采用 LiveData 方案进行线程切换。

    使用 LiveData 切换线程


    1. 引入依赖

    dependencies {
        ...
        implementation "androidx.lifecycle:lifecycle-livedata:2.5.1"
    }
    

    2. 定义 MutableLiveData 变量

    定义 loginResult 变量,用于描述登录结果。

    private final MutableLiveData<Result<String>> loginResult = new MutableLiveData<>();
    

    3. 为 MutableLiveData 变量添加观察者

    调用 loginResult 的 observe() 方法,添加观察者。当 loginResult 的值改变后,此观察者会在主线程进行后续处理。

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ...
        subscribeToLiveData();
    }
    
    private void subscribeToLiveData() {
        loginResult.observe(this, loginResult -> {
            Toast.makeText(LoginActivity.this, loginResult.message, Toast.LENGTH_SHORT).show();        
            if (loginResult.isSuccessful()) {
                handleLoginResultSuccess(loginResult);
            }
        });
    }
    
    private void handleLoginResultSuccess(Result<String> loginResult) {
        Log.i(TAG, "token : " + loginResult.data);
        // save token
        // start activity
    }
    

    4. 在任务线程中调用 postValue() 方法,更改该变量的值

    在 Callback 的 onResponse() 方法中调用 loginResult 的 postValue() 方法。

    @Override
    public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
        ResponseBody body = response.body();
        if (body == null) {
            onFailure(call, new IOException("body is null"));
            return;
        }
        Gson gson = new Gson();
        Result<String> result = gson.fromJson(body.string(), new TypeToken<Result<String>>() {
        }.getType());
    
        loginResult.postValue(result);
    
    }
    


    测试设备参数

    1. 测试设备1:
    • 型号:Mi 10 Lite Zoom
    • 操作系统:MIUI 12.0.6 稳定版 (Android 10)
    1. 测试设备2:
    • 型号:vivo Y66L
    • 操作系统:Funtouch OS 3.0(Android 6.0.1)

    参考资料

    1. 怪盗kidou : 你真的会用Gson吗?Gson使用指南(一)
    2. Square : OkHttp
    3. Android 应用开发指南 : LiveData 概览

    代码

    XuMeng-0 / android-study

    相关文章

      网友评论

          本文标题:Android 访问网络:方案一 OkHttp

          本文链接:https://www.haomeiwen.com/subject/wadtsdtx.html