Retrofit的封装

Retrofit 自定义Converter实现发送String和接收JSON Retrofit已经为用户提供了六种Converter,如下: Gson:com.squareup.retrofit2:converter-gson Jackson:com.squareup.retrofit2:converter-jackson Moshi:com.squareup.retrofit2:converter-moshi Protobuf:com.squareup.... 阅读详情

Retrofit是Square公司基于restful风格推出的网络框架封装,截止目前github已经有了37.2kstart,可见他的受欢迎程度非常高,Retrofit基于Okhttp封装,具有非常强大的解耦特点,高度的灵活解耦导致使用起来不够简洁,下面对Retrofit进行一次二次的封装,在使用上更加简洁。封装之后具有一下特点:

  • 支持reftofit的单例模式配置,一次配置多处使用。
  • 支持动态切换baseUrl不影响原有的baseUrl。
  • 支持通用格式的网络请求,返回对象或者字符串。
  • 支持快捷的请求方式返回字符串格式的数据。
  • 支持大文件下载和进度回调以及动态取消。
  • 支持单文件和多文件上传。

一、导入依赖库

implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
implementation 'com.squareup.retrofit2:converter-scalars:2.9.0'
implementation 'com.google.code.gson:gson:2.8.6'

二、reftofit的创建

Retrofit的创建方式如下:

	Retrofit retrofit = new Retrofit.Builder()
				.baseUrl(baseUrl)
				.addConverterFactory(GsonConverterFactory.create())
				.build();

1、addConverterFactory

用于添加Retrofit返回数据的支持格式,通常有两个返回字符串格式或者返回一个对象,这块需要添加对应的依赖:

  • 返回字符串:.addConverterFactory(GsonConverterFactory.create())
  • 返回对象:.addConverterFactory(ScalarsConverterFactory.create())

二者不能同时添加,同时添加只有后添加的生效,需要依据需求或者项目配置。

2、baseUrl

用于设置请求的协议IP和端口,在配置时候需要确定,但是有些时候有些接口baseUrl会变化,这时候需要单独配置了,原始的retrofit不支持动态配置,目前市面上的解决方案是两种,一种是重新创建一个Retrofit设置baseUrl,另一种是直接在拦截器里面处理,通过Api接口动态配置header,获取对应的baseUrl,使其生效,如果没有配置就使用默认的。

3、Retrofit对象的封装

基于上面两点对retrofit进行封装,命名为RetrofitManager,该管理类中有一个统一的baseUrl配置,需要提前配置好,在请求中直接使用该默认的配置,如果有需要切换的baseUrl,额外创建一个Retrofit,为了避免每次调用创建,把他放在一个Map集合中,每次获取Retrofit根据baseUrl从集合中读取,如果没有则创建,这样可以避免频繁的创建不同baseUrl的Retrofit。另外换需要对于返回数据是String或者为对象的Retrofit的支持。

    /**
     * 返回全局对象
     *
     * 解析为对象
     */
    public Retrofit getRetrofit() {
        checkBaseUrl();
        Retrofit retrofit = retrofitMap.get(baseUrl);
        if (retrofit == null) {
            retrofit = new Retrofit.Builder()
                    .baseUrl(baseUrl)
                    .addConverterFactory(GsonConverterFactory.create())
                    .build();
            retrofitMap.put(baseUrl, retrofit);
        }
        return retrofit;
    }

    /**
     * 返回局部对象
     *
     * 解析为对象
     */
    public Retrofit getRetrofit(String baseUrl) {
        checkBaseUrl(baseUrl);
        Retrofit retrofit = retrofitMap.get(baseUrl);
        if (retrofit == null) {
            retrofit = new Retrofit.Builder()
                    .baseUrl(baseUrl)
                    .addConverterFactory(GsonConverterFactory.create())
                    .build();
            retrofitMap.put(baseUrl, retrofit);
        }
        return retrofit;
    }

    /**
     *  返回全局对象
     *
     *  解析为字符串
     */
    public Retrofit getStringRetrofit() {
        checkBaseUrl();
        Retrofit retrofit = retrofitMap.get(baseUrl);
        if (retrofit == null) {
            retrofit = new Retrofit.Builder()
                    .baseUrl(baseUrl)
                    .addConverterFactory(ScalarsConverterFactory.create())
                    .build();
            retrofitMap.put(baseUrl, retrofit);
        }
        return retrofit;
    }

    /**
     * 返回局部对象
     *
     * 解析为字符串
     */
    public Retrofit getStringRetrofit(String baseUrl) {
        checkBaseUrl();
        Retrofit retrofit = retrofitMap.get(baseUrl);
        if (retrofit == null) {
            retrofit = new Retrofit.Builder()
                    .baseUrl(baseUrl)
                    .addConverterFactory(ScalarsConverterFactory.create())
                    .build();
            retrofitMap.put(baseUrl, retrofit);
        }
        return retrofit;
    }

    /**
     * 设置全局的url
     * @param baseUrl
     * @return
     */
    public  RetrofitManager setBaseUrl(String baseUrl) {
        RetrofitManager.baseUrl = baseUrl;
        return this;
    }

这样在使用中如果有全局统一的baseUrl,则设置:

  • Retrofit retrofit = RetrofitManager.getInstance().setBaseUrl("http://127.0.0.1:3000/").getStringRetrofit();
  • Retrofit retrofit = RetrofitManager.getInstance().setBaseUrl("http://127.0.0.1:3000/").getRetrofit();

如果是需要设置其他的baseUrl,则设置:

  • Retrofit retrofit = RetrofitManager.getInstance().getRetrofit("http://www.weather.com.cn/");
  • Retrofit retrofit = RetrofitManager.getInstance().getStringRetrofit("http://www.weather.com.cn/");

三、Retrofit的通用的请求

    LoginApi loginApi = retrofit.create(LoginApi.class);
    Call<ResponseBody> call = loginApi.getName();
    call.enqueue(new Callback<ResponseBody>() {
        @Override
        public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
            
        }

        @Override
        public void onFailure(Call<ResponseBody> call, Throwable t) {

        }
    });

Retrofit的请求如上,支持get/post/delete/patch/options等方式的请求,配置方式灵活多变,高度解耦,为了兼容各个请求和内容回调,和请求参数配置的解耦,既支持返回为String有支持返回为对象Call这个对象不能直接处理,需要用户配置,否则就是去了通用性,同时能够兼顾请求的简洁性,仅对回调做了处理,回调如下:

	public interface ResponseCallback<T> {

	    void onSuccess(T t);

	    void onFailure(Throwable t);
	}

封装为如下,T表示用户希望返回的数据类型和Call中的泛型保持一致:

	public static <T> void executeAsync(Call<T> call, ResponseCallback<T> callback) {
        call.enqueue(new Callback<T>() {
            @Override
            public void onResponse(Call<T> call, Response<T> response) {
                if (response.isSuccessful() && callback != null) {
                    callback.onSuccess(response.body());
                }
            }

            @Override
            public void onFailure(Call<T> call, Throwable t) {
                if (callback != null) {
                    callback.onFailure(t);
                }
            }
        });
    }

使用封装后的内容如下:

     LoginApi loginApi = retrofit.create(LoginApi.class);
     Call<ResponseBody> call = loginApi.getName();
     HttpUtils.executeAsync(call, new ResponseCallback<ResponseBody>() {
        @Override
        public void onSuccess(ResponseBody responseBody) {
            
        }

        @Override
        public void onFailure(Throwable t) {

        }
    });

四、get和post请求

除了通用的网络请求外,很多时候是get或者post请求,需要返回的格式是字符串的数据,这时候需要对通用的请求进一步封装,返回String格式:

	public interface StringCallback extends ResponseCallback<String> {

	}

对于get和post请求,分为两大类,没有参数的请求和有参数的请求,进一步缩小了请求范围。统一一个StringApi:

	public interface StringApi {

	    //带参数的通用get请求
	    @GET()
	    Call<String> executeGet(@Url String url, @QueryMap Map<String, String> maps);

	    //不带参数的通用get请求
	    @GET()
	    Call<String> executeGet(@Url String url);

	    //不带参数的通用post请求
	    @POST()
	    Call<String> executePost( @Url String url);

	    //带参数的通用post请求
	    @POST()
	    @FormUrlEncoded
	    Call<String> executePost( @Url String url, @FieldMap Map<String, String> maps);

	}

对于call.enqueue的结果统一出来回调

	public class RetrofitStringCallback implements Callback<String> {

	    private StringCallback callback;

	    public RetrofitStringCallback(StringCallback callback) {
	        this.callback = callback;
	    }

	    @Override
	    public void onResponse(Call<String> call, Response<String> response) {
	        if (response.isSuccessful()) {
	            callback.onSuccess(response.body());
	        } else {
	            try {
	                Throwable throwable = new Throwable(response.errorBody().string());
	                callback.onFailure(throwable);
	            } catch (IOException e) {
	                e.printStackTrace();
	            }
	        }
	    }

	    @Override
	    public void onFailure(Call<String> call, Throwable t) {
	        callback.onFailure(t);
	    }
	}

具体请求封装如下:

	/**
     * get:无参数
     */
    public static void get(String url, StringCallback callback) {
        Retrofit retrofit = RetrofitManager.getInstance().getStringRetrofit();
        get(retrofit, url, callback);
    }

    public static void get(Retrofit retrofit, String url, StringCallback callback) {
        StringApi baseApi = retrofit.create(StringApi.class);
        Call<String> call = baseApi.executeGet(url);
        call.enqueue(new RetrofitStringCallback(callback));
    }

    /**
     * get:有参数
     */
    public static void get(String url, Map<String, String> map, StringCallback callback) {
        Retrofit retrofit = RetrofitManager.getInstance().getStringRetrofit();
        get(retrofit, url, map, callback);
    }

    public static void get(Retrofit retrofit, String url, Map<String, String> map, StringCallback callback) {
        StringApi baseApi = retrofit.create(StringApi.class);
        Call<String> call = baseApi.executeGet(url, map);
        call.enqueue(new RetrofitStringCallback(callback));
    }


    /**
     * post:无参数
     */
    public static void post(String url, StringCallback callback) {
        Retrofit retrofit = RetrofitManager.getInstance().getStringRetrofit();
        post(retrofit, url, callback);
    }

    public static void post(Retrofit retrofit, String url, StringCallback callback) {
        StringApi baseApi = retrofit.create(StringApi.class);
        Call<String> call = baseApi.executePost(url);
        call.enqueue(new RetrofitStringCallback(callback));
    }

    /**
     * post有参数
     */
    public static void post(String url, Map<String, String> map, StringCallback callback) {
        Retrofit retrofit = RetrofitManager.getInstance().getStringRetrofit();
        post(retrofit, url, map, callback);
    }

    public static void post(Retrofit retrofit, String url, Map<String, String> map, StringCallback callback) {
        StringApi baseApi = retrofit.create(StringApi.class);
        Call<String> call = baseApi.executePost(url, map);
        call.enqueue(new RetrofitStringCallback(callback));
    }

这样,如果是get或者post请求就变的很简单:

    get("aoi/weather", new StringCallback() {

        @Override
        public void onSuccess(String s) {
            Log.d(TAG, "onSuccess: " + s);
        }

        @Override
        public void onFailure(Throwable t) {
            Log.d(TAG, "onSuccess: " + t);
        }

    });

四、文件下载

1、回调定义

public interface DownLoadListener {

     void onStart();

     void progress(int progress, float currentSize, float totalSize);

     void onFinish(String path);

     void onFailure(String msg);

     void onCancel(String tag);

}

实现类:

public abstract class DownLoadCallback implements DownLoadListener {

    private String folder;
    private String fileName;
    private String tag;

    public DownLoadCallback(String folder, String fileName) {
        this.folder = folder;
        this.fileName = fileName;
    }

    public DownLoadCallback(String folder, String fileName, String tag) {
        this.folder = folder;
        this.fileName = fileName;
        this.tag = tag;
    }


    public void onStart() {

    }

    public void progress(int progress, float currentSize, float totalSize) {

    }

    @Override
    public void onCancel(String tag) {

    }

    public String getFolder() {
        return folder;
    }

    public String getFileName() {
        return fileName;
    }

    public String getTag() {
        return tag;
    }
}

tag用于标记那是那个请求,用于请求的取消和请求的回调标记,如果没有这个需求,则可以不用。

2、DownLoadApi

和get/post的请求一样,文件下载也定义两个接口,一个是有参数的下载,另一个是无参数的下载,返回格式必须是ResponseBody,用于处理下载结果,如果是大文件的话,需要加上@Streaming,因为Retrofit默认下载中回一次性把内容下载到内存中才回调结果,加上@Streaming之后会以流的方式读取写入,否则进度回调不到。

	public interface DownLoadApi {

	    @Streaming
	    @GET()
	    Call<ResponseBody> downLoadApi(@Url String url);

	    @Streaming
	    @GET()
	    Call<ResponseBody> downLoadApi( @Url String url, @QueryMap Map<String, String> maps);

	}

3、封装下载

文件下载是比较耗时间的任务,需要放在子线程中执行,最好放在个线程池executor中,下面直接看下载入口:

    /**
     * 文件下载
     */
    public void executeDownLoadAsync(Retrofit retrofit, String downloadUrl, DownLoadCallback callback) {
        DownLoadApi baseApi = retrofit.create(DownLoadApi.class);
        Call<ResponseBody> call = baseApi.downLoadApi(downloadUrl);
        setDownLoadTag(callback.getTag(), call);
        executor.execute(new DownloadRunnable(call, callback, executor, callMap));
    }

    public void executeDownLoadAsync(Retrofit retrofit, String downloadUrl, Map<String, String> map, DownLoadCallback callback) {
        DownLoadApi baseApi = retrofit.create(DownLoadApi.class);
        Call<ResponseBody> call = baseApi.downLoadApi(downloadUrl, map);
        setDownLoadTag(callback.getTag(), call);
        executor.execute(new DownloadRunnable(call, callback, executor, callMap));
    }

    /**
     * 设置取消下载回调
     */
    private void setDownLoadTag(String tag, Call<ResponseBody> call) {
        if (TextUtils.isEmpty(tag)) {
            return;
        }
        Call put = callMap.get(tag);
        if (put == null) {
            callMap.put(tag, call);
        }
    }

4、下载任务

具体的下载任务放在了DownloadRunnable里面,实现了Runnable接口,run方法中直接发起请求:
 

 call.enqueue(new Callback<ResponseBody>() {
        @Override
        public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
            if (callback == null) {
                return;
            }
            if (response.isSuccessful()) {
                callback.onStart();
                executor.execute(() -> writeResponseBodyToDisk(response.body()));
            } else {
                callback.onFailure(response.message());
            }
        }

        @Override
        public void onFailure(Call<ResponseBody> call, Throwable t) {
            callback.onFailure(t.getMessage());
        }
    });

因为回调是在主线程的,所以需要开辟一块子线程进行磁盘的写入,调用executor.execute只写入:
 

     private void writeResponseBodyToDisk(ResponseBody body) {
        try {
            File file = new File(callback.getFolder() + File.separator + callback.getFileName());
            if (!file.getParentFile().exists()) {
                file.getParentFile().mkdir();
            }
            if (file.exists()) {
                file.delete();
            }
            if (!file.createNewFile()) {
                handler.post(() -> callback.onFailure("file path is not exit"));
                return;
            }
            InputStream inputStream = null;
            OutputStream outputStream = null;
            ProgerssRun progerssRun = new ProgerssRun(callback, file.getAbsolutePath());
            try {
                byte[] fileReader = new byte[1024 * 4];
                long fileSize = body.contentLength();
                long downLoadSize = 0;
                inputStream = body.byteStream();
                outputStream = new FileOutputStream(file);
                handler.postDelayed(progerssRun, 300);
                while (true) {
                    int read = inputStream.read(fileReader);
                    if (read == -1) {
                        break;
                    }
                    outputStream.write(fileReader, 0, read);
                    downLoadSize += read;
                    //回调结果保留几位小数
                    DecimalFormat df = new DecimalFormat("0.000");
                    df.setRoundingMode(RoundingMode.HALF_UP);
                    //将K转为M,保留3位小数返回
                    float currentSize = Float.parseFloat(df.format(downLoadSize / (1024 * 1024f)));
                    float totalSize = Float.parseFloat(df.format(fileSize / (1024 * 1024f)));
                    int progress = (int) (downLoadSize * 100 / fileSize);
                    progerssRun.setProgress(progress, currentSize, totalSize);
                }
                outputStream.flush();

            } catch (IOException e) {
                handler.post(() -> {
                    handler.removeCallbacks(progerssRun);
                    callback.onCancel(callback.getTag());
                });
            } finally {
                if (inputStream != null) {
                    inputStream.close();
                }
                if (outputStream != null) {
                    outputStream.close();
                }
                if (!TextUtils.isEmpty(callback.getTag()) && callMap.get(callback.getTag()) != null) {
                    callMap.remove(callback.getTag());
                }
            }
        } catch (IOException e) {
            handler.post(() -> {
                callback.onFailure(e.getMessage());
            });
        }
    }

上面的handler是主线程的handler,将结果回调给主线程,便于数据的设置,最后关于进度回调的类:

   public static class ProgerssRun implements Runnable {

        private int progress;
        private float currentSize;
        private float totalSize;
        private DownLoadCallback callback;
        private String filePath;

        public ProgerssRun(DownLoadCallback callback, String filePath) {
            this.callback = callback;
            this.filePath = filePath;
        }

        public void setProgress(int progress, float currentSize, float totalSize) {
            this.progress = progress;
            this.currentSize = currentSize;
            this.totalSize = totalSize;
        }

        @Override
        public void run() {
            if (currentSize == totalSize) {
                callback.progress(progress, currentSize, totalSize);
                handler.removeCallbacks(this);
                handler.post(() -> callback.onFinish(filePath));
            } else {
                callback.progress(progress, currentSize, totalSize);
                //延迟300毫秒回调
                handler.postDelayed(this, 300);
            }
        }
    }

这样就完成了文件的下载,用法如下:

    downLoadFile(retrofit, url, new DownLoadCallback(folder, fileFile, tag) {

            @Override
            public void onFinish(String path) {
                
            }

            @Override
            public void onFailure(String msg) {
                
            }

            @Override
            public void progress(int progress, float currentSize, float totalSize) {
               
            }

            @Override
            public void onCancel(String tag) {
                
            }
    });

5、取消下载

在请求的时候设置有一个tag,如果需要取消下载的需求,根据tag进行取消,如果不需要请求可以不用设置:

	/**
     * 取消指定的请求
     *
     * @param tag
     */
    public void cancel(String tag) {
        if (TextUtils.isEmpty(tag)) {
            return;
        }
        Call call = callMap.get(tag);
        if (call != null) {
            callMap.remove(tag);
            if (!call.isCanceled()) {
                call.cancel();
            }
        }
    }

    /**
     * 取消所有的请求
     */
    public void cancelAll() {
        Iterator it = callMap.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry entry = (Map.Entry) it.next();
            Call<ResponseBody> call = (Call<ResponseBody>) entry.getValue();
            call.cancel();
        }
    }

六、文件上传

总结了一下常用的文件上传的Api格式,具体需要那个,直接调用:

	public interface UpLoadApi {

	    /**
	     * 上传字符串
	     */
	    @FormUrlEncoded
	    @POST()
	    Call<String> uploadStringApi(@Url String url, @FieldMap Map<String, String> map);

	    @POST()
	    Call<String> uploadStringApi(@Url String url, @Body RequestBody body);


	    /**
	     * 上传单个文件
	     */
	    @Multipart
	    @POST()
	    Call<String> uploadFileApi(@Url String url, @Part MultipartBody.Part body);

	    /**
	     * 上传多个文件
	     */
	    @Multipart
	    @POST()
	    Call<String> uploadFilesApi(@Url String url, @PartMap Map<String, RequestBody> map);
	    
	    @Multipart
	    @POST()
	    Call<String> uploadFilesApi(@Url String url, @Part List<MultipartBody.Part> parts);

	    /**
	     * 文件字符串混合传递
	     */
	    @Multipart
	    @POST()
	    Call<String> uploadFileStringApi(@Url String url, @Part("body") RequestBody body, @Part MultipartBody.Part file);

	    /**
	     * 通用的上传:这种方式上传的时候,不能再接口上加上@Multipart的注解,否者会报错
	     */
	    @POST()
	    Call<String> uploadApi(@Url String url,@Body RequestBody body);

	}

1、单个文件上传

    /**
     * 上传文件单个
     * 
     * path:文件路径
     * action:服务器接收的字段,和服务器对应
     */
    public static void upLoadFile(String url, String path, String action, StringCallback callback) {
        Retrofit retrofit = RetrofitManager.getInstance().getStringRetrofit();
        upLoadFile(retrofit, url, path, action, callback);
    }

    public static void upLoadFile(Retrofit retrofit, String url, String path, String action, StringCallback callback) {
        UpLoadApi upLoadApi = retrofit.create(UpLoadApi.class);
        File file = new File(path);
        RequestBody body = RequestBody.create(MediaType.parse("multipart/form-data"), file);
        MultipartBody.Part part = MultipartBody.Part.createFormData(action, file.getName(), body);
        Call<String> call = upLoadApi.uploadFileApi(url, part);
        call.enqueue(new RetrofitStringCallback(callback));
    }

使用:

	upLoadFile("upload", "/storage/emulated/0/DCIM/Screenshots/Screenshot_2020_1225_122945.png", "logo", new StringCallback() {

        @Override
        public void onSuccess(String s) {
            Log.d(TAG, "onSuccess: " + s);
        }

        @Override
        public void onFailure(Throwable t) {
            Log.d(TAG, "onFailure: " + t.getMessage());
        }
    });

2、多个文件上传

    /**
     * 上传多个文件
     * listPath:文件路径集合
     * action:服务器接收的字段,和服务器对应
     */
    public static void upLoadFiles(String url, List<String> listPath, String action, StringCallback callback) {
        Retrofit retrofit = RetrofitManager.getInstance().getStringRetrofit();
        upLoadFiles(retrofit, url, listPath, action, callback);
    }

    public static void upLoadFiles(Retrofit retrofit, String url, List<String> listPath, String action, StringCallback callback) {
        Map<String, RequestBody> map = new HashMap<>();
        for (int i = 0; i < listPath.size(); i++) {
            File file = new File(listPath.get(i));
            RequestBody body = RequestBody.create(MediaType.parse("image/*"), file);
            map.put("" + action + "\"; filename=\"" + file.getName(), body);
        }
        UpLoadApi upLoadApi = retrofit.create(UpLoadApi.class);
        Call<String> call = upLoadApi.uploadFilesApi(url, map);
        call.enqueue(new RetrofitStringCallback(callback));
    }

使用:

 	ArrayList<String> pathList = new ArrayList<>();
	pathList.add("/storage/emulated/0/DCIM/Screenshots/Screenshot_2020_1225_122945.png");
	pathList.add("/storage/emulated/0/DCIM/Screenshots/Screenshot_2020_1225_181054.png");
	HttpUtils.upLoadFiles("form", pathList, "logo", new StringCallback() {
	    @Override
	    public void onSuccess(String s) {
	        Log.d(TAG, "onSuccess: " + s);
	    }

	    @Override
	    public void onFailure(Throwable t) {
	        Log.d(TAG, "onFailure: " + t.getMessage());
	    }
	});

有什么改进方案,欢迎提出🤣🤣🤣🤣,最后附上地址,需要的话直接下载:

Retrofit封装源码:https://github.com/yoonerloop/RetrofitUtils

项目测试服务端代码:https://download.youkuaiyun.com/download/yoonerloop/14010673

 

 

 

 

Retrofit中scalars转换html为字符串 在Retrofit中,如果你想直接获取HTML或其他文本格式的响应内容而不是将其映射到一个模型类,ScalarsConverterFactory 就派上用场了。ScalarsConverterFactory 是一个转换器工厂,它能够将响应体转换为Java基本类型如String、Integer或Byte[]等标量值。对于解析HTML而言,最直接的应用就是将整个HTML内容作为字符串获取。 阅读详情

相关推荐

RetrofitUtil网络框架封装,让你事半功倍

进行retrofit框架的封装,让调用更加的简单,高效。适用于不同需求的开发者,详细介绍请看博客 https://blog.youkuaiyun.com/lou_liang/article/details/84071044

android项目实战之二十一之Retrofit简单封装使用

android项目实战之二十一之Retrofit简单封装使用

sccd2009的专栏 764

ORACLE 12C RAC 启动报错,错误代码 ORA-27300,ORA-27301,ORA-27302

非一体机,12.2 无任何补丁,2套X86服务器,1节点集群异常(数据库正常,还有会话),2节点正常工作,负载不高,硬件、空间均未检查到异常,多路径存在掉线的情况,但通过Mulitpath -ll 看又是正常的,2根私有网络,其中一根不同,sysctl中配置的稀疏模式。5、再次加成crs alert ohas等集群日志,以及根据现象和错误再次到后台sr中查找可用信息,发现有一个类似问题,12.2 RAC 无任何补丁,报同样错误,解决方案为重启两套服务器。查询MOS文档以及后台文档,排除上面指出的问题。

weixin_42344665的博客 1461

Retrofit

我们项目当中的每个app都需要用到网络和服务器进行交互,在Android项目开发中使用HTTP协议完成 通信的话,基本上都要用到OkHttp或者Retrofit。OkHttp和Retrofit是目前应用最为广泛的网络组件。

heqiang260的博客 1110

节卡Jaka Zu APP编程避坑指南:从频繁通讯错误到稳定Socket交互的调试心得

本文详细解析了节卡Jaka Zu APP编程中常见的通讯错误问题,并提供了从基础排查到高级调试的完整解决方案。通过优化网络配置、固件匹配、心跳机制和数据交互规范,开发者可实现稳定的Socket通讯,有效提升工业机器人操控的可靠性。文章特别针对v1.6.7.3版本的典型问题给出了实用调试技巧。

weixin_42639633的博客 316

数字签名(Digital Signature)技术详解:从原理到实践

数字签名技术是数字世界身份认证和数据完整性的核心保障。它结合非对称加密和哈希函数两大密码学技术,实现双重安全防护:哈希函数确保数据完整性,非对称加密确保签名不可伪造。签名过程包括发送方用私钥加密文件哈希值生成签名,接收方用公钥验证签名并比对哈希值。RSA、DSA、ECDSA等主流算法各有特点,适用于不同场景。公钥基础设施(PKI)通过数字证书和CA认证建立信任链,确保公钥真实性。这套技术体系支撑着电子合同、软件认证、在线交易等各类数字安全应用,是现代网络信任体系的基石。

guigenyi的专栏 1358

带你认识Retrofit是如何封装Okhttp的

我们本次讨论的主题如下:二者的构建流程可参考下图 现在我们知道了上述的背景知识之后,我们就可以进入本文的主题了。基于上述这三点,我们可以清楚得知道retrofit使得okhttp的使用更加的便利。接下来,我们进入第下一个主题:retrofit如何封装okhttp。 首先,我先看下构建Retrofit对象的代码:很简单,就是一个建造者模式,通过builder为retrofit配置各种需要的数据。 我们进入build方法看下做了什么事情? 从上述代码可以看到,我们在构建retrofit对象时可以不用设置call

qq_36828822的博客 1166

解决LangChain4j报错HTTP/1.1 header parser received no bytes

当使用调用自己部署的大模型服务时报错: 报错信息如下:

weixin_44455388的博客 2334

Retrofit封装

Retrofit封装起来方便使用 标签: android 2017-11-10 16:16 43人阅读 评论(0) 收藏 举报 版权声明:本文为博主原创文章,未经博主允许不得转载。 RetrofitManager是封装的一个工具类,在项目中如果频繁使用Retrofit请求数据,使用RetrofitManager可以减少很多代码量 封装的代码如

qingxuan521721的博客 294

完整版:ultralytics下运行yoloworld并训练

本文介绍了Ultralytics YOLO环境的快速配置与使用流程:1) 通过conda创建Python 3.9环境并安装依赖包;2) 配置中科大镜像源加速安装PyTorch和Ultralytics;3) 准备YOLO格式数据集并修改data.yaml配置文件;4) 提供模型预测、训练和验证的常用指令,包括predict/train/val等命令参数设置。文章还包含CLIP模型下载、权重文件获取以及本地安装等注意事项,完整覆盖了从环境搭建到模型部署的全过程。

weixin_50209871的博客 1341

华南理工大学电子与信息学院23年预推免复试面试经验贴

华南理工大学电子与信息学院23年预推免复试面试经验贴

Scut_Ty的博客 3295

android retrofit 封装,Android实战——Retrofit2的使用和封装

Retrofit2的使用和封装本篇文章包含以下内容:Retrofit2是什么Retrofit2工具类的演示(基于Retrofit2工具类的封装)Retrofit2工具类的封装Retrofit2是什么使用项目的原话:Android和Java中类型安全的HTTP客户端项目地址:https://github.com/square/retrofitRetrofit2的基本使用1、Get请求2、Post请求...

weixin_34163313的博客 1444

《Python星球日记》 第72天:问答系统与信息检索

《Python星球日记》 第72天:问答系统与信息检索,在前面的日子里,我们学习了自然语言处理的基础知识,包括文本预处理、词向量、Transformer架构和各种预训练模型。今天,我们将探索问答系统这一NLP的重要应用,以及如何结合信息检索技术构建智能问答系统。

Code_流苏:在代码中寻诗意,在实践中觅真知 1070

android retrofit 封装,Android 探讨一下Retrofit封装的最佳姿势

在上一篇文章《Android Retrofit + RxJava使用详解》中,我们学习了Retrofit的一些基本用法,但在实际的项目使用中,还是会出现一些问题,今天就让我们一起来探讨一下如何对Retrofit进行封装吧!如果你对Retrofit还不太了解,可以>戳这里如果你使用的是MVP,这篇文章可能不太适合你,请移步《Android 谈谈我所理解的MVP》。1.背景介绍首先来回顾一下Re...

weixin_35044945的博客 1031

仿真学习系列(四十九):Sigrity仿真之电容库制作

在高速电路设计中,电源完整性(PI)是确保系统稳定、可靠运行的关键因素。随着电子产品对性能的要求不断提升,PDN(电源分配网络)的设计与优化变得尤为重要。为了确保电源网络在高速工作状态下不会引发电压波动和信号干扰,我们需要在设计中精确地选择电容器进行优化,而电容库的制作则是这一过程的核心。 OptimizePI作为一个强大的电源完整性优化工具,能够帮助设计师根据不同的目标,批量进行PDN仿真,以得出最佳电容选择。

案例文章,高速信号 223

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

Retrofit的回调封装

Retrofit回调封装的意义 在Android的世界里,可以说 Retrofit 已经一统网络请求的江湖,Retrofit和Spring Cloud中的Feign一样都是声明式REST请求客户端,都提供了大量注解和完善的json对象转换机制,同时不失灵活性。 通常服务端返回都是这种统一格式的...

chenwenxin2088的博客 527

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

Retrofit网络请求二次封装

(之前用过Any,但是后端返回的数据格式有时候会不一样,有可能是Boolean,String,或者就是个列表,并不是一个json,所以后面我换成了JsonElement)App应用程序通过 Retrofit 请求网络,实际上是使用 Retrofit 接口层封装请求参数、Header、Url 等信息,之后由 OkHttp 完成后续的请求操作。网络请求在App开发中是不可避免的开发功能点,Android自带的ottp用于网络请求,于是便衍生了各种便捷的网络请求三方库。retrofit的网络请求的工作本质上是。

Android 领域开发程序员,希望通过写博客的方式不断的总结提升自己,大家共同进步哦! 978

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

Retrofit 最简单的快速入门及自己封装

简单介绍及官方文档的坑 官方文档 http://square.github.io/retrofit/ Retrofit是Square公司开发的一款针对Android网络请求的框架,Retrofit2底层基于OkHttp实现的,OkHttp现在已经得到Google官方认可,大量的app都采用OkHttp做网络请求 Retrofit也就成了最火的网络请求框架之一,想着来研究一下Retrofit了…先看了

zhiyuan0932的博客 2万+

Retrofit2+Rxjava2之优雅的封装

Retrofit2+Rxjava2之优雅的封装   这篇文章主要是教大家如何封装Retrofit2+Rxjava2,所以实现原理不做过多的解释,如有不付,额(你咬我呀!), 还有就是看这篇文章的同时,你一定要对 Retrofit2 和 Rxjava2 有所了解哦,不然懵逼了,我不负责哦,还有就是文章的开头用Retrofit2、和Rxjava2,是为了区分Retrofit1、和Rxjava1的版本为了后面更快的码字都用R

yrmao9893的博客 2万+

retrofit对于BaseBean类的封装

最近才刚刚接触到retrofit 然后就自己的理解对其进行简单的叙述 首先是将retrofit+rxjava+rxLifeCycle等库导入。我这个地方就一下子导入了包含其他的库如果你能够用到就可以直接使用如果不能用到可以去除掉 compile 'io.reactivex.rxjava2:rxandroid:2.0.1' compile 'io.reactivex.rxjava2

weixin_41307234的博客 2496

Android Retrofit 封装模版

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档。

halong99的专栏 1340

Retrofit的使用和封装

Retrofit接口的封装 GET // http://www.qubaobei.com/ios/cf/dish_list.php?stage_id=1&limit=20&page=1 //@Get 请求后面的声明 拼接到我们的baseurl上 之后就会获取一个完整路径 @GET("ios/cf/{path}") //必须传的用@Path(),...

LH_sunshine的博客 504

Android Retrofit的使和封装

Retrofit是Square开发的一个Android和Java的REST客户端库。这个库非常简单并且具有很多特性,相比其他的网络库,更容易让初学者快速掌握。它可以处理GET、POST、PUT、DELETE…等请求,还可以使用picasso加载图片,Retrofit 2.0底层依赖OkHttp实现,也就是说Retrofit本质上就是对OkHttp的更进一步封装。Retrofit和其它Http库最大

Gorky_19的博客 446

retrofit 封装类

package com.example.lenovo.shoppingcenter.network; import com.example.lenovo.shoppingcenter.Apis; import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.concurr...

qq_43151143的博客 899

retrofit2封装

1. retrofit2客户端封装 public class RetrofitClient { private String baseUrl; private long readTimeout = 10000; private long connectTimeout = 10000; public RetrofitClient(String baseUrl...

magic_lemolang的博客 486
上一篇: react-redux的reducer的combineReducers
下一篇: React中的路由
一杯清泉
博客等级 码龄11年 314粉丝 210原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值