网络请求 - GateOfTruth/OkSimple GitHub Wiki

通用链式调用方法

oksimple里目前有四个通用的链式调用方法。分别是addHeader,requestCacheControl,tag和params。addHeader用于为当前请求添加请求头,全局请求头添加请查看全局参数。requestCacheControl是okhttp.Request类自带的一个方法,用于支持修改当前请求的缓存策略。tag方法用于自定义tag参数的值,tag参数的默认值是url,用于支持取消请求。params方法会将传入的参数拼接在url之后。OkSimple里的所有请求,在发起的时候,都可以调用这几个方法。注意,在kotlin中,isSync默认为false,如果你要发起的是异步请求,可以不传

GET请求示例

基于GsonCallback的GET请求,kotlin版本示例如下

 OkSimple.get(url,isSync = false).apply {
            tag=xxx
            requestCacheControl= CacheControl.FORCE_CACHE
            params(key,value)
            addHeader(key,value)
        }.execute(object :GsonCallBack<T>(){
                override fun start() {
                    dialog.show()//重写start(),进行诸如弹出dialog的操作
                }
                override fun getData(
                    data: T,
                    rawBodyString: String,
                    call: Call,
                    response: Response
                ) {
                    dialog.dismiss()
                   
                }

                override fun failure(call: Call, e: Exception) {
                    dialog.dismiss()
                    e.printStackTrace()
                }

            })

java的话可以这么写:

OkSimple.INSTANCE.get(url,false).setTheTag(xxx).addHeader(key,value).setTheRequestCacheControl(CacheControl.FORCE_CACHE).params(key,value).execute(new GsonCallBack<T>() {
            @Override
            public void failure(@NotNull Call call, @NotNull Exception e) {

            }

            @Override
            public void getData(T s, @NotNull String rawBodyString, @NotNull Call call, @NotNull Response response) {
                
            }
        });

后面的请求示例也都会基于GsonCallback,同时也不再写java版本了,因为都是异曲同工的。demo代码

同步请求

同步请求和异步请求区别较大,同步请求不支持策略系统,也不支持传入callback,这意味着也无法监听文件上传下载进度。同步请求主要用于一些不太重要的请求,或者轻量,但是需要配合线程池或协程做并发处理的请求。同步请求使用的时候和异步get,post等等请求一样,可以设置header,tag,requestCacheControl等等。使用的时候,在get或者post等方法后面,传入true,代表这是一个同步请求,不传的话默认是异步请求。同步的execute方法不传入callback,改为传入BaseSynchronizeBean的子类,也可以不传,拿到一个默认的NormalSynchronizeBean。BaseSynchronizeBean是一个抽象类,里面包含两个变量,一个是okhttp返回的response,另一个是捕获到的exception,两个都是可为空的变量。可以通过对respond的code或者exception是否为空判断这次同步请求是否成功。isSync 默认值是false,在同步请求中,要显示声明为true

  val thread=object :Thread(){
            override fun run() {
                val bean=OkSimple.get(url,isSync = true)
                    .params(key,value)
                    .execute(GsonSyncBeanBase(ExampleBean::class.java)).responseToData()
                val result=bean?.result
            }
        }
        thread.start()

注意,这里的GsonSyncBeanBase继承自BaseSynchronizeBean,BaseSynchronizeBean是同步请求返回的基础类,基于这个类,你可以衍生出同步的图片请求,文件请求等,都和GsonSyncBeanBase大同小异,因为response已经拿到了,剩下的就是对response进行处理,我在异步请求里已经处理过了,而且就不多写一遍了。这里的GsonSyncBeanBase主要是示范一下如果使用泛型进行解析 demo代码

POST请求示例,使用map

注意: OkSimple.post()这个方法本身其实就可以传一个map参数进去,后面就可以不用传其他参数了。之所以再写一个,是因为有时候会有各种拼装的情况出现,如果一开始 OkSimple.post()里传了map的话,后面的方法是可以不用调用的

   val map= hashMapOf<String,String>()
   map["key1"]="v1"
   map["key2"]="v2"
   map["key3"]="v3"
   OkSimple.post(url).post(map).params("key","value")
                .execute(object :GsonCallBack<T>(){
                    override fun getData(
                        data: T,
                        rawBodyString: String,
                        call: Call,
                        response: Response
                    ) {
                       
                    }

                    override fun failure(call: Call, e: Exception) {
                        
                    }

                })

demo代码

POST请求示例,不使用map

OkSimple.post(url)
                .post("key1","v1")
                .post("key2","v2")
                .post("key3","v3")
                .execute(object :GsonCallBack<T>(){
                    override fun getData(
                        data: T,
                        rawBodyString: String,
                        call: Call,
                        response: Response
                    ) {
                        
                    }

                    override fun failure(call: Call, e: Exception) {
                        
                    }

                })

demo代码

HEAD,DELETE,PATCH,PUT等请求的请求方法

这几种请求,日常使用中用到的都比较少,所以我统一写了个method方法,你需要传入对应的url,http method,以及requestBody。目前okhttp支持的几个方法名,都放到了OkSimpleConstant里面,可以直接用。okhttp本身没有支持CONNECT,OPTIONS和TRACE方法,不过你可以自己传入http method和requestbody,只要你的服务器能解析,那就没有问题。下面是以head请求为例的示例代码

OkSimple.method(url,OkSimpleConstant.HEAD).execute(object :GsonCallBack<T>(){
            override fun getData(
                data: T,
                rawBodyString: String,
                call: Call,
                response: Response
            ) {

            }

            override fun failure(call: Call, e: Exception) {

            }

        } )

demo代码

POST请求提交JSON数据示例

这里重载了另一个方法,可以第二个参数可以传jsonobject,也可以传jsonarray

 val tem=JSONObject()
        tem.put("key1","value1")
        tem.put("key2","value2")
        tem.put("key3","value3")
        OkSimple.postJson(url,tem).execute(object :GsonCallBack<T>(){
            override fun getData(
                data: T,
                rawBodyString: String,
                call: Call,
                response: Response
            ) {

            }

            override fun failure(call: Call, e: Exception) {

            }

        })

demo代码

表单提交,包含文件上传

OkSimple.postForm(url).addFormPart(key,file,mediaType).addFormPart(key,value).execute(object :GsonCallBack<T>(){
            override fun getData(
                data: T,
                rawBodyString: String,
                call: Call,
                response: Response
            ) {
                
            }

            override fun failure(call: Call, e: Exception) {
                
            }

            override fun uploadProgressOnMainThread(fileName: String, total: Long, current: Long) {
                
            }

        })

通常情况下来说,表单提交(包含文件上传)这样就可以了。Oksimple同时也支持一个key一个file和一个key多个file。这里先说一下mediaTypeString这个参数,这个参数是string类型,不是必传的,是可选参数,默认值是application/octet-stream,但比如上传图片的时候,有的服务器不认application/octet-stream,只认"image/jpg",那么这个时候,那么你就把服务器需要的mediatype传过去就行了。然后是fun uploadProgress(fileName: String, total: Long, current: Long)这个方法,因为我重写了RequestBody,所以uploadProgress默认会在子线程被okhttp回调,并且这个方法如果你点进去,看到父类实现的话,是这样实现的

 fun uploadProgress(fileName: String, total: Long, current: Long) {
        OkSimple.mainHandler.post {
            uploadProgressOnMainThread(fileName, total, current)
        }
    }

所以,如果你想在自己的handler处理子线程和主线程的通讯,那么你可以把super.uploadProgress(fileName, total, current)这句删掉,同时uploadProgressOnMainThread也就不会被回调了。 demo代码

post文件上传

使用post形式的文件上传,没有key值,那么你可以参考下面的代码

OkSimple.uploadFile(url,file,mediaTypeString).execute(object :GsonCallBack<T>(){
            override fun getData(
                data: T,
                rawBodyString: String,
                call: Call,
                response: Response
            ) {

            }

            override fun failure(call: Call, e: Exception) {

            }

            override fun downloadProgressOnMainThread(url: String, total: Long, current: Long) {

            }

            override fun downloadProgress(url: String, total: Long, current: Long) {
                super.downloadProgress(url, total, current)
            }

        })

demo代码

文件下载

效果如图:

 OkSimple.downloadFile(url,filename,filepath).execute(object :FileResultCallBack(){
            override fun downloadProgressOnMainThread(url: String, total: Long, current: Long) {

            }

            override fun downloadProgress(url: String, total: Long, current: Long) {
                super.downloadProgress(url, total, current)
            }

            override fun failure(call: Call, e: Exception) {

            }

            override fun finish(file: File) {
               
            }

        })

通过如上代码,便可完成文件下载。下载完的文件,会在finish()方法里回调,finish是FileResultCallBack继承ResultCallBack后新增的方法,用于获取下载完成的文件。Oksimple默认支持断点续传,假如你的服务器不支持断点续传,也可照常下载。如果你不想断点续传,想重新下载,请在下载前把存在的文件删除。在okhttp的逻辑里,是没有断点续传的概念的,断点续传的原理是服务器和本地文件的读写,本质就是当你下载上次中断的文件的时候,跳过已经下载的流,把新的流接在之前下载了一部分的文件后面,这样就实现了断点续传。 Oksimple会根据路径和文件名来判断是不是同一个文件。如果两次下载的路径和文件名相同,则视为同一个文件的断点续传,不会下载两个文件。 oksimple默认给每一个请求一个和url一样的tag,也可以自定义tag,具体可以参考例子里的文件下载。downloadProgressOnMainThread和downloadProgress与之前文件上传的uploadProgressOnMainThread和uploadProgress同理。因为我重写了ResponseBody,所以okhttp默认会在子线程回调downloadProgress,如果你想自己控制主线程子线程的切换,同样可以删掉 super.downloadProgress(url, total, current)这句代码即可。

多文件同时下载

效果如图:

多文件下载其实就是多次调用下载方法,但有些许不同,具体可以参考demo里的MultipleDownloadActivity。demo里没做到诸如各大应用商店里那样的自动下载,但这确实是可以实现的,你可以考虑接入sqlite或者handler等来进行实现。我没有打算做一个专门的下载框架,因为就以往的开发过程中,对多文件下载的需求总是相当复杂的,要考虑的很多,诸如断网,进程杀死等等。很少有一个框架能满足各种UI和功能的需求。所以oksimple也只是提供了多文件下载的能力,具体实现需要自己编码处理。

关于多线程分段下载

有用我这个框架的一些朋友让我像别的下载框架一样,加上多线程分段下载。我感到很奇怪,问他用这个功能干嘛。他说他的项目里,需要从服务器下载一些资源文件或者安装包,分段下载可能会快一些。我说如果你用Oksimple只是从你服务器上下载东西,那多线程分段下载其实完全没有必要。因为你服务器的带宽是固定的,在单线程情况下,假设100M带宽,10个人下,每个人分到1M。假设现在每个人都开了两个线程下载,那么100M带宽,假设依然保证每个人1M的下载速率,那么只够分5个人。回到多线程,我认为移动端进行自己服务器的多线程下载,很多时候是没有必要的。多线程分段下载适合迅雷这样的,通过稳定的宽带从非自己服务器下载。但Oksimple本来就是基于android这样的移动平台,不适合做成迅雷这样的。所以我并有在Oksimple里加入多线程分段下载。

glide图片加载进度监听

效果如图:

入口类在这里。这里主要讲如何实现gif图里那样的加载效果。如果你看源代码的话,你会发现GlideCallBack是一个空方法。这是因为Oksimple本质是一个网络请求的框架, 不会考虑引入glide等其他库,所以我只是返回了一个重写了responsebody的okhttpclient。因为实现okhttp接入glide获取图片加载进度的思路其实很简单。具体可以参考项目中的代码,要测试的话,把代码里填url的地方替换一下即可。 至于具体使用过程中,如何封装,我的demo也仅供参考。

⚠️ **GitHub.com Fallback** ⚠️