一步步打造网络请求框架——初步成型(一)

本文详细介绍了如何为满足特定业务需求,自定义一个轻量级的网络请求框架,通过OkHttp封装GET、POST、PUT、DELETE等操作,并演示了如何在Activity中集成和测试。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

每个公司的项目都有各自具体的业务,市面上大多数第三方网络请求框架都不能完全满足公司业务的具体需求,所以自己动手一步步写一个网络加载框架。
说到网络请求,无非是把子线程中请求到的数据解析出来,并发送回主线程去,期间Activity中处理的逻辑越少越好,美其名曰:一行代码完成,其实也就是如下图所示的类图:

网络请求框架类图

根据上方的逻辑图,先把每个分支都写好,这里需要导入两个jar包

implementation 'com.squareup.okhttp3:okhttp:3.10.0'
implementation 'com.google.code.gson:gson:2.8.0'

并且在Manifest文件中加入联网权限

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

底层还是使用okhttp框架,用一个HttpUtil将其封装起来

public class HttpUtil {
    private static final String       TAG = HttpUtil.class.getSimpleName();
    private static       OkHttpClient sOkHttpClient;

    public static Response get(String url) {
        LogUtils.e("HttpUtil", url);
        Request request= new Request.Builder()
                .url(url)
                .build();
        try {
            return getOkHttpClient().newCall(request).execute();
        } catch (IOException e) {
            LogUtils.e("HttpUtil", e.toString());
        }
        return null;


    }

    public static Response get(String url, Map<String,String> headers) {
        LogUtils.e("HttpUtil", url);
        Request request;
        Request.Builder builder = new Request.Builder();
        if (headers != null && headers.size() > 0){
            for (Object o : headers.entrySet()) {
                Map.Entry entry = (Map.Entry) o;
                String key = (String) entry.getKey();
                String value = (String) entry.getValue();
                builder.addHeader(key, value);
            }
        }
        request = builder.url(url).build();
        Response response;
        try {
            return getOkHttpClient().newCall(request).execute();
        } catch (IOException e) {
            LogUtils.e("HttpUtil", e.toString());
        }
        return null;
    }

    public static Response post(String url, Map<String, String> postParameters, Map<String, String> headers) {
        LogUtils.e("HttpUtil", url);
        try {
            Request request;
            FormBody.Builder builder = new FormBody.Builder();
            if  (postParameters == null) {
                postParameters = new HashMap<>();
            }
            Set<String> set = postParameters.keySet();
            for (String key : set) {
                builder.add(key,postParameters.get(key));
            }
            Request.Builder requestBuilder = new Request.Builder();
            if (headers != null && headers.size() > 0){
                Set<String> headerSet = headers.keySet();
                for (String key : headerSet) {
                    requestBuilder.addHeader(key,headers.get(key));
                }
            }
            RequestBody formBody = builder.build();
            request = requestBuilder
                    .url(url)
                    .post(formBody)
                    .build();
            return getOkHttpClient().newCall(request).execute();

        } catch (Exception e) {
            LogUtils.e("HttpUtil", e.toString());
        }
        return null;

    }

    public static Response put(String url, Map<String, String> postParameters) {
        LogUtils.e("HttpUtil", url);
        try {
            FormBody.Builder builder = new FormBody.Builder();
            if  (postParameters == null) {
                postParameters = new HashMap<>();
            }
            Set<String> set = postParameters.keySet();
            for (String key : set) {
                builder.add(key,postParameters.get(key));
            }
            RequestBody formBody = builder.build();
            Request request = new Request.Builder()
                    .url(url)
                    .put(formBody)
                    .build();

            return getOkHttpClient().newCall(request).execute();
        } catch (Exception e) {
            LogUtils.e("HttpUtil", e.toString());
        }
        return null;

    }

    public static Response delete(String url, Map<String, String> postParameters) {
        LogUtils.e("HttpUtil", url);
        try {
            FormBody.Builder builder = new FormBody.Builder();
            if  (postParameters == null) {
                postParameters = new HashMap<>();
            }
            Set<String> set = postParameters.keySet();
            for (String key : set) {
                builder.add(key,postParameters.get(key));
            }

            RequestBody formBody = builder.build();
            Request request = new Request.Builder()
                    .url(url)
                    .method("DELETE", formBody)
                    .build();
            return getOkHttpClient().newCall(request).execute();
        } catch (Exception e) {
            LogUtils.e("HttpUtil", e.toString());
        }
        return null;

    }




    private static OkHttpClient getOkHttpClient() {
        if (sOkHttpClient == null) {
            synchronized (HttpUtil.class) {
                if (sOkHttpClient == null) {
                    OkHttpClient.Builder builder = new OkHttpClient.Builder();
                    builder.connectTimeout(10, TimeUnit.SECONDS);
                    builder.writeTimeout(10, TimeUnit.SECONDS);
                    builder.readTimeout(30, TimeUnit.SECONDS);
                    sOkHttpClient = builder.build();
                }
            }
        }
        return sOkHttpClient;
    }


}

HttpUtil中代码没什么好说的,就是将一些基础的Get,Post,Put,Delete这些常见的请求封装成为工具方法
 


RequestManager:请求统一管理类,可以包括发起请求,取消请求等一系列网络请求相关生命周期,可以看到网络请求中所必需的参数是Url,Params,还有请求方式(HttpMethod),还需要一个Callback,用于取到数据后回调给Activity(controller),目前先想到这么多,就先把这些写出来
 

public class RequestManager {
    private static RequestManager                           sRequestManager;
    public static RequestManager getRequestManager(){
        if(sRequestManager == null){
            synchronized (RequestManager.class){
                if(sRequestManager == null){
                    sRequestManager = new RequestManager();
                }
            }
        }
        return sRequestManager;
    }
    public void performRequest(String url, Map<String,String> params,HttpMethod httpMethod,JsonCallback callback){
        RequestTask task = new RequestTask(url,params,httpMethod,callback);
        task.execute();
    }
}

由于RequestManager是个管理类,别忘了用单例模式,这里我使用了双加锁模式,其中performRequest就是启动一个任务,用于请求数据,并且将参数发送过去,task.execute()就是执行这个网络请求。

Callback:用于将数据传回到Activity中

IResponseCallback:最上层接口IResponseCallback包含请求成功和失败两个回调,可以实现此接口对此进行扩展,比如onStart(),onComple().......

public interface IResponseCallback<T> {
    /**
     * 请求成功回调
     * @param result
     */
    void onSuccess(T result);

    /**
     * 请求失败回调
     * @param code
     * @param msg
     */
    void onFailure(int code,String msg);
}

JsonCallback:我这里只做了一个小实现,在JsonCallback中解析Json数据,别的扩展大家可以发挥想象空间......

public abstract class JsonCallback<T> implements IResponseCallback<T> {
    public T bindData(String json) {
        return new Gson().fromJson(json,
                ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]);
    }
}

既然是统一对数据包装并且返回,就必须用到泛型,因为每个请求的实体类Bean不是同一个,Gson框架解析没什么好说的,基本属于模板代码

HttpMethod:简单用一个枚举类表示一下~
 

public enum HttpMethod {
    GET,
    POST,
    PUT,
    DELETE
}


RequestTask:网络请求任务类,用于子线程请求数据并处理相关逻辑,拿到数据后,需要用Handler切换到主线程
 

public class RequestTask implements Runnable {
    private static final String TAG = RequestTask.class.getSimpleName();
    private String url;
    private Map<String,String> params;
    private HttpMethod httpMethod;
    private static       InternalHandler sHandler;
    private JsonCallback mJsonCallback;
    public RequestTask(String url, Map<String, String> params,HttpMethod method,JsonCallback callback) {
        this.url = url;
        this.params = params;
        this.httpMethod = method;
        this.mJsonCallback = callback;
    }

    @Override
    public void run() {
        Response response;
        String json;
        if(httpMethod == HttpMethod.GET){
            response = HttpUtil.get(url);
        }else if(httpMethod == HttpMethod.POST){
            response = HttpUtil.post(url,params,null);
        }else if(httpMethod == HttpMethod.PUT){
            response = HttpUtil.put(url,params);
        }else {
            response = HttpUtil.delete(url,params);
        }
        try {
            if(response != null){
                if(response.body() != null){
                    json = response.body().string();
                    if (!TextUtils.isEmpty(json)) {
                        LogUtils.i(TAG,json);
                        JSONObject jsonObject = new JSONObject(json);
                        if (jsonObject.has("code")) {
                            int code = jsonObject.optInt("code");
                            String message = jsonObject.optString("msg");
                            String type = jsonObject.optString("type");
                            String data = jsonObject.optString("data");
                            LogUtils.i(TAG,"需要解析的数据 :" + data);
                            if (code == 1) {
                                Object o = mJsonCallback.bindData(data);
                                onSuccess(o);
                            } else {
                                onFailure(code, message);
                            }
                        } else {
                            onFailure(-1, "json error");
                        }
                    } else {
                        //Json为空
                        onFailure(-1,"json empty");
                        return;
                    }
                }
            }else {
                onFailure(-1,"response empty");
            }

        } catch (Exception e) {
            LogUtils.e(TAG, "error---" + e.toString());
            e.printStackTrace();
            onFailure(-1,"Exception");
        }

    }

    public void execute() {
        new Thread(this).start();
    }

    private void onFailure(final int code, final String msg) {
        getHandler().post(new Runnable() {
            @Override
            public void run() {
                mJsonCallback.onFailure(code,msg);
            }
        });
    }

    private void onSuccess(final Object o) {
        getHandler().post(new Runnable() {
            @Override
            public void run() {
                mJsonCallback.onSuccess(o);
            }
        });
    }

    private static class InternalHandler extends Handler {
        InternalHandler() {
            super(Looper.getMainLooper());
        }
    }

    private static InternalHandler getHandler() {
        if (sHandler == null) {
            synchronized (RequestTask.class) {
                if (sHandler == null) {
                    sHandler = new InternalHandler();
                }
            }
        }
        return sHandler;
    }
}

其中的execute其实就是启动一个子线程,并且start(),传入this,因为RequestTask实现了Runnable接口,在run()中处理一系列判断逻辑,其中关于code的判断是我们与后台服务器定义好的逻辑,拿到json后code为1是请求成功,其余为失败,失败的类型可以自己根据情况返回,打Log也好,回调也好,总之就是越能快速定位错误越好,这一块可以自己自定义。比如有的后台喜欢code定义为200为成功,其余为失败......(这里感谢后台大神为我专门写了两个测试接口)

 

到这里,网络框架的雏形就基本搭建完成了,对照上面的类图,该有的都有了,写一个Activity,整两个Button,测试一下看看行不行:

public class MainActivity extends AppCompatActivity {
    private static final String TAG = MainActivity.class.getSimpleName();
    private String getUrl        = "http://39.100.224.84:6100/api/system/open/module/selectCCGet";
    private String postUrl       = "http://39.100.224.84:6100/api/system/open/module/selectCCPost";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViewById(R.id.btn_test_get).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                RequestManager.getRequestManager().performRequest(getUrl,null,HttpMethod.GET,
                        new JsonCallback<User>() {
                    @Override
                    public void onSuccess(User result) {
                        LogUtils.i(TAG,result.toString());
                    }

                    @Override
                    public void onFailure(int code, String msg) {
                        LogUtils.i(TAG,"code = " + code + "  msg = " + msg);
                    }
                });
            }
        });
        findViewById(R.id.btn_test_post).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Map<String,String> params = new HashMap<>();
                params.put("userId","123");
                RequestManager.getRequestManager().performRequest(postUrl, params, HttpMethod.POST, new JsonCallback<User>() {
                    @Override
                    public void onSuccess(User result) {
                        LogUtils.i(TAG,result.toString());
                    }

                    @Override
                    public void onFailure(int code, String msg) {
                        LogUtils.i(TAG,"code = " + code + "  msg = " + msg);
                    }
                });
            }
        });
    }
}


这里有个User类,就是返回的实体Bean,里面就三个参数,为了方便看返回结果,重写一下toString()方法
 

public class User {


    /**
     * name : ly
     * id : 1
     * sex : 男
     */

    private String name;
    private String id;
    private String sex;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", id='" + id + '\'' +
                ", sex='" + sex + '\'' +
                '}';
    }
}

这里一个Get请求,一个Post请求,简单测试一下(可以看到onClick方法中就两个步骤:1.拼接参数 2.用RequestManager一句话发送请求,并且创建好Callback等待接收结果),运行一下,看看Callback中返回的结果

 

2021-02-07 17:45:38.510 25446-25855/com.wzw.baseframwork E/HttpUtil: http://39.100.224.84:6100/api/system/open/module/selectCCGet
2021-02-07 17:45:38.627 25446-25855/com.wzw.baseframwork I/RequestTask: {"data":{"name":"ly","id":"1","sex":"男"},"msg":"成功","type":"NO","code":1}
2021-02-07 17:45:38.629 25446-25855/com.wzw.baseframwork I/RequestTask: 需要解析的数据 :{"name":"ly","id":"1","sex":"男"}
2021-02-07 17:45:38.634 25446-25446/com.wzw.baseframwork I/MainActivity: User{name='ly', id='1', sex='男'}

OK,大功告成,可以看到MainActivity中的Log中打印出了User的信息,说明上面的代码测试正确。至此,一个网络请求框架就初步成型了,每次在需要用到它的地方拼几个参数,再用RequestManager一句话发送请求,就可以拿到需要的数据了。

功能是完成了,回顾一下上面的代码,发现有很多细节上的地方可以优化,这篇文章就到这了,下一篇文章再来考虑具体的优化。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值