🐳 《Android》 安卓开发教程 -接口请求okhttp3

225 阅读7分钟

一、安卓的接口请求

安卓的接口请求是指在安卓应用中与服务器进行数据交互的一种方式。通常,安卓应用通过 HTTP 或 HTTPS 协议向服务器发送请求,获取或提交数据。接口请求可以包括 GET、POST、PUT、DELETE 等请求方法,常用于获取远程数据、提交表单、用户认证等。

安卓接口请求的基本流程:

  1. 发送请求:应用通过 HTTP 请求发送给服务器。请求可以包含 URL、请求方法(如 GET、POST)、请求头(headers)、请求体(body,通常用于 POST 请求)等信息。
  2. 服务器处理请求:服务器接收到请求后,根据请求内容进行处理,如查询数据库或进行某些业务操作。
  3. 返回响应:服务器处理完请求后,会返回一个响应,响应通常包括状态码、响应头和响应体(数据)。
  4. 解析响应:应用接收到响应后,根据响应状态码和数据内容进行相应处理(如更新 UI、保存数据等)。

二、什么是OkHttp3

OkHttp3 是一个高效的 HTTP 客户端库,广泛应用于安卓开发中,帮助开发者方便地发送和接收 HTTP 请求。它比 Android 原生的 HttpURLConnection 更加灵活、高效,支持同步和异步请求,自动处理缓存、重定向、压缩等。OkHttp3 是一个非常强大的网络请求库,尤其在请求并发量高时,它表现得尤为优秀。

OkHttp3 的特点:

  1. 简洁易用:使用 OkHttp3,可以非常轻松地发送网络请求,无需过多的配置。
  2. 性能优化:它内置了 HTTP/2 支持、连接池、GZIP 压缩等特性,可以有效提高请求的速度和减少资源的消耗。
  3. 支持异步请求:OkHttp3 可以很方便地支持异步请求,避免了在主线程执行网络操作的阻塞问题。
  4. 自动处理重定向和缓存:OkHttp3 会自动处理一些常见的网络问题,比如重定向、缓存、压缩等。
  5. 连接池机制:它内置连接池管理机制,可以重用已建立的连接,减少连接建立和关闭的开销。
  6. 支持 WebSocket:OkHttp3 还可以支持 WebSocket 协议,适用于需要双向实时通信的场景。

三、OkHttp3实战

HealthCheckSearchRequest

package com.imindbot.medicalinformation.net.request;

import static com.imindbot.medicalinformation.net.G.JSON;

import android.text.TextUtils;
import android.util.Log;

import com.google.gson.Gson;
import com.imindbot.medicalinformation.App;
import com.imindbot.medicalinformation.data.UserInfoBean;
import com.imindbot.medicalinformation.net.G;
import com.imindbot.medicalinformation.utils.GetTokenUtil;
import com.imindbot.medicalinformation.utils.OkHttpUtil;

import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;

public class HealthCheckSearchRequest {

    private Gson mGson;

    public HealthCheckSearchRequest() {
        mGson = new Gson();
    }

    /**
     * 执行体检信息搜索请求
     *
     * @param cardNumber 身份证号
     * @param callback   回调接口,用于处理异步响应
     */
    public void execute(String cardNumber, Callback callback) {
        Log.i(GetTokenUtil.COMMON_TAG, "开始远程接口调用");

        // 创建参数对象并设置身份证号
        HealthCheckSearchData data = new HealthCheckSearchData();
        data.cardNumber = cardNumber;

        // 将参数对象转换为 JSON
        String param = mGson.toJson(data);
        Log.i(GetTokenUtil.COMMON_TAG, "请求参数(JSON 格式):" + param);

        // Token,建议动态获取,避免硬编码
//        String token = "eyJhbGciOiJIUzUxMiIsInppcCI6IkdaSVAifQ.H4sIAAAAAAAAAKtWKi5NUrJScgwN8dANDXYNUtJRSq0oULIyNDe2MLY0NDEw1VEqLU4t8kwBqjI0MFCCcPMSc1OBAsWlBalFiSm5mXlKtQDxC-GeSwAAAA.Ou91T5VTc3x_ipgMa6lEZktBPVClFQj9r7wS6MgFYcKJadzXK06e_LD213rKnx1LAaz8pum8jPmyzDWvDrXzsQ";  // Replace with dynamic token retrieval
        String token = GetTokenUtil.getToken(App.getInstance());
        Log.i(GetTokenUtil.COMMON_TAG, "使用的 Token:" + token);
        if (token == null) {
            token = "";
        }

        // OkHttp 客户端
        OkHttpClient client = OkHttpUtil.getInstance();
        RequestBody body = RequestBody.create(JSON, param);
        Request request = new Request.Builder()
                .url(G.URL_GET_HEALTH_LIST)
                .post(body)
                .addHeader("token", token)
                .build();

        Log.i(GetTokenUtil.COMMON_TAG, "OkHttp 请求对象:" + request);

        // 异步调用并处理响应
        client.newCall(request).enqueue(callback);
        Log.i(GetTokenUtil.COMMON_TAG, "已发送异步请求");
    }

    public void execute(String text, String start, String end, Callback callback) {
        UserInfoBean user = GetTokenUtil.getUserInfo(App.getInstance());
        String username = "";
        if (user != null) {
            username = user.name;
        }
        execute(text, username, start, end, callback);
    }

    public void execute(String text, String inputPerson, String start, String end, Callback callback) {
        Log.i(GetTokenUtil.COMMON_TAG, "开始远程接口调用");

        // Token,建议动态获取,避免硬编码
//        String token = "eyJhbGciOiJIUzUxMiIsInppcCI6IkdaSVAifQ.H4sIAAAAAAAAAKtWKi5NUrJScgwN8dANDXYNUtJRSq0oULIyNDe2MLY0NDEw1VEqLU4t8kwBqjI0MFCCcPMSc1OBAsWlBalFiSm5mXlKtQDxC-GeSwAAAA.Ou91T5VTc3x_ipgMa6lEZktBPVClFQj9r7wS6MgFYcKJadzXK06e_LD213rKnx1LAaz8pum8jPmyzDWvDrXzsQ";  // Replace with dynamic token retrieval
        UserInfoBean user = GetTokenUtil.getUserInfo(App.getInstance());
        String token = GetTokenUtil.getToken(App.getInstance());
        Log.i(GetTokenUtil.COMMON_TAG, "使用的 Token:" + token);
        if (token == null) {
            token = "";
        }

        HealthCheckListData data = new HealthCheckListData();
        data.backFillingType = "健康体检表";
        data.inputPerson = inputPerson;
        //日期只能 从小到大查询,不能从大到小查询
        data.importBeginTime = end;
        data.importEndTime = start;
        if (!TextUtils.isEmpty(text)) {
            if (text.matches("[Xx0-9]+")) {
                data.cardNumber = text;
            } else {
                data.name = text;
            }
        }

        // 将参数对象转换为 JSON
        String param = mGson.toJson(data);
        Log.i(GetTokenUtil.COMMON_TAG, "请求参数(JSON 格式):" + param);

        // OkHttp 客户端
        OkHttpClient client = OkHttpUtil.getInstance();
        RequestBody body = RequestBody.create(JSON, param);
        Request request = new Request.Builder()
                .url(G.URL_GET_HEALTH_LIST)
                .post(body)
                .addHeader("token", token)
                .build();

        Log.i(GetTokenUtil.COMMON_TAG, "OkHttp 请求对象:" + request);

        // 异步调用并处理响应
        client.newCall(request).enqueue(callback);
        Log.i(GetTokenUtil.COMMON_TAG, "已发送异步请求");
    }

    // 参数类定义
    class HealthCheckSearchData {
        public String cardNumber;
    }


    class HealthCheckListData {
        public String name;
        public String backFillingType; //"健康体检表"
        public String inputPerson; // user
        public String cardNumber;
        public String importBeginTime;
        public String importEndTime;
//        public int page;
//        public int size;
    }
}

HealthCheckSearchModel

package com.imindbot.medicalinformation.model;

import android.util.Log;

import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;

import com.google.gson.Gson;
import com.imindbot.medicalinformation.data.response.HealthSearchResponse;
import com.imindbot.medicalinformation.net.request.HealthCheckSearchRequest;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Response;

public class HealthCheckSearchModel extends ViewModel {

    private MutableLiveData<HealthSearchResponse> mHealthCheckSearchResponse;

    public HealthCheckSearchModel() {
        mHealthCheckSearchResponse = new MutableLiveData<>();
    }

    public LiveData<HealthSearchResponse> getSearchResponse() {
        return mHealthCheckSearchResponse;
    }

    private Callback mCallback = new Callback() {
        @Override
        public void onFailure(Call call, IOException e) {
            Log.e("healthCheck", "接口调用失败:" + e.getMessage(), e);
            mHealthCheckSearchResponse.postValue(null);
        }

        @Override
        public void onResponse(Call call, Response response) throws IOException {
            if (!response.isSuccessful()) {
                Log.e("healthCheck", "接口调用失败,HTTP 状态码:" + response.code());
                mHealthCheckSearchResponse.postValue(null);
                return;
            }

            String responseBody = response.body().string();
            Log.i("healthCheck", "成功响应,原始数据:" + responseBody);

            // 解析响应数据
            try {
                HealthSearchResponse healthCheckSearchResponse = parseResponse(responseBody);
                if (healthCheckSearchResponse != null && healthCheckSearchResponse.data != null) {
                    mHealthCheckSearchResponse.postValue(healthCheckSearchResponse);
                    Log.i("healthCheck", "数据解析成功,返回结果:" + Arrays.toString(healthCheckSearchResponse.data.list));
                } else {
                    Log.w("healthCheck", "数据解析失败,返回结果为空");
                    mHealthCheckSearchResponse.postValue(null);
                }
            } catch (Exception e) {
                Log.e("healthCheck", "解析响应数据时发生异常:" + e.getMessage(), e);
                mHealthCheckSearchResponse.postValue(null);
            }
        }
    };

    public void search(String cardNumber) {
        Log.i("healthCheck", "开始调用远程接口搜索");
        // 查询最近1年的
        // 获取今天的日期
        Calendar calendar = Calendar.getInstance();
        Date today = calendar.getTime();
        // 设置日历到一年前
        calendar.add(Calendar.YEAR, -1);
        Date oneYearAgo = calendar.getTime();
        // 格式化日期以便显示
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
        String todayString = dateFormat.format(today);
        String oneYearAgoString = dateFormat.format(oneYearAgo);
        Log.i("healthCheck", "todayString:"+todayString);
        Log.i("healthCheck", "oneYearAgoString:"+oneYearAgoString);
        new HealthCheckSearchRequest().execute(cardNumber,"", todayString, oneYearAgoString, mCallback);
    }

    public void getCurHealthCheckup(String cardNumber) {
        // 获取今天的日期
        Calendar calendar = Calendar.getInstance();
        Date today = calendar.getTime();
        // 设置日历到一天前
        calendar.add(Calendar.DATE, -1);
        Date oneYearAgo = calendar.getTime();
        // 格式化日期以便显示
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
        String todayString = dateFormat.format(today);
        String oneYearAgoString = dateFormat.format(oneYearAgo);
        new HealthCheckSearchRequest().execute(cardNumber,"", todayString, oneYearAgoString, mCallback);
    }

    public void getList(String text, String start, String end) {
        new HealthCheckSearchRequest().execute(text, start, end, mCallback);
    }

    private HealthSearchResponse parseResponse(String responseBody) {
        // 解析响应数据并返回对象
        return new Gson().fromJson(responseBody, HealthSearchResponse.class);
    }
}

HealthSearchResponse

package com.imindbot.medicalinformation.data.response;

import com.google.gson.annotations.SerializedName;

import lombok.Data;

@Data
public class HealthSearchResponse {

    public int code;
    public String message;
    public HealthSearchResult data;

    @Data
    public static class HealthSearchResult {
        public int total;
        public SearchResultList[] list;
    }

    @Data
    public static class SearchResultList {

        @SerializedName("id")
        public String id;

        @SerializedName("name")
        public String name;

        @SerializedName("cardNumber")
        public String cardNumber;

        @SerializedName("exaTime")
        public String exaTime; //体检日期

        @SerializedName("birthday")
        public String birthday; //出生日期

        @SerializedName("gender")
        public String gender; //性别

        @SerializedName("phoneNumber")
        public String phoneNumber;

        @SerializedName("inputPerson")
        public String inputPerson;

        @SerializedName("personCategory")
        public String personCategory;

    }
}

OkHttpUtil

package com.imindbot.medicalinformation.utils;

import okhttp3.OkHttpClient;

public class OkHttpUtil {
    private volatile static OkHttpClient singleton;
    private volatile static OkHttpClient gzipClient;

    private OkHttpUtil() {
    }

    public static OkHttpClient getInstance() {
        if (singleton == null) {
            synchronized (OkHttpUtil.class) {
                if (singleton == null) {
                    singleton = new OkHttpClient();
                }
            }
        }
        return singleton;
    }

    public static OkHttpClient getGzipInstance() {
        if (gzipClient == null) {
            synchronized (OkHttpUtil.class) {
                if (gzipClient == null) {
                    gzipClient = new OkHttpClient.Builder()
                            .addInterceptor(new GzipRequestInterceptor())
                            .build();
                }
            }
        }
        return gzipClient;
    }
}

GetTokenUtil

package com.imindbot.medicalinformation.utils;

import android.content.Context;
import android.util.Log;

import com.imindbot.medicalinformation.data.UserBean;
import com.imindbot.medicalinformation.data.UserInfoBean;

import java.io.Serializable;

/**
 * 工具类:用于管理和获取 token。
 */
public class GetTokenUtil {

    public static final String COMMON_TAG = "common_tag";  // 定义 TAG,方便定位日志来源

    /**
     * 从共享存储(SharedPreferences)中获取 token。
     *
     * @param context 用于访问共享存储的上下文
     * @return 如果 token 存在,返回 token 字符串;否则返回 null
     */
    public static String getToken(Context context) {
        if (context == null) {
//            throw new IllegalArgumentException("Context 不能为空");
            return null;
        }

        UserBean user = getUser(context);
        if (user != null) {
            return user.getToken();
        }
        // 如果 token 不存在或无效,返回 null
        return null;
    }

    public static UserBean getUser(Context context) {
        if (context == null) {
            return null;
        }
        try {
            // 从共享存储中获取对象
            Serializable object = SharePreferenceUtils.getObject(context, G.KEY_LOGIN);

            // 检查获取的对象是否是
            if(object instanceof UserBean) {
                return (UserBean) object;
            } else {
                // 如果对象不是字符串,打印错误日志
                Log.e(COMMON_TAG, "获取的对象不是有效的UserBean。");
            }
        } catch (Exception e) {
            // 捕获异常并打印错误信息
            Log.e(COMMON_TAG, "获取 user 失败:" + e.getMessage(), e);  // 打印堆栈信息
        }
        return null;
    }

    public static UserInfoBean getUserInfo(Context context) {
        if (context == null) {
            return null;
        }
        try {
            // 从共享存储中获取对象
            Serializable object = SharePreferenceUtils.getObject(context, G.KEY_USER_INFO);

            // 检查获取的对象是否是
            if(object instanceof UserInfoBean) {
                return (UserInfoBean) object;
            } else {
                // 如果对象不是字符串,打印错误日志
                Log.e(COMMON_TAG, "获取的对象不是有效的UserBean。");
            }
        } catch (Exception e) {
            // 捕获异常并打印错误信息
            Log.e(COMMON_TAG, "获取 user 失败:" + e.getMessage(), e);  // 打印堆栈信息
        }
        return null;
    }

    public static void logout(Context context) {
        if (context == null) {
            return;
        }
        try {
            UserBean user = getUser(context);
            if (user != null) {
                user.token = "";
            }
            SharePreferenceUtils.putObject(context, G.KEY_LOGIN, user);
        } catch (Exception e) {
            // 捕获异常并打印错误信息
            Log.e(COMMON_TAG, "登出失败:" + e.getMessage(), e);  // 打印堆栈信息
        }
    }
}

实际调用

    private HealthCheckSearchModel healthCheckSearchModel;
    healthCheckSearchModel = new ViewModelProvider(this).get(HealthCheckSearchModel.class);
      healthCheckSearchModel.getSearchResponse().observe(this, new Observer<HealthSearchResponse>() {
            @Override
            public void onChanged(HealthSearchResponse response) {
                Log.i(GetTokenUtil.COMMON_TAG ,"健康体检扫码页面扫码响应了"+response);
                if (entity != null) {
                    Log.i(GetTokenUtil.COMMON_TAG ,"健康体检扫码页面扫码响应了entity1122"+entity);
//                    entity = response;
                    //查询得到体检信息(取最近一条)
                    HealthSearchResponse.SearchResultList[] list = response.data.list;
                    boolean todayHealth = false;
                    if (list != null && list.length >0 ){
                        //查询
                        for (HealthSearchResponse.SearchResultList searchResultList : list) {
                            //等于今天则返回true
                            String currentDate = DateUtilSwy.getCurrentDate();
                            String dateTime = searchResultList.getExaTime();
                            if (Objects.equals(currentDate, dateTime)) {
                                Log.i(GetTokenUtil.COMMON_TAG ,"健康体检扫码页面扫码到体检记录,且今天有做体检11");
                                todayHealth = true;
                                searchById(searchResultList.getId());
                                break;
                            }
                        }
                        if (!todayHealth){
                            //有记录但今天没记录,跳转
                            Intent intent = new Intent(AddHealthCheckupActivity.this, HealthCheckupActivity.class);
                            intent.putExtra(StringConstants.SaoMaCardNumber, saoMANumber);
                            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                            startActivity(intent);
                            finish();
                        }

                    }else {
                        //没有查询到今年体检记录
                        // 如果没有体检记录,空处理,传递身份证信息
                        inputText = saoMANumber;
                        searchResidentByCardNumber(inputText);
                        Log.d(GetTokenUtil.COMMON_TAG, "扫码得到的身份证:" + saoMANumber);
                        updateHealthBaseFragment();
                    }



                }
            }
        });


        public void search(String cardNumber) {
        mExecutorGetHealtIdByCard.execute(new Runnable() {
            @Override
            public void run() {
                Log.i(GetTokenUtil.COMMON_TAG, "扫码搜索的身份证:" + cardNumber);
                healthCheckSearchModel.search(cardNumber);
            }
        });
    }