├── .gitignore ├── .idea ├── .name ├── compiler.xml ├── gradle.xml ├── misc.xml └── vcs.xml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── yujing │ │ └── test │ │ └── ExampleInstrumentedTest.kt │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ ├── yujing │ │ │ └── test │ │ │ │ ├── App.kt │ │ │ │ ├── activity │ │ │ │ └── MainActivity.kt │ │ │ │ └── bean │ │ │ │ ├── FarmersInfo.kt │ │ │ │ ├── UU.kt │ │ │ │ ├── User.kt │ │ │ │ └── YResponse.java │ │ │ └── yutils │ │ │ └── view │ │ │ ├── WarpLinearLayout.java │ │ │ └── utils │ │ │ └── Create.kt │ └── res │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ └── ic_launcher_background.xml │ │ ├── layout │ │ └── activity_all_test.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ │ └── xml │ │ ├── network_config.xml │ │ └── provider_paths.xml │ └── test │ └── java │ └── com │ └── yujing │ └── test │ ├── ExampleUnitTest.kt │ ├── User.kt │ └── YHttpTest.java ├── build.gradle ├── doc └── logcat.png ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── yhttp ├── .gitignore ├── build.gradle └── src └── main └── java └── com └── yutils └── http ├── Android.java ├── YHttp.java ├── YHttpBase.java ├── YHttpThreadPool.java ├── YHttpURLConnectionFactory.java ├── YHttpUtils.java ├── contract ├── ObjectListener.java ├── YFailListener.java ├── YHttpDownloadFileListener.java ├── YHttpListener.java ├── YHttpLoadListener.java ├── YHttpProgressListener.java ├── YObjectListener.java ├── YSessionListener.java └── YSuccessListener.java └── model └── Upload.java /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea 5 | .DS_Store 6 | /build 7 | /captures 8 | .externalNativeBuild 9 | .cxx 10 | /gradles/ 11 | -------------------------------------------------------------------------------- /.idea/.name: -------------------------------------------------------------------------------- 1 | utils_yhttp -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 20 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 10 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # YHttp网络请求,原生JAVA实现,小巧快速 2 | ## 支持原生java工程,原生kotlin工程,安卓工程。 3 | ### 优点: 4 | > * 1.支持get,post,put,delete请求,一行实现同步请求,一行实现异步请求 5 | > * 2.post请求可为字符串,map,byte[] 6 | > * 3.直接返回请求结果为 字符串 或 对象 或 byte[] 7 | > * 4.支持各种格式文件下载,回调进度条 8 | > * 5.单次文件上传请求中可以包含多种不同格式文件 9 | > * 6.日志详细记录请求数据和结果,可关闭日志,异常请求回调异常原因 10 | > * 7.支持https,支持设置ssl文件 11 | > * 8.sessionID的获取和设置,可以切换多个不同sessionID 12 | > * 9.简单好用,作者持续更新 13 | > * 10.支持安卓,请求结果直接回调到UI线程(主线程) 14 | > * 11.自定义gson,如:可以直接序列化指定日期格式的内容 15 | > * 12.链式调用,代码更加简洁,可以不监听失败回调 16 | > * 13.返回数据在logcat中清晰可见,并且可以直接返回对象 17 | 18 | 采用java17,安卓13.0,API33,androidx。 19 | 20 | # 建议大家使用OKHTTP 21 | 22 | ## Gradle采用java17!!! java17!!!java17!!! 23 | 24 | ### 设置方法: Project Structure ----> SDK Location ----> JDK location was moved to Gradle Settings. ----> Gradle JDK ----> JDK17 25 | 26 | #### 返回数据调试清晰可见,超长json自动分段打印logcat 27 | ![logcat](doc/logcat.png) 28 | 29 | [![platform](https://img.shields.io/badge/platform-Android-lightgrey.svg)](https://developer.android.google.cn/studio/index.html) 30 | ![Gradle](https://img.shields.io/badge/Gradle-7.5.1-brightgreen.svg) 31 | [![last commit](https://img.shields.io/github/last-commit/yutils/yhttp.svg)](https://github.com/yutils/yhttp/commits/master) 32 | ![repo size](https://img.shields.io/github/repo-size/yutils/yhttp.svg) 33 | ![android studio](https://img.shields.io/badge/android%20studio-2021.3.1-green.svg) 34 | [![maven](https://img.shields.io/badge/maven-address-green.svg)](https://search.maven.org/artifact/com.kotlinx/yhttp) 35 | 36 | ## 已经从jitpack.io仓库移动至maven中央仓库 37 | 38 | **[releases里面有JAR包。点击前往](https://github.com/yutils/yhttp/releases)** 39 | 40 | ## Gradle 引用 41 | 42 | [添加依赖,当前最新版:————> 1.1.4    ![最新版](https://img.shields.io/badge/%E6%9C%80%E6%96%B0%E7%89%88-1.1.4-green.svg)](https://search.maven.org/artifact/com.kotlinx/yhttp) 43 | 44 | ``` 45 | dependencies { 46 | //更新地址 https://github.com/yutils/yhttp 建议过几天访问看下有没有新版本 47 | implementation 'com.kotlinx:yhttp:1.1.4' 48 | } 49 | ``` 50 | 51 | 注:如果引用失败,看下面方案 52 | ``` 53 | allprojects { 54 | repositories { 55 | //google() 56 | //mavenCentral() 57 | 58 | //阿里云镜像 59 | maven { url 'https://maven.aliyun.com/repository/public' } 60 | maven { url 'https://maven.aliyun.com/repository/google' } 61 | 62 | //如果还是不容易拉取,可以试试直接用maven.org 63 | maven { url 'https://repo1.maven.org/maven2' } 64 | } 65 | ``` 66 | ## 用法举例: 67 | 1.java工程中,异步请求,YHttp返回结果在子线程 68 | 2.安卓工程中,异步请求,如果在UI线程(主线程)中创建YHttp,将返回结果返回到UI线程(主线程) 69 | 70 | ## 链式请求举例 71 | ``` java 72 | //链式请求 java 73 | String url = "http://192.168.6.9:8090/crash/user/login"; 74 | Map hashMap = new HashMap();// = hashMapOf("name" to "yujing", "password" to "wtugeqh") 75 | hashMap.put("name", "yujing"); 76 | hashMap.put("password", "wtugeqh"); 77 | YHttp.create() 78 | .url(url) 79 | .post(hashMap) 80 | .setSuccessListener((bytes, value) -> { 81 | System.out.println("请求成功:" + value); 82 | }).start(); 83 | 84 | //链式,get 85 | YHttp 86 | .create() 87 | .url("http://192.168.6.9:8090/crash/") 88 | .get() 89 | .setSuccessListener { bytes, value -> textView1.text = "成功:$value" } 90 | .setFailListener { value -> textView2.text = "失败:$value" } 91 | .start() 92 | 93 | //链式,post 94 | val url = "http://192.168.6.9:8090/crash/user/login" 95 | val gson=YJson.getGsonDate( "yyyy年MM月dd日 HH:mm:ss") 96 | val hashMap: HashMap = hashMapOf("name" to "yujing", "password" to "wtugeqh") 97 | YHttp.create() 98 | .url(url) 99 | .post(hashMap) 100 | .setGson(gson) 101 | .setObjectListener(object : ObjectListener() { 102 | override fun success(bytes: ByteArray?, value: User?) { 103 | textView2.text = "\n对象:${value.toString()}" 104 | } 105 | }) 106 | .setFailListener { value -> textView2.text = "失败:$value" } 107 | .start() 108 | 109 | //链式,自定义请求 110 | YHttp.create() 111 | .url(url) 112 | .method("POST") 113 | .setContentType("application/x-www-form-urlencoded;charset=utf-8") 114 | .addRequestProperty("connection", "Keep-Alive") 115 | .body(hashMap) 116 | .setGson(gson) 117 | .setSessionId(session) 118 | .setCrtSSL("SSL证书内容") 119 | .setSuccessListener { bytes, value -> textView1.text = "成功:$value" } 120 | .setObjectListener(object : ObjectListener() { 121 | override fun success(bytes: ByteArray?, value: User?) { 122 | textView2.text = "\n对象:${value.toString()}" 123 | } 124 | }) 125 | .setFailListener { value -> textView2.text = "失败:$value" } 126 | .setSessionListener { sessionId -> session = sessionId } 127 | .start() 128 | ``` 129 | 130 | ## java举例 131 | ``` java 132 | String url = "http://www.xxx.xxx/xxx"; 133 | 134 | //同步请求get 135 | YHttpBase yHttp = new YHttpBase().setConnectTimeout(3000).setContentType("application/json; charset=utf-8"); 136 | String json = new String(yHttp.get(url), StandardCharsets.UTF_8); 137 | 138 | //同步请求post 139 | String json = new String(yHttp.post(url,"id=123&name=123".getBytes()), StandardCharsets.UTF_8); 140 | 141 | //————————————————异步请求———————————————— 142 | 143 | //定义地址 144 | String url="http://www.xxx.xxx/getUser"; 145 | //请求参数 146 | HashMap paramsMap=new HashMap<>(); 147 | paramsMap.put("id","123"); 148 | 149 | //异步请求,返回字符串,如是安卓项目返回值自动回到主线程,监听设置成YHttpListener就返回字符串,监听设置成YObjectListener就返回对象 150 | YHttp.create().post(url, paramsMap, new YHttpListener() { 151 | @Override 152 | public void success(byte[] bytes, String value) throws Exception { 153 | //请求结果,文本 154 | } 155 | @Override 156 | public void fail(String value) { 157 | //错误原因 158 | } 159 | }); 160 | 161 | 162 | //异步请求,返回返回对象,如是安卓项目返回值自动回到主线程,监听设置成YHttpListener就返回字符串,监听设置成YObjectListener就返回对象 163 | YHttp.create().post(url, paramsMap, new YObjectListener() { 164 | @Override 165 | public void success(byte[] bytes, User value) { 166 | //请求结果,对象 167 | } 168 | @Override 169 | public void fail(String value) { 170 | //错误原因 171 | } 172 | }); 173 | 174 | 175 | //java文件上传,如是安卓项目返回值自动回到主线程,监听设置成YHttpListener就返回字符串,监听设置成YObjectListener就返回对象 176 | String url = "http://192.168.6.9:8090/crash/upload/file"; 177 | List uploads = new ArrayList<>(); 178 | uploads.add(new Upload("file1", new File("D:/1.jpg"))); 179 | uploads.add(new Upload("file2", "ABCDEF".getBytes()).setFilename("abcd.txt")); 180 | 181 | YHttp.create().setSessionId(session).upload(url, "", uploads, new YHttpListener() { 182 | @Override 183 | public void success(byte[] bytes, String value){ 184 | System.out.println("上传成功:" + value); 185 | } 186 | @Override 187 | public void fail(String value) { 188 | System.out.println("上传失败:" + value); 189 | } 190 | }); 191 | 192 | 193 | //文件下载,如是安卓项目返回值自动回到主线程 194 | String url = "https://down.qq.com/qqweb/PCQQ/PCQQ_EXE/PCQQ2020.exe"; 195 | File f = new File( "D:/QQ.exe"); 196 | YHttp.create().downloadFile(url, f, new YHttpDownloadFileListener (){ 197 | @Override 198 | public void progress(int downloadSize, int fileSize) { 199 | double progress = ((int)(10000.0 * downloadSize / fileSize))/100.0;//下载进度,保留2位小数 200 | } 201 | @Override 202 | public void success(File file) { 203 | //下载完成 204 | } 205 | @Override 206 | public void fail(String value) { 207 | //下载失败 208 | } 209 | }); 210 | ``` 211 | 212 | ## kotlin举例 213 | ``` kotlin 214 | 215 | //当前session值 216 | var session = "" 217 | //请求地址 218 | val url = "http://www.xxx.xxx/xxx" 219 | //请求参数 220 | val hashMap: HashMap = hashMapOf("name" to "abc", "password" to "123456") 221 | 222 | //post请求。保存sessionId,如登录,如是安卓项目返回值自动回到主线程,监听设置成YHttpListener就返回字符串,监听设置成YObjectListener就返回对象 223 | YHttp.create().setSessionListener { sessionId ->session = sessionId }.post(url, hashMap, object : YHttpListener { 224 | override fun success(bytes: ByteArray?, value: String?) { 225 | //成功 226 | } 227 | override fun fail(value: String?) { 228 | //失败 229 | } 230 | }) 231 | 232 | 233 | //请求返回对象,带上sessionId,如业务操作,如是安卓项目返回值自动回到主线程,监听设置成YHttpListener就返回字符串,监听设置成YObjectListener就返回对象 234 | YHttp.create().setSessionId(session).post(url, map, object : YObjectListener() { 235 | override fun success(bytes: ByteArray?, value: User?) { 236 | runOnUiThread(Runnable { 237 | YToast.show(App.get(), value?.Name) 238 | }) 239 | } 240 | override fun fail(value: String) { 241 | runOnUiThread(Runnable { 242 | YToast.show(App.get(), value) 243 | }) 244 | } 245 | }) 246 | 247 | 248 | //文件上传,并且上次参数请求,如是安卓项目返回值自动回到主线程,监听设置成YHttpListener就返回字符串,监听设置成YObjectListener就返回对象 249 | val url = "http://192.168.6.9:8090/crash/upload/file" 250 | val params: HashMap = hashMapOf("name" to "yujing", "password" to "123456") 251 | val list: MutableList = ArrayList() 252 | list.add(Upload("file1",file)) 253 | list.add(Upload("file2", "ABCDEF".toByteArray()).setFilename("abcd.txt")) 254 | list.add(Upload("file3",bitmap)) 255 | //请求 256 | YHttp.create().setSessionId(session).upload(url, params, list, object : YHttpListener { 257 | override fun success(bytes: ByteArray?, value: String?) { 258 | //成功 259 | } 260 | override fun fail(value: String?) { 261 | //失败 262 | } 263 | }) 264 | 265 | 266 | //文件下载,如是安卓项目返回值自动回到主线程 267 | val url = "https://down.qq.com/qqweb/PCQQ/PCQQ_EXE/PCQQ2020.exe" 268 | //保存路径 269 | var f = File( "D:/BB.exe") 270 | //请求 271 | YHttp.create().downloadFile(url, f, object : 272 | YHttpDownloadFileListener { 273 | override fun progress(downloadSize: Int, fileSize: Int) { 274 | val progress = (10000.0 * downloadSize / fileSize).toInt() / 100.0 //下载进度,保留2位小数 275 | } 276 | override fun success(file: File) {}//下载完成 277 | override fun fail(value: String) {}//下载出错 278 | }) 279 | ``` 280 | 281 | ## 如安卓中使用注意添加权限: 282 | > * 必须权限         ——>     android.permission.INTERNET 283 | > * 返回对象必须引用Gson   ——>     implementation 'com.google.code.gson:gson:2.8.6' 284 | 285 | Github地址:[https://github.com/yutils/yhttp](https://github.com/yutils/yhttp) 286 | 287 | 我的CSDN:[https://blog.csdn.net/Yu1441](https://blog.csdn.net/Yu1441) 288 | 289 | 感谢关注微博:[细雨若静](https://weibo.com/32005200) -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.android.application' 3 | id 'org.jetbrains.kotlin.android' 4 | id 'kotlin-kapt' 5 | id 'kotlin-parcelize' 6 | } 7 | android { 8 | compileSdk 33 9 | namespace 'com.yujing.test' 10 | defaultConfig { 11 | applicationId "com.yujing.test" 12 | minSdk 19 13 | targetSdk 33 14 | versionCode 14 15 | versionName "1.1.4" 16 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 17 | } 18 | buildTypes { 19 | release { 20 | minifyEnabled false 21 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 22 | } 23 | } 24 | compileOptions { 25 | sourceCompatibility JavaVersion.VERSION_17 26 | targetCompatibility JavaVersion.VERSION_17 27 | } 28 | buildFeatures { 29 | dataBinding = true 30 | } 31 | kotlinOptions { 32 | jvmTarget = '17' 33 | } 34 | } 35 | dependencies { 36 | implementation fileTree(dir: 'libs', include: ['*.jar']) 37 | implementation 'androidx.appcompat:appcompat:1.6.1' 38 | implementation 'androidx.core:core-ktx:1.10.0' 39 | implementation 'androidx.constraintlayout:constraintlayout:2.1.4' 40 | testImplementation 'junit:junit:4.13.2' 41 | androidTestImplementation 'androidx.test.ext:junit:1.1.5' 42 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' 43 | implementation('com.kotlinx:yutils:2.1.7') { 44 | exclude group: 'com.kotlinx', module: 'yhttp' 45 | } 46 | //关联lib 47 | implementation project(':yhttp') 48 | //gson 49 | implementation 'com.google.code.gson:gson:2.10.1' 50 | } 51 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/yujing/test/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package com.yujing.test 2 | 3 | import androidx.test.platform.app.InstrumentationRegistry 4 | import androidx.test.ext.junit.runners.AndroidJUnit4 5 | 6 | import org.junit.Test 7 | import org.junit.runner.RunWith 8 | 9 | import org.junit.Assert.* 10 | 11 | /** 12 | * Instrumented test, which will execute on an Android device. 13 | * 14 | * See [testing documentation](http://d.android.com/tools/testing). 15 | */ 16 | @RunWith(AndroidJUnit4::class) 17 | class ExampleInstrumentedTest { 18 | @Test 19 | fun useAppContext() { 20 | // Context of the app under test. 21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext 22 | assertEquals("com.yujing.test", appContext.packageName) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 34 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /app/src/main/java/com/yujing/test/App.kt: -------------------------------------------------------------------------------- 1 | package com.yujing.test 2 | 3 | import android.app.Application 4 | import com.yujing.utils.YUtils 5 | 6 | class App : Application() { 7 | //标准单列 8 | // companion object { 9 | // val instance: App by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {App()} 10 | // } 11 | //单列 12 | companion object { 13 | private var instance: App? = null 14 | get() { 15 | if (field == null) field = App() 16 | return field 17 | } 18 | 19 | @Synchronized 20 | fun get(): App { 21 | return instance!! 22 | } 23 | } 24 | 25 | override fun onCreate() { 26 | super.onCreate() 27 | instance = this 28 | YUtils.init(this) 29 | } 30 | } -------------------------------------------------------------------------------- /app/src/main/java/com/yujing/test/activity/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.yujing.test.activity 2 | 3 | import android.content.Intent 4 | import android.widget.TextView 5 | import com.google.gson.Gson 6 | import com.yujing.base.YBaseActivity 7 | import com.yujing.test.R 8 | import com.yujing.test.bean.UU 9 | import com.yujing.test.bean.User 10 | import com.yujing.test.databinding.ActivityAllTestBinding 11 | import com.yujing.utils.* 12 | import com.yutils.http.YHttp 13 | import com.yutils.http.contract.ObjectListener 14 | import com.yutils.http.contract.YHttpDownloadFileListener 15 | import com.yutils.http.contract.YHttpListener 16 | import com.yutils.http.contract.YObjectListener 17 | import com.yutils.http.model.Upload 18 | import com.yutils.view.utils.Create 19 | import java.io.File 20 | 21 | 22 | class MainActivity : YBaseActivity(R.layout.activity_all_test) { 23 | lateinit var textView1: TextView 24 | lateinit var textView2: TextView 25 | val gson = YJson.getGsonDate("yyyy年MM月dd日 HH:mm:ss") 26 | override fun init() { 27 | YPermissions.requestAll(this) 28 | binding.wll.removeAllViews() 29 | binding.ll.removeAllViews() 30 | textView1 = Create.textView(binding.ll) 31 | textView2 = Create.textView(binding.ll) 32 | Create.button(binding.wll, "登录获取session") { 33 | net1() 34 | } 35 | Create.button(binding.wll, "获取用户信息") { 36 | Thread { 37 | net2() 38 | }.start() 39 | } 40 | Create.button(binding.wll, "链式-登录") { 41 | net4() 42 | } 43 | Create.button(binding.wll, "链式-获取信息") { 44 | net5() 45 | } 46 | Create.button(binding.wll, "拍照上传图片") { 47 | netUp() 48 | } 49 | Create.button(binding.wll, "App更新") { 50 | update() 51 | } 52 | Create.button(binding.wll, "文件下载") { 53 | downLoad() 54 | } 55 | Create.button(binding.wll, "终止下载") { 56 | downLoadStop() 57 | } 58 | } 59 | 60 | //登录并保存session 61 | var session = "" 62 | private fun net1() { 63 | val url = "http://192.168.6.9:8090/crash/user/login" 64 | val hashMap: HashMap = hashMapOf("name" to "yujing", "password" to "wtugeqh") 65 | YHttp.create().setSessionListener { sessionId -> 66 | session = sessionId 67 | textView1.text = "sessionId:$sessionId" 68 | }.post(url, hashMap, object : YHttpListener { 69 | override fun success(bytes: ByteArray?, value: String?) { 70 | textView2.text = "成功:$value" 71 | } 72 | 73 | override fun fail(value: String?) { 74 | textView2.text = "失败:$value" 75 | } 76 | }) 77 | } 78 | 79 | //获取用户信息 80 | private fun net2() { 81 | val url = "http://192.168.6.9:8090/crash/" 82 | YHttp.create().setGson(gson).setSessionId(session) 83 | .get(url, object : YObjectListener() { 84 | override fun success(bytes: ByteArray?, value: User?) { 85 | textView2.text = "\n对象:${value.toString()}" 86 | } 87 | 88 | override fun fail(value: String?) { 89 | textView2.text = "失败:$value" 90 | } 91 | }) 92 | } 93 | 94 | private fun 链式全部设置() { 95 | val url = "http://192.168.6.9:8090/crash/user/login" 96 | val gson = YJson.getGsonDate("yyyy年MM月dd日 HH:mm:ss") 97 | val hashMap: HashMap = hashMapOf("name" to "yujing", "password" to "wtugeqh") 98 | YHttp.create() 99 | .url(url) 100 | .method("POST") 101 | .setContentType("application/x-www-form-urlencoded;charset=utf-8") 102 | .addRequestProperty("connection", "Keep-Alive") 103 | .body(hashMap) 104 | .setGson(gson) 105 | .setSessionId(session) 106 | .setCrtSSL("SSL证书内容") 107 | .setSuccessListener { bytes, value -> textView1.text = "成功:$value" } 108 | .setObjectListener(object : ObjectListener() { 109 | override fun success(bytes: ByteArray?, value: User?) { 110 | textView2.text = "对象:${value.toString()} \n转换成json:${Gson().toJson(value)}" 111 | } 112 | }) 113 | .setFailListener { value -> textView2.text = "失败:$value" } 114 | .setSessionListener { sessionId -> session = sessionId } 115 | .start() 116 | } 117 | 118 | private fun net4() { 119 | val url = "http://192.168.6.9:8090/crash/user/login" 120 | val gson = YJson.getGsonDate("yyyy年MM月dd日 HH:mm:ss") 121 | val hashMap: HashMap = hashMapOf("name" to "yujing", "password" to "wtugeqh") 122 | YHttp.create() 123 | .url(url) 124 | .post(hashMap) 125 | .setGson(gson) 126 | .setSessionId(session) 127 | .setSuccessListener { bytes, value -> textView1.text = "成功:$value" } 128 | .setObjectListener(object : ObjectListener() { 129 | override fun success(bytes: ByteArray?, value: User?) { 130 | textView2.text = "\n对象:${value.toString()}" 131 | } 132 | }) 133 | .setFailListener { value -> textView2.text = "失败:$value" } 134 | .setSessionListener { sessionId -> session = sessionId } 135 | .start() 136 | } 137 | 138 | private fun net5() { 139 | val gson = YJson.getGsonDate("yyyy年MM月dd日 HH:mm:ss") 140 | YHttp.create() 141 | .url("http://192.168.6.9:8090/crash/") 142 | .get() 143 | .setGson(gson) 144 | .setSessionId(session) 145 | .setSuccessListener { bytes, value -> textView1.text = "成功:$value" } 146 | .setObjectListener(object : ObjectListener() { 147 | override fun success(bytes: ByteArray?, value: User?) { 148 | textView2.text = "\n对象:${value.toString()}" 149 | } 150 | }) 151 | .setFailListener { value -> textView2.text = "失败:$value" } 152 | .start() 153 | } 154 | 155 | //长传图片,并且上次参数请求 156 | private val yPicture: YPicture = YPicture() 157 | private fun netUp() { 158 | yPicture.gotoCamera(this) 159 | yPicture.setPictureFromCameraListener { uri, file, Flag -> 160 | var bitmap = YConvert.uri2Bitmap(this, uri) 161 | // YShow.show(this, "正在上传") 162 | // val url = "http://192.168.6.9:8090/crash/upload/file" 163 | // val params: HashMap = hashMapOf("name" to "yujing", "password" to "123456") 164 | // val list: MutableList = ArrayList() 165 | // list.add(Upload("file1", file)) 166 | // list.add(Upload("file2", "ABCDEF".toByteArray()).setFilename("abcd.txt")) 167 | // list.add(Upload("file3", bitmap)) 168 | // 169 | // //文件上传 170 | // YHttp.create().setSessionId(session) 171 | // .upload(url, params, list, object : YObjectListener() { 172 | // override fun success(bytes: ByteArray?, value: UU?) { 173 | // YShow.finish() 174 | // text2.text = value.toString() 175 | // } 176 | // 177 | // override fun fail(value: String?) { 178 | // YShow.finish() 179 | // text2.text = "失败:$value" 180 | // } 181 | // }) 182 | 183 | 184 | val list: MutableList = ArrayList() 185 | list.add(Upload("file", bitmap)) 186 | YShow.show(this, "正在上传...", "身份证正面照") 187 | YHttp.create().setSessionId(session) 188 | .setRequestProperty("X-Session-Token", "4ea64bef2bb54a5fbbe3c8e28da8b92a") 189 | .upload( 190 | "http://152.136.213.28:8008/garbage/app/idNum/imgUrl", 191 | "", 192 | list, 193 | object : YObjectListener() { 194 | override fun success(bytes: ByteArray?, value: UU?) { 195 | YShow.finish() 196 | textView2.text = value.toString() 197 | } 198 | 199 | override fun fail(value: String?) { 200 | YShow.finish() 201 | textView2.text = "失败:$value" 202 | } 203 | }) 204 | 205 | // val paramsMap = HashMap() 206 | // val uploadImg = HashMap() 207 | // bitmap=YBitmapUtil.zoom(bitmap,540,960) 208 | // uploadImg["file"] = bitmap 209 | // YnetAndroid.uploadBitmap( 210 | // "http://152.136.213.28:8008/garbage/app/idNum/imgUrl", paramsMap, uploadImg, 211 | // object : Ynet.YnetListener { 212 | // override fun success(value: String?) { 213 | // YLog.d(value) 214 | // } 215 | // 216 | // override fun fail(value: String?) { 217 | // YLog.d(value) 218 | // } 219 | // } 220 | // ) 221 | } 222 | } 223 | 224 | private var yVersionUpdate: YVersionUpdate? = null 225 | private fun update() { 226 | val url = "https://down.qq.com/qqweb/QQ_1/android_apk/AndroidQQ_8.4.5.4745_537065283.apk" 227 | YLog.i("url:$url") 228 | yVersionUpdate = YVersionUpdate() 229 | yVersionUpdate?.update(20, false, url, "1.9.99", "\n修复了bug1引起的问题\n新增功能:aaa") 230 | } 231 | 232 | private var download = YHttp.create() 233 | private fun downLoad() { 234 | textView1.text = "开始下载" 235 | val url = "https://down.qq.com/qqweb/PCQQ/PCQQ_EXE/PCQQ2020.exe" 236 | var f = File(YPath.getFilePath(this, "download") + "/qq.exe") 237 | 238 | download.downloadFile(url, f, object : YHttpDownloadFileListener { 239 | override fun progress(downloadSize: Int, fileSize: Int) { 240 | val progress = (10000.0 * downloadSize / fileSize).toInt() / 100.0 //下载进度,保留2位小数 241 | textView1.text = "$downloadSize/$fileSize" 242 | textView2.text = "进度:$progress%" 243 | } 244 | 245 | override fun success(file: File) { 246 | textView2.text = "下载完成" 247 | } 248 | 249 | override fun fail(value: String) { 250 | textView2.text = value 251 | } 252 | }) 253 | } 254 | 255 | private fun downLoadStop() { 256 | download.downloadFileStop() 257 | } 258 | 259 | override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { 260 | super.onActivityResult(requestCode, resultCode, data) 261 | yPicture.onActivityResult(requestCode, resultCode, data) 262 | } 263 | 264 | override fun onDestroy() { 265 | super.onDestroy() 266 | yVersionUpdate?.onDestroy() 267 | } 268 | } -------------------------------------------------------------------------------- /app/src/main/java/com/yujing/test/bean/FarmersInfo.kt: -------------------------------------------------------------------------------- 1 | package com.yujing.test.bean 2 | 3 | /** 4 | * 烟农信息 5 | */ 6 | /* 7 | 字段 名称 类型 8 | Command 命令码 int 9 | MsgId 消息Id int 10 | YDMC 烟点名称 string 11 | YDBM 烟点编码 string 12 | Name 烟农名称 string 13 | HTH 合同号 string 14 | YHKH 银行卡号 string 15 | YYPZ 烟叶品种 string 16 | HTZL 合同总量 decimal 17 | YJZL 已交重量 decimal 18 | YL 余量 decimal 19 | JTDZ 家庭地址 string 20 | ZZMJ 种值面积 decimal 21 | SFZ 身份证号 string 22 | KFH 开户行 string 23 | */ 24 | class FarmersInfo { 25 | var Command = 0 //命令码 26 | var MsgId = 0//消息Id 27 | var YDMC: String? = null//烟点名称 28 | var YDBM: String? = null//烟点编码 29 | var Name: String? = null//烟农名称 30 | var HTH: String? = null//合同号 31 | var YHKH: String? = null//银行卡号 32 | var YYPZ: String? = null//烟叶品种 33 | var HTZL = 0.0//合同总量 34 | var YJZL = 0.0//已交重量 35 | var YL = 0//余量 36 | var JTDZ: String? = null//家庭地址 37 | var ZZMJ = 0//种值面积 38 | var SFZ: String? = null//身份证号 39 | var KFH: String? = null//开户行 40 | } -------------------------------------------------------------------------------- /app/src/main/java/com/yujing/test/bean/UU.kt: -------------------------------------------------------------------------------- 1 | package com.yujing.test.bean 2 | 3 | data class UU( 4 | val code: Int, 5 | val `data`: List, 6 | val message: String 7 | ) 8 | 9 | data class Data( 10 | val absoluteUrl: String, 11 | val filePath: String, 12 | val relativeUrl: String 13 | ) -------------------------------------------------------------------------------- /app/src/main/java/com/yujing/test/bean/User.kt: -------------------------------------------------------------------------------- 1 | package com.yujing.test.bean 2 | 3 | import java.util.* 4 | 5 | data class User( 6 | val code: Int, 7 | val data: DD?, 8 | val message: String 9 | ) 10 | 11 | data class DD( 12 | val 可用内存: String, 13 | val 已使用内存: String, 14 | val 服务器时间: Date, 15 | val 用户: 用户? 16 | ) 17 | 18 | data class 用户( 19 | val createTime: Date, 20 | val endLoginTime: Date, 21 | val id: Int, 22 | val name: String, 23 | val nickName: String, 24 | val phone: String 25 | ) -------------------------------------------------------------------------------- /app/src/main/java/com/yujing/test/bean/YResponse.java: -------------------------------------------------------------------------------- 1 | package com.yujing.test.bean; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | *

7 | * 返回结果封装类 8 | * @author yujing 2019年11月21日15:09:51 9 | *

10 | */ 11 | public class YResponse implements Serializable { 12 | 13 | private int ResultType; 14 | private String Msg; 15 | private int ErrorCode; 16 | private String ErrorMsg; 17 | private T Data; 18 | 19 | public int getResultType() { 20 | return ResultType; 21 | } 22 | 23 | public void setResultType(int resultType) { 24 | ResultType = resultType; 25 | } 26 | 27 | public String getMsg() { 28 | return Msg; 29 | } 30 | 31 | public void setMsg(String msg) { 32 | Msg = msg; 33 | } 34 | 35 | public int getErrorCode() { 36 | return ErrorCode; 37 | } 38 | 39 | public void setErrorCode(int errorCode) { 40 | ErrorCode = errorCode; 41 | } 42 | 43 | public String getErrorMsg() { 44 | return ErrorMsg; 45 | } 46 | 47 | public void setErrorMsg(String errorMsg) { 48 | ErrorMsg = errorMsg; 49 | } 50 | 51 | public T getData() { 52 | return Data; 53 | } 54 | 55 | public void setData(T data) { 56 | Data = data; 57 | } 58 | 59 | @Override 60 | public String toString() { 61 | return "YResponse{" + 62 | "ResultType=" + ResultType + 63 | ", Msg='" + Msg + '\'' + 64 | ", ErrorCode=" + ErrorCode + 65 | ", ErrorMsg='" + ErrorMsg + '\'' + 66 | ", Data=" + Data + 67 | '}'; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /app/src/main/java/com/yutils/view/WarpLinearLayout.java: -------------------------------------------------------------------------------- 1 | package com.yutils.view; 2 | 3 | 4 | import android.content.Context; 5 | import android.content.res.TypedArray; 6 | import android.util.AttributeSet; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | 10 | import com.yujing.test.R; 11 | 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | 15 | /** 16 | * 瀑布流布局 17 | */ 18 | public class WarpLinearLayout extends ViewGroup { 19 | private Type mType; 20 | private List mWarpLineGroup; 21 | 22 | public WarpLinearLayout(Context context) { 23 | this(context, null); 24 | } 25 | 26 | public WarpLinearLayout(Context context, AttributeSet attrs) { 27 | this(context, attrs, R.style.WarpLinearLayoutDefault); 28 | } 29 | 30 | public WarpLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) { 31 | super(context, attrs, defStyleAttr); 32 | mType = new Type(context, attrs); 33 | } 34 | 35 | @Override 36 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 37 | int withMode = MeasureSpec.getMode(widthMeasureSpec); 38 | int withSize = MeasureSpec.getSize(widthMeasureSpec); 39 | int heightMode = MeasureSpec.getMode(heightMeasureSpec); 40 | int heightSize = MeasureSpec.getSize(heightMeasureSpec); 41 | int with = 0; 42 | int height = 0; 43 | int childCount = getChildCount(); 44 | /** 45 | * 在调用childView。getMeasre之前必须先调用该行代码,用于对子View大小的测量 46 | */ 47 | measureChildren(widthMeasureSpec, heightMeasureSpec); 48 | /** 49 | * 计算宽度 50 | */ 51 | switch (withMode) { 52 | case MeasureSpec.EXACTLY: 53 | //noinspection DuplicateBranchesInSwitch 54 | with = withSize; 55 | break; 56 | case MeasureSpec.AT_MOST: 57 | for (int i = 0; i < childCount; i++) { 58 | if (i != 0) { 59 | with += mType.horizontal_Space; 60 | } 61 | with += getChildAt(i).getMeasuredWidth(); 62 | } 63 | with += getPaddingLeft() + getPaddingRight(); 64 | with = Math.min(with, withSize); 65 | break; 66 | case MeasureSpec.UNSPECIFIED: 67 | for (int i = 0; i < childCount; i++) { 68 | if (i != 0) { 69 | with += mType.horizontal_Space; 70 | } 71 | with += getChildAt(i).getMeasuredWidth(); 72 | } 73 | with += getPaddingLeft() + getPaddingRight(); 74 | break; 75 | default: 76 | with = withSize; 77 | break; 78 | 79 | } 80 | /** 81 | * 根据计算出的宽度,计算出所需要的行数 82 | */ 83 | WarpLine warpLine = new WarpLine(); 84 | /** 85 | * 不能够在定义属性时初始化,因为onMeasure方法会多次调用 86 | */ 87 | mWarpLineGroup = new ArrayList<>(); 88 | for (int i = 0; i < childCount; i++) { 89 | if (warpLine.lineWidth + getChildAt(i).getMeasuredWidth() + mType.horizontal_Space > with) { 90 | if (warpLine.lineView.size() == 0) { 91 | warpLine.addView(getChildAt(i)); 92 | mWarpLineGroup.add(warpLine); 93 | warpLine = new WarpLine(); 94 | } else { 95 | mWarpLineGroup.add(warpLine); 96 | warpLine = new WarpLine(); 97 | warpLine.addView(getChildAt(i)); 98 | } 99 | } else { 100 | warpLine.addView(getChildAt(i)); 101 | } 102 | } 103 | /** 104 | * 添加最后一行 105 | */ 106 | if (warpLine.lineView.size() > 0 && !mWarpLineGroup.contains(warpLine)) { 107 | mWarpLineGroup.add(warpLine); 108 | } 109 | /** 110 | * 计算宽度 111 | */ 112 | height = getPaddingTop() + getPaddingBottom(); 113 | for (int i = 0; i < mWarpLineGroup.size(); i++) { 114 | if (i != 0) { 115 | height += mType.vertical_Space; 116 | } 117 | height += mWarpLineGroup.get(i).height; 118 | } 119 | switch (heightMode) { 120 | case MeasureSpec.EXACTLY: 121 | height = heightSize; 122 | break; 123 | case MeasureSpec.AT_MOST: 124 | height = Math.min(height, heightSize); 125 | break; 126 | case MeasureSpec.UNSPECIFIED: 127 | break; 128 | default: 129 | break; 130 | } 131 | setMeasuredDimension(with, height); 132 | } 133 | 134 | @Override 135 | protected void onLayout(boolean changed, int l, int t, int r, int b) { 136 | t = getPaddingTop(); 137 | for (int i = 0; i < mWarpLineGroup.size(); i++) { 138 | int left = getPaddingLeft(); 139 | WarpLine warpLine = mWarpLineGroup.get(i); 140 | int lastWidth = getMeasuredWidth() - warpLine.lineWidth; 141 | for (int j = 0; j < warpLine.lineView.size(); j++) { 142 | View view = warpLine.lineView.get(j); 143 | if (isFull()) {//需要充满当前行时 144 | view.layout(left, t, left + view.getMeasuredWidth() + lastWidth / warpLine.lineView.size(), t + view.getMeasuredHeight()); 145 | left += view.getMeasuredWidth() + mType.horizontal_Space + lastWidth / warpLine.lineView.size(); 146 | } else { 147 | switch (getGrivate()) { 148 | case 0://右对齐 149 | view.layout(left + lastWidth, t, left + lastWidth + view.getMeasuredWidth(), t + view.getMeasuredHeight()); 150 | break; 151 | case 2://居中对齐 152 | view.layout(left + lastWidth / 2, t, left + lastWidth / 2 + view.getMeasuredWidth(), t + view.getMeasuredHeight()); 153 | break; 154 | default://左对齐 155 | view.layout(left, t, left + view.getMeasuredWidth(), t + view.getMeasuredHeight()); 156 | break; 157 | } 158 | left += view.getMeasuredWidth() + mType.horizontal_Space; 159 | } 160 | } 161 | t += warpLine.height + mType.vertical_Space; 162 | } 163 | } 164 | 165 | /** 166 | * 用于存放一行子View 167 | */ 168 | private final class WarpLine { 169 | private List lineView = new ArrayList(); 170 | /** 171 | * 当前行中所需要占用的宽度 172 | */ 173 | private int lineWidth = getPaddingLeft() + getPaddingRight(); 174 | /** 175 | * 该行View中所需要占用的最大高度 176 | */ 177 | private int height = 0; 178 | 179 | private void addView(View view) { 180 | if (lineView.size() != 0) { 181 | lineWidth += mType.horizontal_Space; 182 | } 183 | height = Math.max(height, view.getMeasuredHeight()); 184 | lineWidth += view.getMeasuredWidth(); 185 | lineView.add(view); 186 | } 187 | } 188 | 189 | /** 190 | * 对样式的初始化 191 | */ 192 | private final static class Type { 193 | /* 194 | *对齐方式 right 0,left 1,center 2 195 | */ 196 | private int grivate; 197 | /** 198 | * 水平间距,单位px 199 | */ 200 | private float horizontal_Space; 201 | /** 202 | * 垂直间距,单位px 203 | */ 204 | private float vertical_Space; 205 | /** 206 | * 是否自动填满 207 | */ 208 | private boolean isFull; 209 | 210 | Type(Context context, AttributeSet attrs) { 211 | if (attrs == null) { 212 | return; 213 | } 214 | TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.WarpLinearLayout); 215 | grivate = typedArray.getInt(R.styleable.WarpLinearLayout_grivate, grivate); 216 | horizontal_Space = typedArray.getDimension(R.styleable.WarpLinearLayout_horizontal_Space, horizontal_Space); 217 | vertical_Space = typedArray.getDimension(R.styleable.WarpLinearLayout_vertical_Space, vertical_Space); 218 | isFull = typedArray.getBoolean(R.styleable.WarpLinearLayout_isFull, isFull); 219 | } 220 | } 221 | 222 | public int getGrivate() { 223 | return mType.grivate; 224 | } 225 | 226 | public float getHorizontal_Space() { 227 | return mType.horizontal_Space; 228 | } 229 | 230 | public float getVertical_Space() { 231 | return mType.vertical_Space; 232 | } 233 | 234 | public boolean isFull() { 235 | return mType.isFull; 236 | } 237 | 238 | public void setGrivate(int grivate) { 239 | mType.grivate = grivate; 240 | } 241 | 242 | public void setHorizontal_Space(float horizontal_Space) { 243 | mType.horizontal_Space = horizontal_Space; 244 | } 245 | 246 | public void setVertical_Space(float vertical_Space) { 247 | mType.vertical_Space = vertical_Space; 248 | } 249 | 250 | public void setIsFull(boolean isFull) { 251 | mType.isFull = isFull; 252 | } 253 | } -------------------------------------------------------------------------------- /app/src/main/java/com/yutils/view/utils/Create.kt: -------------------------------------------------------------------------------- 1 | package com.yutils.view.utils 2 | 3 | import android.graphics.Bitmap 4 | import android.view.Gravity 5 | import android.view.View 6 | import android.view.ViewGroup 7 | import android.widget.* 8 | import com.yujing.test.App 9 | import com.yujing.utils.YScreenUtil.dp2px 10 | 11 | /** 12 | * 动态创建view 13 | */ 14 | @Suppress("MemberVisibilityCanBePrivate") 15 | class Create { 16 | companion object { 17 | //动态创建Button 18 | fun button(name: String = "按钮", listener: View.OnClickListener): Button { 19 | val layoutParams = LinearLayout.LayoutParams( 20 | LinearLayout.LayoutParams.WRAP_CONTENT, 21 | LinearLayout.LayoutParams.WRAP_CONTENT 22 | ) 23 | val view = Button(App.get()) 24 | view.isAllCaps = false//不自动变大写 25 | name.let { view.text = it } 26 | view.layoutParams = layoutParams 27 | view.setOnClickListener(listener) 28 | return view 29 | } 30 | 31 | //动态创建Button 32 | fun button( 33 | linearLayout: ViewGroup?, name: String = "按钮", 34 | listener: View.OnClickListener 35 | ): Button { 36 | val view = button(name, listener) 37 | linearLayout?.addView(view) 38 | return view 39 | } 40 | 41 | //动态创建TextView 42 | fun textView(value: String? = null): TextView { 43 | val layoutParams = LinearLayout.LayoutParams( 44 | LinearLayout.LayoutParams.WRAP_CONTENT, 45 | LinearLayout.LayoutParams.WRAP_CONTENT 46 | ) 47 | val view = TextView(App.get()) 48 | value.let { view.text = it } 49 | view.layoutParams = layoutParams 50 | return view 51 | } 52 | 53 | //动态创建TextView 54 | fun textView(linearLayout: ViewGroup?, value: String? = null): TextView { 55 | val view = textView(value) 56 | linearLayout?.addView(view) 57 | return view 58 | } 59 | 60 | //动态创建EditText 61 | fun editText(value: String = ""): EditText { 62 | val layoutParams = LinearLayout.LayoutParams( 63 | LinearLayout.LayoutParams.WRAP_CONTENT, 64 | LinearLayout.LayoutParams.WRAP_CONTENT 65 | ) 66 | val view = EditText(App.get()) 67 | view.setText(value) 68 | view.hint = "在这儿输入内容" 69 | view.layoutParams = layoutParams 70 | return view 71 | } 72 | 73 | 74 | //动态创建EditText 75 | fun editText(linearLayout: ViewGroup?, value: String = ""): EditText { 76 | val view = editText(value) 77 | linearLayout?.addView(view) 78 | return view 79 | } 80 | 81 | //动态创建EditText 82 | fun imageView(bitmap: Bitmap? = null): ImageView { 83 | val layoutParams = LinearLayout.LayoutParams(dp2px(300f), dp2px(300f)) 84 | layoutParams.gravity = Gravity.CENTER_HORIZONTAL 85 | val view = ImageView(App.get()) 86 | view.layoutParams = layoutParams 87 | bitmap.let { view.setImageBitmap(it) } 88 | return view 89 | } 90 | 91 | //动态创建EditText 92 | fun imageView(linearLayout: ViewGroup?, bitmap: Bitmap? = null): ImageView { 93 | val view = imageView(bitmap) 94 | linearLayout?.addView(view) 95 | return view 96 | } 97 | 98 | //添加空行 99 | fun space(linearLayout: ViewGroup?): Space { 100 | val view = Space(linearLayout?.context) 101 | val layoutParams = LinearLayout.LayoutParams( 102 | LinearLayout.LayoutParams.MATCH_PARENT, 103 | LinearLayout.LayoutParams.WRAP_CONTENT 104 | ) 105 | view.layoutParams = layoutParams 106 | linearLayout?.addView(view) 107 | return view 108 | } 109 | } 110 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 15 | 18 | 21 | 22 | 23 | 24 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_all_test.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | 16 | 17 | 20 | 21 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yutils/yhttp/52e791efa014d282b56414d1d209c442ba0c39fd/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yutils/yhttp/52e791efa014d282b56414d1d209c442ba0c39fd/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yutils/yhttp/52e791efa014d282b56414d1d209c442ba0c39fd/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yutils/yhttp/52e791efa014d282b56414d1d209c442ba0c39fd/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yutils/yhttp/52e791efa014d282b56414d1d209c442ba0c39fd/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yutils/yhttp/52e791efa014d282b56414d1d209c442ba0c39fd/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yutils/yhttp/52e791efa014d282b56414d1d209c442ba0c39fd/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yutils/yhttp/52e791efa014d282b56414d1d209c442ba0c39fd/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yutils/yhttp/52e791efa014d282b56414d1d209c442ba0c39fd/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yutils/yhttp/52e791efa014d282b56414d1d209c442ba0c39fd/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #6200EE 4 | #3700B3 5 | #03DAC5 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | test 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 29 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/xml/network_config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/xml/provider_paths.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/test/java/com/yujing/test/ExampleUnitTest.kt: -------------------------------------------------------------------------------- 1 | package com.yujing.test 2 | 3 | import org.junit.Test 4 | 5 | import org.junit.Assert.* 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * See [testing documentation](http://d.android.com/tools/testing). 11 | */ 12 | class ExampleUnitTest { 13 | @Test 14 | fun addition_isCorrect() { 15 | assertEquals(4, 2 + 2) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/src/test/java/com/yujing/test/User.kt: -------------------------------------------------------------------------------- 1 | package com.yujing.test 2 | 3 | data class User( 4 | val code: Int, 5 | val data: DD?, 6 | val message: String 7 | ) 8 | 9 | data class DD( 10 | val 可用内存: String, 11 | val 已使用内存: String, 12 | val 服务器时间: String, 13 | val 用户: 用户? 14 | ) 15 | 16 | data class 用户( 17 | val createTime: String, 18 | val endLoginTime: String, 19 | val id: Int, 20 | val name: String, 21 | val nickName: String, 22 | val phone: String 23 | ) 24 | class Test{ 25 | fun test(){ 26 | 27 | 28 | } 29 | } -------------------------------------------------------------------------------- /app/src/test/java/com/yujing/test/YHttpTest.java: -------------------------------------------------------------------------------- 1 | package com.yujing.test; 2 | 3 | import com.yujing.utils.YNumber; 4 | import com.yutils.http.YHttp; 5 | import com.yutils.http.contract.YHttpDownloadFileListener; 6 | import com.yutils.http.contract.YHttpListener; 7 | import com.yutils.http.contract.YObjectListener; 8 | import com.yutils.http.model.Upload; 9 | 10 | import java.io.File; 11 | import java.util.ArrayList; 12 | import java.util.HashMap; 13 | import java.util.List; 14 | import org.junit.Test; 15 | 16 | public class YHttpTest { 17 | 18 | @Test 19 | public void main() throws InterruptedException { 20 | YHttp.setShowLog(false); 21 | test1(); 22 | Thread.sleep(2000); 23 | download(); 24 | } 25 | 26 | String session; 27 | private void test1() { 28 | String url = "http://192.168.6.9:8090/crash/user/login"; 29 | HashMap hashMap = new HashMap<>();// = hashMapOf("name" to "yujing", "password" to "wtugeqh") 30 | hashMap.put("name", "yujing"); 31 | hashMap.put("password", "wtugeqh"); 32 | 33 | YHttp.create().setSessionListener(s -> session = s).post(url, hashMap, new YHttpListener() { 34 | @Override 35 | public void success(byte[] bytes, String s) { 36 | System.out.println("请求成功:" + s); 37 | test2(); 38 | test3(); 39 | } 40 | 41 | @Override 42 | public void fail(String s) { 43 | System.out.println("请求失败:" + s); 44 | } 45 | }); 46 | } 47 | 48 | private void test2() { 49 | String url = "http://192.168.6.9:8090/crash/"; 50 | YHttp.create().setSessionId(session).get(url, new YObjectListener() { 51 | @Override 52 | public void success(byte[] bytes, User value) { 53 | System.out.println("请求成功:" + value.toString()); 54 | } 55 | 56 | @Override 57 | public void fail(String value) { 58 | System.out.println("请求失败:" + value); 59 | } 60 | }); 61 | } 62 | 63 | private void test3() { 64 | String url = "http://192.168.6.9:8090/crash/upload/file"; 65 | List uploads = new ArrayList<>(); 66 | uploads.add(new Upload("file1", new File("D:/1.jpg"))); 67 | 68 | YHttp.create().setSessionId(session).upload(url, "", uploads, new YHttpListener() { 69 | @Override 70 | public void success(byte[] bytes, String value) throws Exception { 71 | System.out.println("上传成功:" + value.toString()); 72 | } 73 | 74 | @Override 75 | public void fail(String value) { 76 | System.out.println("上传失败:" + value.toString()); 77 | } 78 | }); 79 | } 80 | 81 | private void download() { 82 | String url = "https://down.qq.com/qqweb/PCQQ/PCQQ_EXE/PCQQ2020.exe"; 83 | File f = new File("D:/PCQQ2020.exe "); 84 | YHttp.create().downloadFile(url, f, new YHttpDownloadFileListener() { 85 | @Override 86 | public void progress(int downloadSize, int fileSize) { 87 | System.out.println("当前进度:" + downloadSize + " " + fileSize + " " + YNumber.showNumber(downloadSize * 100d / fileSize)); 88 | } 89 | 90 | @Override 91 | public void success(File file) { 92 | System.out.println("下载完成:" + file.getPath()); 93 | } 94 | 95 | @Override 96 | public void fail(String value) { 97 | System.out.println("下载失败:" + value); 98 | } 99 | }); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.android.application' version '8.0.1' apply false 3 | id 'com.android.library' version '8.0.1' apply false 4 | id 'org.jetbrains.kotlin.android' version '1.8.10' apply false 5 | } 6 | task clean(type: Delete) { 7 | delete rootProject.buildDir 8 | } -------------------------------------------------------------------------------- /doc/logcat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yutils/yhttp/52e791efa014d282b56414d1d209c442ba0c39fd/doc/logcat.png -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx1536m 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | # AndroidX package structure to make it clearer which packages are bundled with the 15 | # Android operating system, and which are packaged with your app's APK 16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 17 | android.useAndroidX=true 18 | # Automatically convert third-party libraries to use AndroidX 19 | android.enableJetifier=true 20 | # Kotlin code style for this project: "official" or "obsolete": 21 | kotlin.code.style=official 22 | 23 | 24 | # 25 | #signing.keyId=AEAADF14 26 | #signing.password=wtugeqh 27 | #signing.secretKeyRingFile=C\:\\Users\\yujing\\yujing_0xAEAADF14_public.gpg 28 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yutils/yhttp/52e791efa014d282b56414d1d209c442ba0c39fd/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Oct 14 15:22:21 CST 2020 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.1-bin.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | gradlePluginPortal() 4 | google() 5 | mavenCentral() 6 | maven { url 'https://maven.aliyun.com/repository/gradle-plugin' } 7 | } 8 | } 9 | 10 | dependencyResolutionManagement { 11 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) 12 | repositories { 13 | maven { url 'https://repo1.maven.org/maven2' } 14 | google() 15 | mavenCentral() 16 | } 17 | } 18 | rootProject.name='utils_yhttp' 19 | include ':app',':yhttp' -------------------------------------------------------------------------------- /yhttp/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /yhttp/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java-library' 3 | } 4 | java { 5 | sourceCompatibility = JavaVersion.VERSION_1_8 6 | targetCompatibility = JavaVersion.VERSION_1_8 7 | } 8 | dependencies { 9 | //gson,https://mvnrepository.com/artifact/com.google.code.gson/gson 10 | implementation 'com.google.code.gson:gson:2.10.1' 11 | } 12 | //maven配置和签名文件,请注释掉该行 13 | apply from: "${getRootDir().absolutePath}/gradles/publish-maven.gradle" -------------------------------------------------------------------------------- /yhttp/src/main/java/com/yutils/http/Android.java: -------------------------------------------------------------------------------- 1 | package com.yutils.http; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.OutputStream; 5 | import java.lang.reflect.Constructor; 6 | import java.lang.reflect.Method; 7 | 8 | /** 9 | * 安卓常用方法,反射调用 10 | * 11 | * @author yujing 2021年9月11日15:56:45 12 | */ 13 | /* 14 | 用法: 15 | //判断是否是安卓 16 | Android.isAndroid() 17 | //主线程中运行 18 | Android.runOnUiThread { } 19 | //Log 20 | Android.Log("d", "tag", "内容") 21 | //Toast 22 | Android.Toast(context,"内容") 23 | //bitmap转Byte数组 24 | Android.bitmapToByteArray(bitmap) 25 | */ 26 | @SuppressWarnings("ALL") 27 | public class Android { 28 | //安卓里面的 Handler(Looper.getMainLooper()); 29 | private static Object handler; 30 | 31 | static { 32 | try { 33 | if (handler == null) { 34 | //获取 Looper.getMainLooper() 35 | Class cLooper = Class.forName("android.os.Looper"); 36 | Method mGetMainLooper = cLooper.getMethod("getMainLooper"); 37 | Object looper = mGetMainLooper.invoke(null); 38 | 39 | //构造 Handler handler = new Handler(Looper.getMainLooper()); 40 | Class cHandler = Class.forName("android.os.Handler"); 41 | Constructor conHandler = cHandler.getConstructor(cLooper); 42 | handler = conHandler.newInstance(looper); 43 | } 44 | } catch (Exception e) { 45 | Log("e", "错误", e.getMessage()); 46 | } 47 | } 48 | 49 | /** 50 | * 判断是否是安卓项目 51 | * 52 | * @return 是否 53 | */ 54 | public static boolean isAndroid() { 55 | return handler != null; 56 | } 57 | 58 | /** 59 | * 在主线程中运行 60 | * 实际逻辑: 61 | * if (Looper.myLooper() == Looper.getMainLooper()) { 62 | * runnable.run(); 63 | * } else { 64 | * HANDLER.post(runnable); 65 | * } 66 | * 67 | * @param runnable 执行的内容 68 | * @return 是否成功 69 | */ 70 | public static boolean runOnUiThread(Runnable runnable) { 71 | if (!isAndroid()) { 72 | runnable.run(); 73 | return true; 74 | } 75 | try { 76 | Class cLooper = Class.forName("android.os.Looper"); 77 | Method mGetMainLooper = cLooper.getMethod("getMainLooper"); 78 | Method mMyLooper = cLooper.getMethod("myLooper"); 79 | if (mGetMainLooper.invoke(null) == mMyLooper.invoke(null)) { 80 | runnable.run(); 81 | } else { 82 | Class classHandler = Class.forName("android.os.Handler"); 83 | Method mPost = classHandler.getMethod("post", Runnable.class); 84 | mPost.invoke(handler, runnable); 85 | } 86 | return true; 87 | } catch (Exception e) { 88 | //Log("e", "错误", e.getMessage()); 89 | //如果是非安卓,返回false 90 | return false; 91 | } 92 | } 93 | 94 | /** 95 | * 调用安卓Log,如Log.d("tag" ,"内容") 96 | * 使用方法,如: Log(""内容") 97 | * 98 | * @param msg msg 99 | * @return 是否成功 100 | */ 101 | public static boolean Log(String msg) { 102 | return Log("i", "Android", msg, null); 103 | } 104 | 105 | /** 106 | * 调用安卓Log,如Log.d("tag" ,"内容") 107 | * 使用方法,如: Log("d","tag" ,"内容") 108 | * 109 | * @param type log——类型 110 | * @param tag log——tag 111 | * @param msg log——内容 112 | * @return 是否成功 113 | */ 114 | public static boolean Log(String type, String tag, String msg) { 115 | return Log(type, tag, msg, null); 116 | } 117 | 118 | /** 119 | * 调用安卓Log,如Log.d("tag" ,"内容" , throwable) 120 | * 使用方法,如: Log("d","tag" ,"内容" , throwable) 121 | * 122 | * @param type log——类型 123 | * @param tag log——tag 124 | * @param msg log——内容 125 | * @param throwable log——throwable 126 | * @return 是否成功 127 | */ 128 | public static boolean Log(String type, String tag, String msg, Throwable throwable) { 129 | try { 130 | Class cLog = Class.forName("android.util.Log"); 131 | Method method = cLog.getMethod(type, String.class, String.class, Throwable.class); 132 | method.invoke(null, tag, " \n" + msg, throwable); 133 | return true; 134 | } catch (Exception e) { 135 | //System.out.println("打印日志错误:" + e.getMessage() + "\n日志:\ttype:" + type + "\ttag:" + tag + "\tmsg:" + msg); 136 | System.out.println("type:" + type + "\ttag:" + tag + "\tmsg:" + msg + ((throwable == null) ? "" : ("\tthrowable:" + throwable.toString()))); 137 | } 138 | return false; 139 | } 140 | 141 | /** 142 | * 显示Toast 143 | * 实际逻辑: 144 | * Toast toast=Toast.makeText(context, "msg", Toast.LENGTH_SHORT) 145 | * toast.show() 146 | * 147 | * @param context context 148 | * @param msg 内容 149 | * @return 是否成功 150 | */ 151 | public static boolean Toast(Object context, String msg) { 152 | return runOnUiThread(new Runnable() { 153 | @Override 154 | public void run() { 155 | try { 156 | Class cToast = Class.forName("android.widget.Toast"); 157 | Method mMakeText = cToast.getMethod("makeText", Class.forName("android.content.Context"), Class.forName("java.lang.CharSequence"), int.class); 158 | Object obj = mMakeText.invoke(null, context, msg, 0); 159 | Method mShow = cToast.getMethod("show"); 160 | mShow.invoke(obj); 161 | } catch (Exception e) { 162 | System.out.println("显示Toast错误:" + e.getMessage() + "\nmsg:" + msg); 163 | } 164 | } 165 | }); 166 | } 167 | 168 | 169 | /** 170 | * bitmap转ByteArray 171 | * 相当于: 172 | * ByteArrayOutputStream baos = new ByteArrayOutputStream(); 173 | * bitmap.compress(Bitmap.CompressFormat.JPEG, 90, baos); 174 | * baos.toByteArray(); 175 | * 176 | * @param bitmap bitmap 177 | * @return ByteArray 178 | */ 179 | public static byte[] bitmapToByteArray(Object bitmap) { 180 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 181 | try { 182 | Class cBitmap = Class.forName("android.graphics.Bitmap"); 183 | Class cCompressFormat = Class.forName("android.graphics.Bitmap$CompressFormat"); 184 | Object oFormat = null; 185 | for (int i = 0; i < cCompressFormat.getEnumConstants().length; i++) { 186 | //JPEG,PNG,WEBP 187 | if ("JPEG".equals(cCompressFormat.getEnumConstants()[i].toString())) { 188 | oFormat = cCompressFormat.getEnumConstants()[i]; 189 | break; 190 | } 191 | } 192 | Method mCompress = cBitmap.getMethod("compress", cCompressFormat, int.class, OutputStream.class); 193 | mCompress.invoke(bitmap, oFormat, 90, baos); 194 | return baos.toByteArray(); 195 | } catch (Exception e) { 196 | System.out.println("转换bitmap错误:" + e.getMessage()); 197 | } 198 | return null; 199 | } 200 | } 201 | -------------------------------------------------------------------------------- /yhttp/src/main/java/com/yutils/http/YHttp.java: -------------------------------------------------------------------------------- 1 | package com.yutils.http; 2 | 3 | import com.google.gson.Gson; 4 | import com.yutils.http.contract.ObjectListener; 5 | import com.yutils.http.contract.YFailListener; 6 | import com.yutils.http.contract.YHttpDownloadFileListener; 7 | import com.yutils.http.contract.YHttpListener; 8 | import com.yutils.http.contract.YHttpLoadListener; 9 | import com.yutils.http.contract.YObjectListener; 10 | import com.yutils.http.contract.YSessionListener; 11 | import com.yutils.http.contract.YSuccessListener; 12 | import com.yutils.http.model.Upload; 13 | 14 | import java.io.File; 15 | import java.io.FileNotFoundException; 16 | import java.io.IOException; 17 | import java.io.UnsupportedEncodingException; 18 | import java.net.MalformedURLException; 19 | import java.util.ArrayList; 20 | import java.util.List; 21 | import java.util.Map; 22 | 23 | /** 24 | * 网络请求类 25 | * 26 | * @author yujing 2021年12月24日09:50:29 27 | * 详细说明和最新版请查看 https://github.com/yutils/yhttp 28 | * 优点: 29 | * 1.支持get,post,put,delete请求,一行实现同步请求,一行实现异步请求 30 | * 2.post请求可为字符串,map,byte[] 31 | * 3.直接返回请求结果为 字符串 或 对象 或 byte[] 32 | * 4.支持各种格式文件下载,回调进度条 33 | * 5.单次文件上传请求中可以包含多种不同格式文件 34 | * 6.日志详细记录请求数据和结果,可关闭日志,异常请求回调异常原因 35 | * 7.支持https,支持设置ssl文件 36 | * 8.sessionID的获取和设置,可以切换多个不同sessionID 37 | * 9.简单好用,作者持续更新 38 | * 10.支持安卓,请求结果直接回调到UI线程(主线程) 39 | * 11.自定义gson,如:可以直接序列化指定日期格式的内容 40 | * 12.链式调用,代码更加简洁,可以不监听失败回调 41 | */ 42 | /*基本用法举例 43 | //java 44 | YHttp.create().post(url, hashMap, new YObjectListener() { 45 | @Override 46 | public void success(byte[] bytes, User value) { 47 | //请求结果,对象 48 | } 49 | 50 | @Override 51 | public void fail(String value) { 52 | //错误原因 53 | } 54 | }); 55 | 56 | //java文件上传 57 | String url = "http://192.168.6.9:8090/crash/upload/file"; 58 | List uploads = new ArrayList<>(); 59 | uploads.add(new Upload("file1", new File("D:/1.jpg"))); 60 | uploads.add(new Upload("file2", "ABCDEF".getBytes()).setFilename("abcd.txt")); 61 | 62 | YHttp.create().setSessionId(session).upload(url, "", uploads, new YHttpListener() { 63 | @Override 64 | public void success(byte[] bytes, String value){ 65 | System.out.println("上传成功:" + value); 66 | } 67 | @Override 68 | public void fail(String value) { 69 | System.out.println("上传失败:" + value); 70 | } 71 | }); 72 | 73 | 74 | //kotlin 75 | val url = "https://down.qq.com/qqweb/PCQQ/PCQQ_EXE/PCQQ2020.exe" 76 | YHttp.create().setSessionId(session).get(url, object : YObjectListener(){ 77 | override fun success(bytes: ByteArray?, value: User?) { 78 | //成功 User对象 79 | } 80 | 81 | override fun fail(value: String?) { 82 | //错误原因 83 | } 84 | }) 85 | 86 | //文件上传 87 | val url = "http://192.168.6.9:8090/crash/upload/file" 88 | val list: MutableList = ArrayList() 89 | list.add(Upload("file1",file)) 90 | list.add(Upload("file2", "ABCDEF".toByteArray()).setFilename("abcd.txt")) 91 | list.add(Upload("file3",bitmap)) 92 | YHttp.create().setSessionId(session).upload(url, "", list, object : YHttpListener { 93 | override fun success(bytes: ByteArray?, value: String?) { 94 | //成功 95 | } 96 | override fun fail(value: String?) { 97 | //失败 98 | } 99 | }) 100 | 101 | //文件下载,如是安卓,返回值自动回到主线程 102 | val url = "https://down.qq.com/qqweb/PCQQ/PCQQ_EXE/PCQQ2020.exe" 103 | var f = File( "D:/BB.exe") 104 | YHttp.create().downloadFile(url, f, object : 105 | YHttpDownloadFileListener { 106 | override fun progress(downloadSize: Int, fileSize: Int) { 107 | val progress = (10000.0 * downloadSize / fileSize).toInt() / 100.0 //下载进度,保留2位小数 108 | } 109 | override fun success(file: File) {}//下载完成 110 | override fun fail(value: String) {}//下载出错 111 | }) 112 | 113 | //链式请求 java 114 | String url = "http://192.168.6.9:8090/crash/user/login"; 115 | Map hashMap = new HashMap();// = hashMapOf("name" to "yujing", "password" to "wtugeqh") 116 | hashMap.put("name", "yujing"); 117 | hashMap.put("password", "wtugeqh"); 118 | YHttp.create() 119 | .url(url) 120 | .post(hashMap) 121 | .setSuccessListener((bytes, value) -> { 122 | System.out.println("请求成功:" + value); 123 | }).start(); 124 | 125 | //链式,get 126 | YHttp 127 | .create() 128 | .url("http://192.168.6.9:8090/crash/") 129 | .get() 130 | .setSuccessListener { bytes, value -> textView1.text = "成功:$value" } 131 | .setFailListener { value -> textView2.text = "失败:$value" } 132 | .start() 133 | 134 | //链式,post 135 | val url = "http://192.168.6.9:8090/crash/user/login" 136 | val gson=YJson.getGsonDate( "yyyy年MM月dd日 HH:mm:ss") 137 | val hashMap: HashMap = hashMapOf("name" to "yujing", "password" to "wtugeqh") 138 | YHttp.create() 139 | .url(url) 140 | .post(hashMap) 141 | .setGson(gson) 142 | .setObjectListener(object : ObjectListener() { 143 | override fun success(bytes: ByteArray?, value: User?) { 144 | textView2.text = "\n对象:${value.toString()}" 145 | } 146 | }) 147 | .setFailListener { value -> textView2.text = "失败:$value" } 148 | .start() 149 | 150 | //链式,自定义请求 151 | YHttp.create() 152 | .url(url) 153 | .method("POST") 154 | .setContentType("application/x-www-form-urlencoded;charset=utf-8") 155 | .addRequestProperty("connection", "Keep-Alive") 156 | .body(hashMap) 157 | .setGson(gson) 158 | .setSessionId(session) 159 | .setCrtSSL("SSL证书内容") 160 | .setSuccessListener { bytes, value -> textView1.text = "成功:$value" } 161 | .setObjectListener(object : ObjectListener() { 162 | override fun success(bytes: ByteArray?, value: User?) { 163 | textView2.text = "\n对象:${value.toString()}" 164 | } 165 | }) 166 | .setFailListener { value -> textView2.text = "失败:$value" } 167 | .setSessionListener { sessionId -> session = sessionId } 168 | .start() 169 | */ 170 | public class YHttp extends YHttpBase { 171 | private static volatile boolean showLog = true; 172 | private Object gson;//防止对方没引用Gson时完全无法使用 173 | private String requestUrl;//请求url 174 | private byte[] requestBytes;//请求内容 175 | private String requestMethod;//请求方式,只能是 "GET", "POST", "HEAD", "OPTIONS", "PUT", "DELETE", "TRACE" 176 | private YSuccessListener successListener;//成功监听 177 | private ObjectListener objectListener;//成功监听,返回对象 178 | private YFailListener failListener;//失败监听 179 | 180 | /** 181 | * 设置 是否显示日志 182 | * 183 | * @param showLog 是否显示日志 184 | */ 185 | public static void setShowLog(boolean showLog) { 186 | YHttp.showLog = showLog; 187 | } 188 | 189 | public YHttp() { 190 | } 191 | 192 | /** 193 | * 获取YHttp实例 194 | * 195 | * @return YHttp 196 | */ 197 | public static YHttp create() { 198 | return new YHttp(); 199 | } 200 | 201 | /** 202 | * 获取当前Gson对象 203 | * 204 | * @return Gson 205 | */ 206 | public Gson getGson() { 207 | if (gson != null && gson instanceof Gson) { 208 | return (Gson) gson; 209 | } else { 210 | gson = new Gson(); 211 | } 212 | return (Gson) gson; 213 | } 214 | 215 | /** 216 | * 设置当前Gson对象 217 | * 218 | * @param gson Gson 219 | * @return YHttp 220 | */ 221 | public YHttp setGson(Gson gson) { 222 | this.gson = gson; 223 | return this; 224 | } 225 | 226 | /** 227 | * @param contentType 设置contentType,常见如 228 | * "application/x-www-form-urlencoded;charset=utf-8" 229 | * "application/json;charset=utf-8" 230 | * @return YHttp 231 | */ 232 | @Override 233 | public YHttp setContentType(String contentType) { 234 | super.setContentType(contentType); 235 | return this; 236 | } 237 | 238 | /** 239 | * 设置超时时间 240 | * 241 | * @param connectTimeout 毫秒 242 | * @return YHttp 243 | */ 244 | @Override 245 | public YHttp setConnectTimeout(int connectTimeout) { 246 | super.setConnectTimeout(connectTimeout); 247 | return this; 248 | } 249 | 250 | /** 251 | * 设置SSL证书内容 252 | * 253 | * @param crtSSL ssl 254 | * @return YHttp 255 | */ 256 | @Override 257 | public YHttp setCrtSSL(String crtSSL) { 258 | super.setCrtSSL(crtSSL); 259 | return this; 260 | } 261 | 262 | /** 263 | * 设置请求头 264 | * 如: 265 | * "connection","Keep-Alive" 266 | * "Charset","utf-8" 267 | * 268 | * @param key key 269 | * @param value value 270 | * @return YHttp 271 | */ 272 | @Override 273 | public YHttp setRequestProperty(String key, String value) { 274 | super.setRequestProperty(key, value); 275 | return this; 276 | } 277 | 278 | /** 279 | * 添加请求头 280 | * 如: 281 | * "connection","Keep-Alive" 282 | * "Charset","utf-8" 283 | * 284 | * @param key key 285 | * @param value value 286 | * @return YHttp 287 | */ 288 | @Override 289 | public YHttp addRequestProperty(String key, String value) { 290 | super.addRequestProperty(key, value); 291 | return this; 292 | } 293 | 294 | /** 295 | * 设置 Session回调 296 | * 297 | * @param ySessionListener 回调服务返回的sessionId 298 | * @return YHttp 299 | */ 300 | @Override 301 | public YHttp setSessionListener(YSessionListener ySessionListener) { 302 | super.setSessionListener(ySessionListener); 303 | return this; 304 | } 305 | 306 | /** 307 | * 设置 sessionId 308 | * 309 | * @param sessionId sessionId 310 | * @return YHttp 311 | */ 312 | @Override 313 | public YHttp setSessionId(String sessionId) { 314 | super.setSessionId(sessionId); 315 | return this; 316 | } 317 | 318 | /** 319 | * 设置 请求地址 320 | * 321 | * @param url url地址,http:// 或 https:// 开头 322 | * @return YHttp 323 | */ 324 | public YHttp url(String url) { 325 | requestUrl = url; 326 | return this; 327 | } 328 | 329 | /** 330 | * 设置 请求内容 331 | * 332 | * @param json json/文本 333 | * @return YHttp 334 | */ 335 | public YHttp body(String json) { 336 | requestBytes = json.getBytes(); 337 | return this; 338 | } 339 | 340 | /** 341 | * 设置 请求内容 342 | * 343 | * @param paramsMap paramsMap,key,value方式 344 | * @return YHttp 345 | */ 346 | public YHttp body(Map paramsMap) { 347 | requestBytes = YHttpUtils.mapToParams(paramsMap).toString().getBytes(); 348 | return this; 349 | } 350 | 351 | /** 352 | * 设置 请求内容 353 | * 354 | * @param bytes bytes 355 | * @return YHttp 356 | */ 357 | public YHttp body(byte[] bytes) { 358 | requestBytes = bytes; 359 | return this; 360 | } 361 | 362 | /** 363 | * 设置 请求方式 364 | * 365 | * @param method "GET", "POST", "HEAD", "OPTIONS", "PUT", "DELETE", "TRACE" 366 | * @return YHttp 367 | */ 368 | public YHttp method(String method) { 369 | this.requestMethod = method; 370 | return this; 371 | } 372 | 373 | /** 374 | * 设置 请求成功监听,回调字符串 375 | * 376 | * @param successListener 成功返回请求的字符串,和byte数组 377 | * @return YHttp 378 | */ 379 | public YHttp setSuccessListener(YSuccessListener successListener) { 380 | this.successListener = successListener; 381 | return this; 382 | } 383 | 384 | /** 385 | * 设置 请求成功监听,回调对象 386 | * 387 | * @param objectListener 成功返回object 388 | * @return YHttp 389 | */ 390 | public YHttp setObjectListener(ObjectListener objectListener) { 391 | this.objectListener = objectListener; 392 | return this; 393 | } 394 | 395 | /** 396 | * 设置 请求失败监听 397 | * 398 | * @param failListener 失败返回原因 399 | * @return YHttp 400 | */ 401 | public YHttp setFailListener(YFailListener failListener) { 402 | this.failListener = failListener; 403 | return this; 404 | } 405 | 406 | /** 407 | * 设置请求类型 get 408 | * 409 | * @return YHttp 410 | */ 411 | public YHttp get() { 412 | requestMethod = "GET"; 413 | return this; 414 | } 415 | 416 | /** 417 | * 设置请求类型 post 418 | * 419 | * @return YHttp 420 | */ 421 | public YHttp post() { 422 | requestMethod = "POST"; 423 | return this; 424 | } 425 | 426 | /** 427 | * 设置请求类型 post 428 | * 429 | * @param json json/字符串 430 | * @return YHttp 431 | */ 432 | public YHttp post(String json) { 433 | if (getContentType() == null) setContentType("application/json;charset=utf-8"); 434 | return post().body(json); 435 | } 436 | 437 | /** 438 | * 设置请求类型 post 439 | * 440 | * @param paramsMap paramsMap 441 | * @return YHttp 442 | */ 443 | public YHttp post(Map paramsMap) { 444 | return post().body(paramsMap); 445 | } 446 | 447 | /** 448 | * 设置请求类型 post 449 | * 450 | * @param bytes bytes 451 | * @return YHttp 452 | */ 453 | public YHttp post(byte[] bytes) { 454 | return post().body(bytes); 455 | } 456 | 457 | /** 458 | * 设置请求类型 put 459 | * 460 | * @return YHttp 461 | */ 462 | public YHttp put() { 463 | requestMethod = "PUT"; 464 | return this; 465 | } 466 | 467 | /** 468 | * 设置请求类型 put 469 | * 470 | * @param json json/字符串 471 | * @return YHttp 472 | */ 473 | public YHttp put(String json) { 474 | if (getContentType() == null) setContentType("application/json;charset=utf-8"); 475 | return put().body(json); 476 | } 477 | 478 | /** 479 | * 设置请求类型 put 480 | * 481 | * @param paramsMap paramsMap 482 | * @return YHttp 483 | */ 484 | public YHttp put(Map paramsMap) { 485 | return put().body(paramsMap); 486 | } 487 | 488 | /** 489 | * 设置请求类型 put 490 | * 491 | * @param bytes bytes 492 | * @return YHttp 493 | */ 494 | public YHttp put(byte[] bytes) { 495 | return put().body(bytes); 496 | } 497 | 498 | /** 499 | * 设置请求类型 delete 500 | * 501 | * @return YHttp 502 | */ 503 | public YHttp delete() { 504 | requestMethod = "DELETE"; 505 | return this; 506 | } 507 | 508 | /** 509 | * 设置请求类型 delete 510 | * 511 | * @param json json/字符串 512 | * @return YHttp 513 | */ 514 | public YHttp delete(String json) { 515 | if (getContentType() == null) setContentType("application/json;charset=utf-8"); 516 | return delete().body(json); 517 | } 518 | 519 | /** 520 | * 设置请求类型 delete 521 | * 522 | * @param paramsMap paramsMap 523 | * @return YHttp 524 | */ 525 | public YHttp delete(Map paramsMap) { 526 | return delete().body(paramsMap); 527 | } 528 | 529 | /** 530 | * 设置请求类型 delete 531 | * 532 | * @param bytes bytes 533 | * @return YHttp 534 | */ 535 | public YHttp delete(byte[] bytes) { 536 | return delete().body(bytes); 537 | } 538 | 539 | /** 540 | * 设置请求成功监听 541 | * 542 | * @param listener 成功返回object,失败返回原因 543 | */ 544 | public void YObjectListener(YObjectListener listener) { 545 | YObjectListener listener2 = listener; 546 | } 547 | 548 | /** 549 | * 开始网络请求,链式时可以调用 550 | */ 551 | public void start() { 552 | request(requestUrl, requestBytes, requestMethod, new YHttpListener() { 553 | @Override 554 | public void success(byte[] bytes, String value) throws Exception { 555 | if (successListener != null) successListener.success(bytes, value); 556 | if (objectListener != null) { 557 | println("json转对象:" + objectListener.getType()); 558 | try { 559 | //如果是安卓就用handler调回到主线程,如果是普通JAVA工程,直接回调到线程 560 | Android.runOnUiThread(() -> { 561 | try { 562 | if (String.class.equals(objectListener.getType())) { 563 | objectListener.success(bytes, (T) value); 564 | } else if ("byte[]".equals(objectListener.getType().toString())) { 565 | objectListener.success(bytes, (T) bytes); 566 | } else { 567 | T object = getGson().fromJson(value, objectListener.getType()); 568 | objectListener.success(bytes, object); 569 | } 570 | } catch (Exception e) { 571 | if (failListener != null) 572 | failListener.fail("异常:" + e.getMessage()); 573 | e.printStackTrace(); 574 | } 575 | }); 576 | } catch (java.lang.ClassCastException e) { 577 | if (failListener != null) 578 | failListener.fail("对象转换失败"); 579 | e.printStackTrace(); 580 | } catch (Exception e) { 581 | if (failListener != null) 582 | failListener.fail("异常:" + e.getMessage()); 583 | e.printStackTrace(); 584 | } 585 | } 586 | } 587 | 588 | @Override 589 | public void fail(String value) { 590 | failListener.fail(value); 591 | } 592 | }); 593 | } 594 | //----------------------------------------------GET---------------------------------------------- 595 | 596 | /** 597 | * get请求 598 | * 599 | * @param requestUrl url 600 | * @param listener 监听 601 | */ 602 | public void get(final String requestUrl, YHttpListener listener) { 603 | request(requestUrl, new byte[0], "GET", listener); 604 | } 605 | 606 | /** 607 | * get请求 608 | * 609 | * @param requestUrl url 610 | * @param listener 监听 611 | */ 612 | public void get(final String requestUrl, YObjectListener listener) { 613 | request(requestUrl, new byte[0], "GET", listener); 614 | } 615 | //----------------------------------------------POST---------------------------------------------- 616 | 617 | /** 618 | * post请求 619 | * 620 | * @param requestUrl url 621 | * @param paramsMap key,value 622 | * @param listener 监听 623 | */ 624 | public void post(final String requestUrl, Map paramsMap, YHttpListener listener) { 625 | request(requestUrl, YHttpUtils.mapToParams(paramsMap).toString().getBytes(), "POST", listener); 626 | } 627 | 628 | /** 629 | * post请求 630 | * 631 | * @param requestUrl url 632 | * @param json json/文本 633 | * @param listener 监听 634 | */ 635 | public void post(final String requestUrl, String json, YHttpListener listener) { 636 | if (getContentType() == null) setContentType("application/json;charset=utf-8"); 637 | request(requestUrl, json.getBytes(), "POST", listener); 638 | } 639 | 640 | /** 641 | * post请求 642 | * 643 | * @param requestUrl url 644 | * @param requestBytes bytes 645 | * @param listener 监听 646 | */ 647 | public void post(final String requestUrl, byte[] requestBytes, YHttpListener listener) { 648 | request(requestUrl, requestBytes, "POST", listener); 649 | } 650 | 651 | /** 652 | * post请求 653 | * 654 | * @param requestUrl url 655 | * @param paramsMap key,value 656 | * @param listener 监听 657 | */ 658 | public void post(String requestUrl, Map paramsMap, YObjectListener listener) { 659 | request(requestUrl, YHttpUtils.mapToParams(paramsMap).toString().getBytes(), "POST", listener); 660 | } 661 | 662 | /** 663 | * post请求 664 | * 665 | * @param requestUrl url 666 | * @param json json/文本 667 | * @param listener 监听 668 | */ 669 | public void post(String requestUrl, String json, YObjectListener listener) { 670 | if (getContentType() == null) setContentType("application/json;charset=utf-8"); 671 | request(requestUrl, json.getBytes(), "POST", listener); 672 | } 673 | 674 | /** 675 | * post请求 676 | * 677 | * @param requestUrl url 678 | * @param requestBytes bytes 679 | * @param listener 监听 680 | */ 681 | public void post(String requestUrl, byte[] requestBytes, YObjectListener listener) { 682 | request(requestUrl, requestBytes, "POST", listener); 683 | } 684 | 685 | //----------------------------------------------PUT---------------------------------------------- 686 | 687 | /** 688 | * put请求 689 | * 690 | * @param requestUrl url 691 | * @param paramsMap key,value 692 | * @param listener 监听 693 | */ 694 | public void put(String requestUrl, Map paramsMap, YHttpListener listener) { 695 | request(requestUrl, YHttpUtils.mapToParams(paramsMap).toString().getBytes(), "PUT", listener); 696 | } 697 | 698 | /** 699 | * put请求 700 | * 701 | * @param requestUrl url 702 | * @param json json/文本 703 | * @param listener 监听 704 | */ 705 | public void put(String requestUrl, String json, YHttpListener listener) { 706 | if (getContentType() == null) setContentType("application/json;charset=utf-8"); 707 | request(requestUrl, json.getBytes(), "PUT", listener); 708 | } 709 | 710 | /** 711 | * put请求 712 | * 713 | * @param requestUrl url 714 | * @param requestBytes bytes 715 | * @param listener 监听 716 | */ 717 | public void put(String requestUrl, byte[] requestBytes, YHttpListener listener) { 718 | request(requestUrl, requestBytes, "PUT", listener); 719 | } 720 | 721 | /** 722 | * put请求 723 | * 724 | * @param requestUrl url 725 | * @param paramsMap key,value 726 | * @param listener 监听 727 | */ 728 | public void put(String requestUrl, Map paramsMap, YObjectListener listener) { 729 | request(requestUrl, YHttpUtils.mapToParams(paramsMap).toString().getBytes(), "PUT", listener); 730 | } 731 | 732 | /** 733 | * put请求 734 | * 735 | * @param requestUrl url 736 | * @param json json/文本 737 | * @param listener 监听 738 | */ 739 | public void put(String requestUrl, String json, YObjectListener listener) { 740 | if (getContentType() == null) setContentType("application/json;charset=utf-8"); 741 | request(requestUrl, json.getBytes(), "PUT", listener); 742 | } 743 | 744 | /** 745 | * put请求 746 | * 747 | * @param requestUrl url 748 | * @param requestBytes bytes 749 | * @param listener 监听 750 | */ 751 | public void put(String requestUrl, byte[] requestBytes, YObjectListener listener) { 752 | request(requestUrl, requestBytes, "PUT", listener); 753 | } 754 | 755 | //----------------------------------------------DELETE---------------------------------------------- 756 | 757 | /** 758 | * delete请求 759 | * 760 | * @param requestUrl url 761 | * @param paramsMap key,value 762 | * @param listener 监听 763 | */ 764 | public void delete(String requestUrl, Map paramsMap, YHttpListener listener) { 765 | request(requestUrl, YHttpUtils.mapToParams(paramsMap).toString().getBytes(), "DELETE", listener); 766 | } 767 | 768 | /** 769 | * delete请求 770 | * 771 | * @param requestUrl url 772 | * @param json json/文本 773 | * @param listener 监听 774 | */ 775 | public void delete(String requestUrl, String json, YHttpListener listener) { 776 | if (getContentType() == null) setContentType("application/json;charset=utf-8"); 777 | request(requestUrl, json.getBytes(), "DELETE", listener); 778 | } 779 | 780 | /** 781 | * delete请求 782 | * 783 | * @param requestUrl url 784 | * @param requestBytes bytes 785 | * @param listener 监听 786 | */ 787 | public void delete(String requestUrl, byte[] requestBytes, YHttpListener listener) { 788 | request(requestUrl, requestBytes, "DELETE", listener); 789 | } 790 | 791 | /** 792 | * delete请求 793 | * 794 | * @param requestUrl url 795 | * @param paramsMap key,value 796 | * @param listener 监听 797 | */ 798 | public void delete(String requestUrl, Map paramsMap, YObjectListener listener) { 799 | request(requestUrl, YHttpUtils.mapToParams(paramsMap).toString().getBytes(), "DELETE", listener); 800 | } 801 | 802 | /** 803 | * delete请求 804 | * 805 | * @param requestUrl url 806 | * @param json json/文本 807 | * @param listener 监听 808 | */ 809 | public void delete(String requestUrl, String json, YObjectListener listener) { 810 | if (getContentType() == null) setContentType("application/json;charset=utf-8"); 811 | request(requestUrl, json.getBytes(), "DELETE", listener); 812 | } 813 | 814 | /** 815 | * delete请求 816 | * 817 | * @param requestUrl url 818 | * @param requestBytes bytes 819 | * @param listener 监听 820 | */ 821 | public void delete(String requestUrl, byte[] requestBytes, YObjectListener listener) { 822 | request(requestUrl, requestBytes, "DELETE", listener); 823 | } 824 | 825 | //----------------------------------------------request---------------------------------------------- 826 | 827 | /** 828 | * request请求 829 | * 830 | * @param requestUrl url 831 | * @param paramsMap key,value 832 | * @param requestMethod 请求类型,只能是 "GET", "POST", "HEAD", "OPTIONS", "PUT", "DELETE", "TRACE" 833 | * @param listener 监听 834 | */ 835 | public void request(String requestUrl, Map paramsMap, String requestMethod, YHttpListener listener) { 836 | request(requestUrl, YHttpUtils.mapToParams(paramsMap).toString().getBytes(), requestMethod, listener); 837 | } 838 | 839 | /** 840 | * request请求 841 | * 842 | * @param requestUrl url 843 | * @param json json/文本 844 | * @param requestMethod 请求类型,只能是 "GET", "POST", "HEAD", "OPTIONS", "PUT", "DELETE", "TRACE" 845 | * @param listener 监听 846 | */ 847 | public void request(String requestUrl, String json, String requestMethod, YHttpListener listener) { 848 | if (getContentType() == null) setContentType("application/json;charset=utf-8"); 849 | request(requestUrl, json.getBytes(), requestMethod, listener); 850 | } 851 | 852 | /** 853 | * request请求 854 | * 855 | * @param requestUrl url 856 | * @param paramsMap key,value 857 | * @param requestMethod 请求类型,只能是 "GET", "POST", "HEAD", "OPTIONS", "PUT", "DELETE", "TRACE" 858 | * @param listener 监听 859 | */ 860 | public void request(String requestUrl, Map paramsMap, String requestMethod, YObjectListener listener) { 861 | request(requestUrl, YHttpUtils.mapToParams(paramsMap).toString().getBytes(), requestMethod, listener); 862 | } 863 | 864 | /** 865 | * request请求 866 | * 867 | * @param requestUrl url 868 | * @param json json/文本 869 | * @param requestMethod 请求类型,只能是 "GET", "POST", "HEAD", "OPTIONS", "PUT", "DELETE", "TRACE" 870 | * @param listener 监听 871 | */ 872 | public void request(String requestUrl, String json, String requestMethod, YObjectListener listener) { 873 | if (getContentType() == null) setContentType("application/json;charset=utf-8"); 874 | request(requestUrl, json.getBytes(), requestMethod, listener); 875 | } 876 | 877 | /** 878 | * request请求 879 | * 880 | * @param requestUrl url 881 | * @param requestBytes byte数组 882 | * @param requestMethod 请求类型,只能是 "GET", "POST", "HEAD", "OPTIONS", "PUT", "DELETE", "TRACE" 883 | * @param listener 监听 884 | */ 885 | public void request(final String requestUrl, final byte[] requestBytes, String requestMethod, final YHttpListener listener) { 886 | Thread thread = new Thread(() -> { 887 | long startTime = System.currentTimeMillis(); 888 | try { 889 | byte[] bytes = request(requestUrl, requestBytes, requestMethod); 890 | String result = new String(bytes); 891 | if (showLog) { 892 | String info = "请求地址:" + requestMethod + "--->" + requestUrl; 893 | if (requestBytes != null && requestBytes.length != 0) 894 | info += "\n请求参数:" + new String(requestBytes); 895 | info += "\n请求结果:" + result; 896 | info += "\n耗时:" + (System.currentTimeMillis() - startTime) + "毫秒"; 897 | println(info); 898 | } 899 | Android.runOnUiThread(() -> { 900 | try { 901 | listener.success(bytes, result); 902 | } catch (Exception e) { 903 | listener.fail("异常:" + e.getMessage()); 904 | e.printStackTrace(); 905 | } 906 | }); 907 | } catch (Exception e) { 908 | if (showLog) { 909 | String info = "请求地址:" + requestMethod + "--->" + requestUrl; 910 | if (requestBytes != null) info += "\n请求参数:" + new String(requestBytes); 911 | info += "\n请求异常:" + exceptionToString(e); 912 | info += "\n耗时:" + (System.currentTimeMillis() - startTime) + "毫秒"; 913 | println(info); 914 | } 915 | exception(e, listener); 916 | } finally { 917 | YHttpThreadPool.shutdown(); 918 | } 919 | }); 920 | thread.setName("request请求:" + requestUrl); 921 | YHttpThreadPool.add(thread); 922 | } 923 | 924 | /** 925 | * request请求 926 | * 927 | * @param requestUrl url 928 | * @param requestBytes byte数组 929 | * @param requestMethod 请求类型,只能是 "GET", "POST", "HEAD", "OPTIONS", "PUT", "DELETE", "TRACE" 930 | * @param listener 监听 931 | */ 932 | public void request(String requestUrl, byte[] requestBytes, String requestMethod, final YObjectListener listener) { 933 | request(requestUrl, requestBytes, requestMethod, new YHttpListener() { 934 | @Override 935 | public void success(byte[] bytes, String value) { 936 | println("json转对象:" + listener.getType()); 937 | try { 938 | Android.runOnUiThread(() -> { 939 | try { 940 | if (String.class.equals(listener.getType())) { 941 | listener.success(bytes, (T) value); 942 | } else if ("byte[]".equals(listener.getType().toString())) { 943 | listener.success(bytes, (T) bytes); 944 | } else { 945 | T object = getGson().fromJson(value, listener.getType()); 946 | listener.success(bytes, object); 947 | } 948 | } catch (Exception e) { 949 | listener.fail("异常:" + e.getMessage()); 950 | e.printStackTrace(); 951 | } 952 | }); 953 | } catch (java.lang.ClassCastException e) { 954 | listener.fail("对象转换失败"); 955 | e.printStackTrace(); 956 | } catch (Exception e) { 957 | listener.fail("异常:" + e.getMessage()); 958 | e.printStackTrace(); 959 | } 960 | } 961 | 962 | @Override 963 | public void fail(String value) { 964 | listener.fail(value); 965 | } 966 | }); 967 | } 968 | 969 | /** 970 | * 文件上传post 971 | * 972 | * @param requestUrl url 973 | * @param paramsMap key,value 974 | * @param fileMap 文件列表 975 | * @param listener 监听 976 | */ 977 | public void upload(String requestUrl, Map paramsMap, Map fileMap, YHttpListener listener) { 978 | upload(requestUrl, YHttpUtils.mapToParams(paramsMap).toString().getBytes(), fileMap, listener); 979 | } 980 | 981 | /** 982 | * 文件上传post 983 | * 984 | * @param requestUrl url 985 | * @param json json/文本 986 | * @param fileMap 文件列表 987 | * @param listener 监听 988 | */ 989 | public void upload(String requestUrl, String json, Map fileMap, YHttpListener listener) { 990 | if (getContentType() == null) setContentType("application/json;charset=utf-8"); 991 | upload(requestUrl, json.getBytes(), fileMap, listener); 992 | } 993 | 994 | /** 995 | * 文件上传post 996 | * 997 | * @param requestUrl url 998 | * @param requestBytes bytes 999 | * @param fileMap 文件列表 1000 | * @param listener 监听 1001 | */ 1002 | public void upload(String requestUrl, byte[] requestBytes, Map fileMap, YHttpListener listener) { 1003 | List uploads = new ArrayList<>(); 1004 | for (Map.Entry entry : fileMap.entrySet()) { 1005 | if (entry.getValue() == null) continue; 1006 | uploads.add(new Upload(entry.getKey(), entry.getValue())); 1007 | } 1008 | upload(requestUrl, requestBytes, uploads, listener); 1009 | } 1010 | 1011 | /** 1012 | * 文件上传post 1013 | * 1014 | * @param requestUrl url 1015 | * @param paramsMap key,value 1016 | * @param uploads 上传的key,内容,文件名,contentType 1017 | * @param listener 监听 1018 | */ 1019 | public void upload(String requestUrl, Map paramsMap, List uploads, YHttpListener listener) { 1020 | upload(requestUrl, YHttpUtils.mapToParams(paramsMap).toString().getBytes(), uploads, listener); 1021 | } 1022 | 1023 | /** 1024 | * 文件上传post 1025 | * 1026 | * @param requestUrl url 1027 | * @param json json/文本 1028 | * @param uploads 上传的key,内容,文件名,contentType 1029 | * @param listener 监听 1030 | */ 1031 | public void upload(String requestUrl, String json, List uploads, YHttpListener listener) { 1032 | if (getContentType() == null) setContentType("application/json;charset=utf-8"); 1033 | upload(requestUrl, json.getBytes(), uploads, listener); 1034 | } 1035 | 1036 | /** 1037 | * 文件上传post 1038 | * 1039 | * @param requestUrl url 1040 | * @param requestBytes bytes 1041 | * @param uploads 上传的key,内容,文件名,contentType 1042 | * @param listener 监听 1043 | */ 1044 | public void upload(final String requestUrl, final byte[] requestBytes, final List uploads, final YHttpListener listener) { 1045 | Thread thread = new Thread(() -> { 1046 | long startTime = System.currentTimeMillis(); 1047 | try { 1048 | byte[] bytes = upload(requestUrl, requestBytes, uploads); 1049 | String result = new String(bytes); 1050 | if (showLog) { 1051 | String info = "文件上传\n请求地址:" + requestMethod + "--->" + requestUrl; 1052 | if (requestBytes != null && requestBytes.length != 0) 1053 | info += "\n请求参数:" + new String(requestBytes); 1054 | info += "\n文件数:" + uploads.size(); 1055 | info += "\n请求结果:" + result; 1056 | info += "\n耗时:" + (System.currentTimeMillis() - startTime) + "毫秒"; 1057 | println(info); 1058 | } 1059 | Android.runOnUiThread(() -> { 1060 | try { 1061 | listener.success(bytes, result); 1062 | } catch (Exception e) { 1063 | listener.fail("异常:" + e.getMessage()); 1064 | e.printStackTrace(); 1065 | } 1066 | }); 1067 | } catch (Exception e) { 1068 | if (showLog) { 1069 | String info = "文件上传\n请求地址:" + requestMethod + "--->" + requestUrl; 1070 | if (requestBytes != null) info += "\n请求参数:" + new String(requestBytes); 1071 | info += "\n文件数:" + uploads.size(); 1072 | info += "\n请求异常:" + exceptionToString(e); 1073 | info += "\n耗时:" + (System.currentTimeMillis() - startTime) + "毫秒"; 1074 | println(info); 1075 | } 1076 | exception(e, listener); 1077 | } finally { 1078 | YHttpThreadPool.shutdown(); 1079 | } 1080 | }); 1081 | thread.setName("文件上传post:" + requestUrl); 1082 | YHttpThreadPool.add(thread); 1083 | } 1084 | 1085 | /** 1086 | * 文件上传post,返回对象 1087 | * 1088 | * @param requestUrl url 1089 | * @param paramsMap 参数 1090 | * @param uploads 上传对象列表 1091 | * @param listener 返回对象监听 1092 | */ 1093 | public void upload(String requestUrl, Map paramsMap, List uploads, YObjectListener listener) { 1094 | upload(requestUrl, YHttpUtils.mapToParams(paramsMap).toString().getBytes(), uploads, listener); 1095 | } 1096 | 1097 | /** 1098 | * 文件上传post,返回对象 1099 | * 1100 | * @param requestUrl url 1101 | * @param json json/文本 1102 | * @param uploads 上传对象列表 1103 | * @param listener 返回对象监听 1104 | */ 1105 | public void upload(String requestUrl, String json, List uploads, YObjectListener listener) { 1106 | if (getContentType() == null) setContentType("application/json;charset=utf-8"); 1107 | upload(requestUrl, json.getBytes(), uploads, listener); 1108 | } 1109 | 1110 | /** 1111 | * 文件上传post,返回对象 1112 | * 1113 | * @param requestUrl url 1114 | * @param requestBytes 参数 1115 | * @param uploads 上传对象列表 1116 | * @param listener 返回对象监听 1117 | */ 1118 | public void upload(final String requestUrl, final byte[] requestBytes, final List uploads, final YObjectListener listener) { 1119 | upload(requestUrl, requestBytes, uploads, new YHttpListener() { 1120 | @Override 1121 | public void success(byte[] bytes, String value) { 1122 | println("json转对象:" + listener.getType()); 1123 | try { 1124 | Android.runOnUiThread(() -> { 1125 | try { 1126 | if (String.class.equals(listener.getType())) { 1127 | listener.success(bytes, (T) value); 1128 | } else if ("byte[]".equals(listener.getType().toString())) { 1129 | listener.success(bytes, (T) bytes); 1130 | } else { 1131 | T object = getGson().fromJson(value, listener.getType()); 1132 | listener.success(bytes, object); 1133 | } 1134 | } catch (Exception e) { 1135 | listener.fail("异常:" + e.getMessage()); 1136 | e.printStackTrace(); 1137 | } 1138 | }); 1139 | } catch (java.lang.ClassCastException e) { 1140 | listener.fail("对象转换失败"); 1141 | e.printStackTrace(); 1142 | } catch (Exception e) { 1143 | listener.fail("异常:" + e.getMessage()); 1144 | e.printStackTrace(); 1145 | } 1146 | } 1147 | 1148 | @Override 1149 | public void fail(String value) { 1150 | listener.fail(value); 1151 | } 1152 | }); 1153 | } 1154 | 1155 | /** 1156 | * 文件下载,get请求,回调进度 1157 | * 1158 | * @param requestUrl url 1159 | * @param file 保存的文件 1160 | * @param listener 监听 1161 | */ 1162 | public void downloadFile(final String requestUrl, final File file, final YHttpDownloadFileListener listener) { 1163 | Thread thread = new Thread(() -> { 1164 | long startTime = System.currentTimeMillis(); 1165 | try { 1166 | downloadFile(requestUrl, file, (size, sizeCount) -> { 1167 | Android.runOnUiThread(() -> { 1168 | try { 1169 | listener.progress(size, sizeCount); 1170 | } catch (Exception e) { 1171 | listener.fail("异常:" + e.getMessage()); 1172 | e.printStackTrace(); 1173 | } 1174 | }); 1175 | }); 1176 | if (showLog) { 1177 | String info = "文件下载\n请求地址:" + "GET" + "--->" + requestUrl; 1178 | info += "\n保存成功:" + file.getPath(); 1179 | info += "\n耗时:" + (System.currentTimeMillis() - startTime) + "毫秒"; 1180 | println(info); 1181 | } 1182 | Android.runOnUiThread(() -> { 1183 | try { 1184 | listener.success(file); 1185 | } catch (Exception e) { 1186 | listener.fail("异常:" + e.getMessage()); 1187 | e.printStackTrace(); 1188 | } 1189 | }); 1190 | } catch (Exception e) { 1191 | if (showLog) { 1192 | String info = "文件下载\n请求地址:" + "GET" + "--->" + requestUrl; 1193 | info += "\n请求异常:" + exceptionToString(e); 1194 | info += "\n耗时:" + (System.currentTimeMillis() - startTime) + "毫秒"; 1195 | println(info); 1196 | } 1197 | exception(e, listener); 1198 | } finally { 1199 | YHttpThreadPool.shutdown(); 1200 | } 1201 | }); 1202 | thread.setName("文件下载,get:" + requestUrl); 1203 | YHttpThreadPool.add(thread); 1204 | } 1205 | 1206 | /** 1207 | * 加载get请求,回调进度 1208 | * 1209 | * @param requestUrl url 1210 | * @param listener 监听 1211 | */ 1212 | public void load(final String requestUrl, final YHttpLoadListener listener) { 1213 | Thread thread = new Thread(() -> { 1214 | long startTime = System.currentTimeMillis(); 1215 | try { 1216 | byte[] bytes = load(requestUrl, (size, sizeCount) -> { 1217 | Android.runOnUiThread(() -> { 1218 | try { 1219 | listener.progress(size, sizeCount); 1220 | } catch (Exception e) { 1221 | listener.fail("异常:" + e.getMessage()); 1222 | e.printStackTrace(); 1223 | } 1224 | }); 1225 | }); 1226 | if (showLog) { 1227 | String info = "文件加载\n请求地址:" + "GET" + "--->" + requestUrl; 1228 | info += "\n文件加载完成"; 1229 | info += "\n耗时:" + (System.currentTimeMillis() - startTime) + "毫秒"; 1230 | println(info); 1231 | } 1232 | Android.runOnUiThread(() -> { 1233 | try { 1234 | listener.success(bytes); 1235 | } catch (Exception e) { 1236 | listener.fail("异常:" + e.getMessage()); 1237 | e.printStackTrace(); 1238 | } 1239 | }); 1240 | } catch (Exception e) { 1241 | if (showLog) { 1242 | String info = "文件加载\n请求地址:" + "GET" + "--->" + requestUrl; 1243 | info += "\n请求异常:" + exceptionToString(e); 1244 | info += "\n耗时:" + (System.currentTimeMillis() - startTime) + "毫秒"; 1245 | println(info); 1246 | } 1247 | exception(e, listener); 1248 | } finally { 1249 | YHttpThreadPool.shutdown(); 1250 | } 1251 | }); 1252 | thread.setName("加载get请求,回调进度:" + requestUrl); 1253 | YHttpThreadPool.add(thread); 1254 | } 1255 | 1256 | /** 1257 | * 错误情况处理 1258 | * 1259 | * @param e 错误 1260 | * @param listener 监听 1261 | */ 1262 | void exception(Exception e, Object listener) { 1263 | Android.runOnUiThread(() -> { 1264 | error(exceptionToString(e), listener); 1265 | }); 1266 | } 1267 | 1268 | String exceptionToString(Exception e) { 1269 | if (e instanceof MalformedURLException) { 1270 | return "URL地址不规范"; 1271 | } else if (e instanceof java.net.SocketTimeoutException) { 1272 | return "网络连接超时"; 1273 | } else if (e instanceof UnsupportedEncodingException) { 1274 | return "不支持的编码"; 1275 | } else if (e instanceof FileNotFoundException) { 1276 | return "找不到该地址"; 1277 | } else if (e instanceof IOException) { 1278 | return "连接服务器失败"; 1279 | } else { 1280 | if ("终止下载".equals(e.getMessage())) { 1281 | return "终止下载"; 1282 | } else { 1283 | return "请求失败 " + e.getMessage(); 1284 | } 1285 | } 1286 | } 1287 | 1288 | /** 1289 | * 错误回调 1290 | * 1291 | * @param error 错误 1292 | * @param listener 监听 1293 | */ 1294 | void error(String error, Object listener) { 1295 | printlnE(error); 1296 | if (listener instanceof YHttpListener) { 1297 | ((YHttpListener) listener).fail(error); 1298 | } else if (listener instanceof YHttpLoadListener) { 1299 | ((YHttpLoadListener) listener).fail(error); 1300 | } else if (listener instanceof YHttpDownloadFileListener) { 1301 | ((YHttpDownloadFileListener) listener).fail(error); 1302 | } else if (listener instanceof YFailListener) { 1303 | ((YFailListener) listener).fail(error); 1304 | } 1305 | } 1306 | 1307 | /** 1308 | * 打印日志。如果发现包含Log就用Log打印,否则就用println 1309 | * 1310 | * @param str 日志 1311 | */ 1312 | void println(String str) { 1313 | if (Android.isAndroid()) { 1314 | println("d", "YHttp", str); 1315 | } else { 1316 | System.out.println(str); 1317 | } 1318 | } 1319 | 1320 | /** 1321 | * 打印错误日志。如果发现包含Log就用Log打印,否则就用println 1322 | * 1323 | * @param str 错误内容 1324 | */ 1325 | void printlnE(String str) { 1326 | if (Android.isAndroid()) { 1327 | println("e", "YHttp", str); 1328 | } else { 1329 | System.err.println(str); 1330 | } 1331 | } 1332 | 1333 | /** 1334 | * 打印日志 1335 | * 1336 | * @param tag tag 1337 | * @param msg 内容 1338 | */ 1339 | private static void println(String type, String tag, String msg) { 1340 | int LOG_MAX_LENGTH = 2000; 1341 | int strLength = msg.length(); 1342 | int start = 0; 1343 | int end = LOG_MAX_LENGTH; 1344 | for (int i = 0; i < (msg.length() / LOG_MAX_LENGTH + 1); i++) { 1345 | //剩下的文本还是大于规定长度则继续重复截取并输出 1346 | if (strLength > end) { 1347 | String s = tag + " " + i; 1348 | Android.Log(type, s, msg.substring(start, end)); 1349 | start = end; 1350 | end = end + LOG_MAX_LENGTH; 1351 | } else { 1352 | String s = i == 0 ? tag : tag + " " + i; 1353 | Android.Log(type, s, msg.substring(start, strLength)); 1354 | break; 1355 | } 1356 | } 1357 | } 1358 | } -------------------------------------------------------------------------------- /yhttp/src/main/java/com/yutils/http/YHttpBase.java: -------------------------------------------------------------------------------- 1 | package com.yutils.http; 2 | 3 | import com.yutils.http.contract.YHttpProgressListener; 4 | import com.yutils.http.contract.YSessionListener; 5 | import com.yutils.http.model.Upload; 6 | 7 | import java.io.ByteArrayOutputStream; 8 | import java.io.DataInputStream; 9 | import java.io.DataOutputStream; 10 | import java.io.File; 11 | import java.io.FileInputStream; 12 | import java.io.FileOutputStream; 13 | import java.io.IOException; 14 | import java.io.InputStream; 15 | import java.io.OutputStream; 16 | import java.net.HttpURLConnection; 17 | import java.util.ArrayList; 18 | import java.util.HashMap; 19 | import java.util.IdentityHashMap; 20 | import java.util.List; 21 | import java.util.Map; 22 | import java.util.Objects; 23 | 24 | /** 25 | * 网络请求基础类,柱塞式 26 | * 27 | * @author yujing 2020年7月28日10:22:35 28 | */ 29 | public class YHttpBase { 30 | protected String contentType = null;// "application/x-www-form-urlencoded;charset=utf-8";//"application/json;charset=utf-8" 31 | protected int connectTimeout = 1000 * 20; 32 | //userAgent,Android ----> Mozilla/5.0 (Linux; Android 8.0; Pixel 2 Build/OPD3.170816.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Mobile Safari/537.36 33 | //userAgent,iPhoneX ----> Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1 34 | //userAgent,iPad ----> Mozilla/5.0 (iPad; CPU OS 11_0 like Mac OS X) AppleWebKit/604.1.34 (KHTML, like Gecko) Version/11.0 Mobile/15A5341f Safari/604.1 Edg/85.0.4183.83 35 | //userAgent,windows10 ----> Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36 36 | protected String userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36"; 37 | /** 38 | * boundary就是request头和上传文件内容的分隔符 39 | */ 40 | protected static final String BOUNDARY = "------------YuJing---------------"; 41 | /** 42 | * session获取监听 43 | */ 44 | protected YSessionListener sessionListener; 45 | /** 46 | * SessionId 47 | */ 48 | protected String sessionId; 49 | /** 50 | * 下载是否停止 51 | */ 52 | protected boolean downLoadStop = false; 53 | 54 | //立即终止当前文件下载 55 | public void downloadFileStop() { 56 | downLoadStop = true; 57 | } 58 | 59 | //ContentType 60 | public String getContentType() { 61 | return contentType; 62 | } 63 | 64 | public YHttpBase setContentType(String contentType) { 65 | this.contentType = contentType; 66 | return this; 67 | } 68 | 69 | //Timeout 70 | public int getConnectTimeout() { 71 | return connectTimeout; 72 | } 73 | 74 | public YHttpBase setConnectTimeout(int connectTimeout) { 75 | this.connectTimeout = connectTimeout; 76 | return this; 77 | } 78 | 79 | //crt证书 80 | protected String crtSSL; 81 | 82 | public String getCrtSSL() { 83 | return crtSSL; 84 | } 85 | 86 | public YHttpBase setCrtSSL(String crtSSL) { 87 | this.crtSSL = crtSSL; 88 | return this; 89 | } 90 | 91 | //RequestProperty,请求头 92 | protected Map mapSetRequestProperty; 93 | protected Map mapAddRequestProperty; 94 | 95 | public YHttpBase setRequestProperty(String key, String value) { 96 | if (mapSetRequestProperty == null) 97 | mapSetRequestProperty = new HashMap<>(); 98 | mapSetRequestProperty.put(key, value); 99 | return this; 100 | } 101 | 102 | @SuppressWarnings("StringOperationCanBeSimplified") 103 | public YHttpBase addRequestProperty(String key, String value) { 104 | //可以重复key的map,但是key的内存地址要不一样 105 | if (mapAddRequestProperty == null) 106 | mapAddRequestProperty = new IdentityHashMap<>(); 107 | mapAddRequestProperty.put(new String(key), value); 108 | return this; 109 | } 110 | 111 | //session监听 112 | public YHttpBase setSessionListener(YSessionListener ySessionListener) { 113 | this.sessionListener = ySessionListener; 114 | return this; 115 | } 116 | 117 | //setSessionId 118 | public YHttpBase setSessionId(String sessionId) { 119 | this.sessionId = sessionId; 120 | return this; 121 | } 122 | 123 | /** 124 | * get请求,同步柱塞试 125 | * 126 | * @param requestUrl url 127 | * @return 请求结果 128 | * @throws Exception 异常 129 | */ 130 | public byte[] get(String requestUrl) throws Exception { 131 | return request(requestUrl, null, "GET"); 132 | } 133 | 134 | /** 135 | * post请求,同步柱塞试 136 | * 137 | * @param requestUrl rul 138 | * @param requestBytes 请求内容 139 | * @return 请求结果 140 | * @throws Exception 异常 141 | */ 142 | public byte[] post(String requestUrl, byte[] requestBytes) throws Exception { 143 | return request(requestUrl, requestBytes, "POST"); 144 | } 145 | 146 | /** 147 | * put请求,同步柱塞试 148 | * 149 | * @param requestUrl rul 150 | * @param requestBytes 请求内容 151 | * @return 请求结果 152 | * @throws Exception 异常 153 | */ 154 | public byte[] put(String requestUrl, byte[] requestBytes) throws Exception { 155 | return request(requestUrl, requestBytes, "PUT"); 156 | } 157 | 158 | /** 159 | * delete请求,同步柱塞试 160 | * 161 | * @param requestUrl rul 162 | * @param requestBytes 请求内容 163 | * @return 请求结果 164 | * @throws Exception 异常 165 | */ 166 | public byte[] delete(String requestUrl, byte[] requestBytes) throws Exception { 167 | return request(requestUrl, requestBytes, "DELETE"); 168 | } 169 | 170 | /** 171 | * delete请求,同步柱塞试 172 | * 173 | * @param requestUrl rul 174 | * @param requestBytes 请求内容 175 | * @param requestMethod 请求方式,只能是 "GET", "POST", "HEAD", "OPTIONS", "PUT", "DELETE", "TRACE" 176 | * @return 请求结果 177 | * @throws Exception 异常 178 | */ 179 | public byte[] request(String requestUrl, byte[] requestBytes, String requestMethod) throws Exception { 180 | // 打开一个HttpURLConnection连接 181 | HttpURLConnection urlConn = YHttpURLConnectionFactory.create(requestUrl, crtSSL); 182 | //设置从主机读取数据超时 183 | urlConn.setReadTimeout(connectTimeout); 184 | setHttpURLConnection(urlConn, requestMethod); 185 | if ("GET".equals(requestMethod)) { 186 | // 设置session 187 | setSession(urlConn); 188 | // 开始连接 189 | urlConn.connect(); 190 | // 获取session 191 | getSession(urlConn); 192 | // 判断请求是否成功 193 | int responseCode = urlConn.getResponseCode(); 194 | if (responseCode != HttpURLConnection.HTTP_OK) { 195 | throw new Exception("错误码:" + responseCode); 196 | } 197 | // 关闭连接 198 | } else { 199 | // 发送POST请求必须设置如下两行 200 | urlConn.setDoOutput(true); 201 | urlConn.setDoInput(true); 202 | // 设置session 203 | setSession(urlConn); 204 | // 开始连接 205 | urlConn.connect(); 206 | // 发送请求参数 207 | DataOutputStream dos = new DataOutputStream(urlConn.getOutputStream()); 208 | dos.write(requestBytes); 209 | dos.flush(); 210 | dos.close(); 211 | // 获取session 212 | getSession(urlConn); 213 | // 判断请求是否成功 214 | int responseCode = urlConn.getResponseCode(); 215 | if (responseCode != HttpURLConnection.HTTP_OK) { 216 | throw new Exception("错误码:" + responseCode); 217 | } 218 | } 219 | // 关闭连接 220 | byte[] bytes = YHttpUtils.inputStreamToBytes(urlConn.getInputStream()); 221 | urlConn.disconnect(); 222 | return bytes; 223 | } 224 | 225 | /** 226 | * 文件下载,同步柱塞试 227 | * 228 | * @param requestUrl url 229 | * @param file 下载的文件 230 | * @param listener 进度监听 231 | * @throws Exception 异常 232 | */ 233 | @SuppressWarnings("ResultOfMethodCallIgnored") 234 | public void downloadFile(String requestUrl, File file, YHttpProgressListener listener) throws Exception { 235 | File parent = file.getParentFile(); 236 | if (!Objects.requireNonNull(parent).exists()) parent.mkdirs(); 237 | if (file.exists()) file.delete();// 删除存在文件 238 | // 打开一个HttpURLConnection连接 239 | HttpURLConnection urlConn = YHttpURLConnectionFactory.create(requestUrl, crtSSL); 240 | setHttpURLConnection(urlConn, "GET"); 241 | // 设置session 242 | setSession(urlConn); 243 | // 开始连接 244 | urlConn.connect(); 245 | // 获取session 246 | getSession(urlConn); 247 | // 判断请求是否成功 248 | int responseCode = urlConn.getResponseCode(); 249 | if (responseCode != HttpURLConnection.HTTP_OK) { 250 | throw new Exception("错误码:" + responseCode); 251 | } 252 | int downloadSize = 0; 253 | int fileSize = urlConn.getContentLength(); // 获取不到文件大小时候fileSize=-1 254 | int len; 255 | byte[] buffer = new byte[1024 * 8]; 256 | FileOutputStream fos = new FileOutputStream(file); 257 | InputStream inputStream = urlConn.getInputStream(); 258 | downLoadStop = false;//这设置成false,在下载过程中downLoadIsStop的值可能会被改变 259 | while (!downLoadStop && (len = inputStream.read(buffer)) != -1) { 260 | // 写到本地 261 | fos.write(buffer, 0, len); 262 | downloadSize += len; 263 | listener.progress(downloadSize, fileSize); 264 | } 265 | if (downLoadStop) throw new Exception("终止下载"); 266 | // 关闭连接 267 | urlConn.disconnect(); 268 | } 269 | 270 | /** 271 | * 加载,同步柱塞试 272 | * 273 | * @param requestUrl url 274 | * @param listener 进度监听 275 | * @return 结果 276 | * @throws Exception 异常 277 | */ 278 | public byte[] load(String requestUrl, YHttpProgressListener listener) throws Exception { 279 | // 打开一个HttpURLConnection连接 280 | HttpURLConnection urlConn = YHttpURLConnectionFactory.create(requestUrl, crtSSL); 281 | urlConn.setAllowUserInteraction(true); 282 | setHttpURLConnection(urlConn, "GET"); 283 | // 设置session 284 | setSession(urlConn); 285 | // 开始连接 286 | urlConn.connect(); 287 | // 获取session 288 | getSession(urlConn); 289 | // 判断请求是否成功 290 | int responseCode = urlConn.getResponseCode(); 291 | if (responseCode != HttpURLConnection.HTTP_OK) { 292 | throw new Exception("错误码:" + responseCode); 293 | } 294 | int downloadSize = 0; 295 | int fileSize = urlConn.getContentLength(); // 获取不到文件大小时候fileSize=-1 296 | int len; 297 | byte[] buffer = new byte[1024 * 8]; 298 | ByteArrayOutputStream bs = new ByteArrayOutputStream(); 299 | InputStream inputStream = urlConn.getInputStream(); 300 | while ((len = inputStream.read(buffer)) != -1) { 301 | bs.write(buffer, 0, len); 302 | downloadSize += len; 303 | listener.progress(downloadSize, fileSize); 304 | } 305 | bs.flush(); 306 | byte[] bytes = bs.toByteArray(); 307 | // 关闭连接 308 | urlConn.disconnect(); 309 | return bytes; 310 | } 311 | 312 | /** 313 | * 文件上传,同步柱塞试 314 | * 315 | * @param requestUrl url 316 | * @param requestBytes 请求内容 317 | * @param fileMap key,文件 318 | * @return 请求结果 319 | * @throws Exception 异常 320 | */ 321 | public byte[] upload(String requestUrl, byte[] requestBytes, Map fileMap) throws Exception { 322 | List uploads = new ArrayList<>(); 323 | for (Map.Entry entry : fileMap.entrySet()) { 324 | if (entry.getValue() == null) continue; 325 | uploads.add(new Upload(entry.getKey(), entry.getValue())); 326 | } 327 | return upload(requestUrl, requestBytes, uploads); 328 | } 329 | 330 | /** 331 | * 文件上传,同步柱塞试 332 | * 333 | * @param requestUrl url 334 | * @param requestBytes 请求内容 335 | * @param uploads 上传的key,内容,文件名,contentType 336 | * @return 请求结果 337 | * @throws Exception 异常 338 | */ 339 | public byte[] upload(String requestUrl, byte[] requestBytes, List uploads) throws Exception { 340 | // 打开一个HttpURLConnection连接 341 | HttpURLConnection urlConn = YHttpURLConnectionFactory.create(requestUrl, crtSSL); 342 | //设置从主机读取数据超时 343 | urlConn.setReadTimeout(connectTimeout); 344 | setContentType("multipart/form-data; boundary=" + BOUNDARY); 345 | setHttpURLConnection(urlConn, "POST"); 346 | // 设置session 347 | setSession(urlConn); 348 | // 发送POST请求必须设置如下两行 349 | urlConn.setDoOutput(true); 350 | urlConn.setDoInput(true); 351 | // 开始连接 352 | urlConn.connect(); 353 | // 发送请求参数 354 | send(urlConn, requestBytes, uploads); 355 | // 获取session 356 | getSession(urlConn); 357 | // 判断请求是否成功 358 | int responseCode = urlConn.getResponseCode(); 359 | if (responseCode != HttpURLConnection.HTTP_OK) { 360 | throw new Exception("错误码:" + responseCode); 361 | } 362 | byte[] bytes = YHttpUtils.inputStreamToBytes(urlConn.getInputStream()); 363 | // 关闭连接 364 | urlConn.disconnect(); 365 | return bytes; 366 | } 367 | 368 | /** 369 | * 发送文件的数据组装 370 | * 371 | * @param httpURLConnection 连接对象 372 | * @param requestBytes 请求的参数 373 | * @param uploads 上传的文件 374 | * @throws IOException 异常 375 | */ 376 | protected void send(HttpURLConnection httpURLConnection, byte[] requestBytes, List uploads) throws IOException { 377 | OutputStream out = new DataOutputStream(httpURLConnection.getOutputStream()); 378 | // 文本参数 379 | if (requestBytes != null) out.write(requestBytes); 380 | // 文件 381 | if (uploads != null) { 382 | for (Upload item : uploads) { 383 | if (item.getBytes() != null) { 384 | StringBuilder strBuf = new StringBuilder(); 385 | strBuf.append("\r\n--").append(BOUNDARY).append("\r\n") 386 | .append("Content-Disposition: form-data; name=\"") 387 | .append(item.getKey()) 388 | .append("\"; filename=\"") 389 | .append(item.getFilename()) 390 | .append("\"\r\n"); 391 | strBuf.append("Content-Type:").append(item.getContentType()).append("\r\n\r\n"); 392 | out.write(strBuf.toString().getBytes()); 393 | out.write(item.getBytes()); 394 | } else if (item.getFile() != null) { 395 | StringBuilder strBuf = new StringBuilder(); 396 | strBuf.append("\r\n--").append(BOUNDARY).append("\r\n") 397 | .append("Content-Disposition: form-data; name=\"") 398 | .append(item.getKey()) 399 | .append("\"; filename=\"") 400 | .append(item.getFilename()) 401 | .append("\"\r\n"); 402 | strBuf.append("Content-Type:").append(item.getContentType()).append("\r\n\r\n"); 403 | out.write(strBuf.toString().getBytes()); 404 | DataInputStream in = new DataInputStream(new FileInputStream(item.getFile())); 405 | int bytes; 406 | byte[] bufferOut = new byte[1024 * 8]; 407 | while ((bytes = in.read(bufferOut)) != -1) 408 | out.write(bufferOut, 0, bytes); 409 | in.close(); 410 | } else { 411 | try { 412 | Class.forName("android.graphics.Bitmap"); 413 | if (item.getBitmap() != null) { 414 | StringBuilder strBuf = new StringBuilder(); 415 | strBuf.append("\r\n--").append(BOUNDARY).append("\r\n") 416 | .append("Content-Disposition: form-data; name=\"") 417 | .append(item.getKey()) 418 | .append("\"; filename=\"") 419 | .append(item.getFilename()) 420 | .append("\"\r\n"); 421 | strBuf.append("Content-Type:").append(item.getContentType()).append("\r\n\r\n"); 422 | out.write(strBuf.toString().getBytes()); 423 | // bitmap转Bytes 424 | byte[] bytes = Android.bitmapToByteArray(item.getBitmap()); 425 | out.write(bytes); 426 | } 427 | } catch (Exception e) { 428 | System.err.println("上传Bitmap异常:" + e.getMessage()); 429 | } 430 | } 431 | } 432 | } 433 | out.write(("\r\n--" + BOUNDARY + "--\r\n").getBytes());// 结束标记 434 | out.flush(); 435 | out.close(); 436 | } 437 | 438 | /** 439 | * HttpURLConnection 的一些基础设置 440 | * 441 | * @param urlConn 连接 442 | * @param requestMethod 请求类型 443 | * @throws Exception Exception 444 | */ 445 | private void setHttpURLConnection(HttpURLConnection urlConn, String requestMethod) throws Exception { 446 | // 设置连接超时时间 447 | urlConn.setConnectTimeout(connectTimeout); 448 | //设置请求允许输入 默认是true 449 | urlConn.setDoInput(true); 450 | // Post请求不能使用缓存 451 | urlConn.setUseCaches(false); 452 | // 设置为请求类型 453 | if (requestMethod != null) 454 | urlConn.setRequestMethod(requestMethod); 455 | //设置本次连接是否自动处理重定向 456 | urlConn.setInstanceFollowRedirects(true); 457 | // 配置请求Content-Type 458 | urlConn.setRequestProperty("accept", "*/*"); 459 | urlConn.setRequestProperty("connection", "Keep-Alive"); 460 | urlConn.setRequestProperty("Charset", "utf-8"); 461 | urlConn.setRequestProperty("Content-Type", contentType == null ? "application/x-www-form-urlencoded;charset=utf-8" : contentType); 462 | urlConn.setRequestProperty("User-Agent", userAgent); 463 | if (mapSetRequestProperty != null) 464 | for (Map.Entry entry : mapSetRequestProperty.entrySet()) 465 | urlConn.setRequestProperty(entry.getKey(), entry.getValue()); 466 | if (mapAddRequestProperty != null) 467 | for (Map.Entry entry : mapAddRequestProperty.entrySet()) 468 | urlConn.addRequestProperty(entry.getKey(), entry.getValue()); 469 | } 470 | 471 | /** 472 | * 设置session,把JSESSIONID变量的值设置成session 473 | * 474 | * @param httpURLConnection httpURLConnection 475 | */ 476 | public void setSession(HttpURLConnection httpURLConnection) { 477 | if (sessionId != null && !sessionId.isEmpty()) { 478 | httpURLConnection.setRequestProperty("Cookie", "JSESSIONID=" + sessionId); 479 | } 480 | } 481 | 482 | /** 483 | * 获取session 并保存到JSESSIONID变量 484 | * 485 | * @param httpURLConnection httpURLConnection 486 | */ 487 | public void getSession(HttpURLConnection httpURLConnection) { 488 | Map> map = httpURLConnection.getHeaderFields(); 489 | if (map != null) { 490 | List list = map.get("Set-Cookie"); 491 | if (list != null) { 492 | for (int i = 0; i < list.size(); i++) { 493 | //System.out.println("Set-Cookie:"+list.get(i)); 494 | int start = list.get(i).indexOf("JSESSIONID"); 495 | if (start != -1) { 496 | int idStart = start + 10 + 1; 497 | int idEnd = start + 10 + 1 + 32; 498 | if (list.get(i).length() >= idEnd) { 499 | String JSESSIONID = list.get(i).substring(idStart, idEnd);// 如:list.get(i)="JSESSIONID=743D39694F006763220CA0CA63FE8978"; 500 | if (sessionListener != null) 501 | Android.runOnUiThread(() -> sessionListener.sessionId(JSESSIONID)); 502 | sessionId = JSESSIONID; 503 | } 504 | } 505 | } 506 | } 507 | } 508 | } 509 | } 510 | -------------------------------------------------------------------------------- /yhttp/src/main/java/com/yutils/http/YHttpThreadPool.java: -------------------------------------------------------------------------------- 1 | package com.yutils.http; 2 | 3 | import java.util.concurrent.ScheduledThreadPoolExecutor; 4 | 5 | /** 6 | * 线程池管理类 7 | * 8 | * @author yujing 2020年7月28日10:22:35 9 | */ 10 | public class YHttpThreadPool { 11 | private static volatile int threadNum = 20; 12 | private static ScheduledThreadPoolExecutor sTpe = new ScheduledThreadPoolExecutor(threadNum); 13 | 14 | /** 15 | * 停止当前队列中全部请求 16 | */ 17 | public static void stopAll() { 18 | if (sTpe != null) 19 | sTpe.getQueue().clear(); 20 | } 21 | 22 | /** 23 | * 把一个线程扔进线程池 24 | * 25 | * @param runnable 要执行的线程 26 | */ 27 | public synchronized static void add(Runnable runnable) { 28 | synchronized (sTpe) { 29 | if (sTpe.isShutdown()) { 30 | sTpe = new ScheduledThreadPoolExecutor(threadNum); 31 | synchronized (sTpe) { 32 | sTpe.execute(runnable); 33 | } 34 | } else { 35 | sTpe.execute(runnable); 36 | } 37 | } 38 | } 39 | 40 | /** 41 | * 获取当前有多少线程 42 | * 43 | * @return 线程数量 44 | */ 45 | public static int getPoolSize() { 46 | return sTpe.isShutdown() ? -1 : sTpe.getPoolSize(); 47 | } 48 | 49 | /** 50 | * 关闭释放线程池 51 | */ 52 | public synchronized static void shutdown() { 53 | synchronized (sTpe) { 54 | if (!sTpe.isShutdown()) 55 | sTpe.shutdown(); 56 | } 57 | } 58 | 59 | /** 60 | * 释放当前线程池,并重新创建线程池一个最大值未threadNum的线程池 61 | * 62 | * @param threadNum 线程池最大值 63 | */ 64 | public static void setThreadNum(int threadNum) { 65 | YHttpThreadPool.threadNum = threadNum; 66 | shutdown(); 67 | sTpe = new ScheduledThreadPoolExecutor(threadNum); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /yhttp/src/main/java/com/yutils/http/YHttpURLConnectionFactory.java: -------------------------------------------------------------------------------- 1 | package com.yutils.http; 2 | 3 | import java.io.ByteArrayInputStream; 4 | import java.net.HttpURLConnection; 5 | import java.net.URL; 6 | import java.security.KeyStore; 7 | import java.security.SecureRandom; 8 | import java.security.cert.Certificate; 9 | import java.security.cert.CertificateFactory; 10 | import java.security.cert.X509Certificate; 11 | import java.util.Locale; 12 | 13 | import javax.net.ssl.HttpsURLConnection; 14 | import javax.net.ssl.SSLContext; 15 | import javax.net.ssl.SSLSocketFactory; 16 | import javax.net.ssl.TrustManager; 17 | import javax.net.ssl.TrustManagerFactory; 18 | import javax.net.ssl.X509TrustManager; 19 | 20 | /** 21 | * HttpURLConnection工厂,如果带有crtString,就创建HTTPS请求,否则就HTTP请求 22 | * 23 | * @author yujing 2020年7月28日10:22:35 24 | */ 25 | public class YHttpURLConnectionFactory { 26 | /** 27 | * 创建HttpURLConnection对象,如果请求包含https就创建HttpsURLConnection,并且创建证书 28 | * 29 | * @param url 请求地址 30 | * @param crtSSL crt证书 31 | * @return HttpURLConnection 32 | * @throws Exception Exception 33 | */ 34 | public static HttpURLConnection create(String url, String crtSSL) throws Exception { 35 | if (crtSSL != null && (url.toLowerCase(Locale.getDefault()).contains("https://"))) { 36 | HttpsURLConnection httpsURLConnection = (HttpsURLConnection) (new URL(url)).openConnection(); 37 | httpsURLConnection.setSSLSocketFactory(createSSLSocketFactory(crtSSL)); 38 | //屏蔽https验证 39 | httpsURLConnection.setHostnameVerifier((hostname, session) -> true); 40 | return httpsURLConnection; 41 | } else { 42 | return (HttpURLConnection) (new URL(url)).openConnection(); 43 | } 44 | } 45 | 46 | /** 47 | * 创建SSL套接字工厂 48 | * 49 | * @param crtString crt证书 50 | * @return SSLSocketFactory 51 | * @throws Exception Exception 52 | */ 53 | private static SSLSocketFactory createSSLSocketFactory(String crtString) throws Exception { 54 | CertificateFactory cf = CertificateFactory.getInstance("X.509"); 55 | //如果是src/main/assets/test.crt,直接获取InputStream:getAssets().open("test.crt") 56 | Certificate ca = cf.generateCertificate(new ByteArrayInputStream(crtString.getBytes())); 57 | 58 | String keyStoreType = KeyStore.getDefaultType(); 59 | KeyStore keyStore = KeyStore.getInstance(keyStoreType); 60 | keyStore.load(null, null); 61 | keyStore.setCertificateEntry("ca", ca); 62 | 63 | String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm(); 64 | TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm); 65 | tmf.init(keyStore); 66 | 67 | SSLContext context = SSLContext.getInstance("TLS"); 68 | context.init(null, new TrustManager[]{new X509TrustManager() { 69 | @Override 70 | public void checkClientTrusted(X509Certificate[] chain, String authType) { 71 | 72 | } 73 | 74 | @Override 75 | public void checkServerTrusted(X509Certificate[] chain, String authType) { 76 | 77 | } 78 | 79 | @Override 80 | public X509Certificate[] getAcceptedIssuers() { 81 | return new X509Certificate[0]; 82 | } 83 | }}, new SecureRandom()); 84 | return context.getSocketFactory(); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /yhttp/src/main/java/com/yutils/http/YHttpUtils.java: -------------------------------------------------------------------------------- 1 | package com.yutils.http; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.IOException; 5 | import java.io.InputStream; 6 | import java.util.Map; 7 | 8 | /** 9 | * 网络请求工具类 10 | * 11 | * @author 2020年7月28日10:22:35 12 | */ 13 | public class YHttpUtils { 14 | /** 15 | * 请求map转换成String 16 | * 17 | * @param paramsMap paramsMap 18 | * @return StringBuffer 19 | */ 20 | public static StringBuffer mapToParams(Map paramsMap) { 21 | if (paramsMap == null) { 22 | return null; 23 | } 24 | StringBuffer params = new StringBuffer(); 25 | for (Map.Entry element : paramsMap.entrySet()) { 26 | if (element.getValue() == null) 27 | continue; 28 | params.append(element.getKey()).append("=").append(element.getValue()).append("&"); 29 | } 30 | if (params.length() > 0) 31 | params.deleteCharAt(params.length() - 1); 32 | return params; 33 | } 34 | 35 | /** 36 | * inputStream 转换成byte[] 37 | * 38 | * @param inputStream inputStream 39 | * @return byte[] 40 | * @throws IOException IOException 41 | */ 42 | public static byte[] inputStreamToBytes(InputStream inputStream) throws IOException { 43 | ByteArrayOutputStream bs = new ByteArrayOutputStream(); 44 | byte[] buffer = new byte[1024]; 45 | int len; 46 | while ((len = inputStream.read(buffer)) != -1) { 47 | bs.write(buffer, 0, len); 48 | } 49 | bs.flush(); 50 | return bs.toByteArray(); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /yhttp/src/main/java/com/yutils/http/contract/ObjectListener.java: -------------------------------------------------------------------------------- 1 | package com.yutils.http.contract; 2 | 3 | import java.lang.reflect.ParameterizedType; 4 | import java.lang.reflect.Type; 5 | 6 | /** 7 | * 请求结果返回对象监听 8 | * 【注意:】此处不能用interface只能使用 abstract class,因为要取出泛型T的具体实现类型, 9 | * interface不能取出T类型, 10 | * 所以只能采用abstract class。 11 | * 12 | * @param 泛型 13 | * @author 余静 2021年3月25日10:00:11 14 | */ 15 | 16 | public abstract class ObjectListener { 17 | private final Type type; 18 | 19 | protected ObjectListener() { 20 | //取出泛型具体类型 21 | type = getSuperclassTypeParameter(getClass()); 22 | } 23 | 24 | //取出class的父类泛类类型 25 | static Type getSuperclassTypeParameter(Class subclass) { 26 | Type superclass = subclass.getGenericSuperclass(); 27 | if (superclass instanceof Class) { 28 | throw new RuntimeException("Missing type parameter."); 29 | } 30 | ParameterizedType parameterized = (ParameterizedType) superclass; 31 | return parameterized.getActualTypeArguments()[0]; 32 | } 33 | 34 | /** 35 | * 取出泛型的具体类型 36 | * 37 | * @return Type 38 | */ 39 | public Type getType() { 40 | return type; 41 | } 42 | 43 | public abstract void success(byte[] bytes, T value); 44 | } -------------------------------------------------------------------------------- /yhttp/src/main/java/com/yutils/http/contract/YFailListener.java: -------------------------------------------------------------------------------- 1 | package com.yutils.http.contract; 2 | 3 | /** 4 | * 失败监听 5 | * @author yujing 2021年3月24日23:24:09 6 | */ 7 | public interface YFailListener { 8 | void fail(String value); 9 | } 10 | -------------------------------------------------------------------------------- /yhttp/src/main/java/com/yutils/http/contract/YHttpDownloadFileListener.java: -------------------------------------------------------------------------------- 1 | package com.yutils.http.contract; 2 | 3 | import java.io.File; 4 | 5 | /** 6 | * 文件下载监听 7 | * 8 | * @author yujing 2020年7月28日10:23:26 9 | */ 10 | public interface YHttpDownloadFileListener extends YHttpProgressListener, YFailListener { 11 | void success(File file); 12 | } -------------------------------------------------------------------------------- /yhttp/src/main/java/com/yutils/http/contract/YHttpListener.java: -------------------------------------------------------------------------------- 1 | package com.yutils.http.contract; 2 | 3 | /** 4 | * 请求信息监听 5 | * 6 | * @author 余静 2020年7月28日10:23:26 7 | */ 8 | public interface YHttpListener extends YSuccessListener, YFailListener { 9 | } -------------------------------------------------------------------------------- /yhttp/src/main/java/com/yutils/http/contract/YHttpLoadListener.java: -------------------------------------------------------------------------------- 1 | package com.yutils.http.contract; 2 | 3 | /** 4 | * 文件下载监听 5 | * 6 | * @author yujing 2020年7月28日10:23:26 7 | */ 8 | public interface YHttpLoadListener extends YHttpProgressListener, YFailListener { 9 | void success(byte[] bytes); 10 | } -------------------------------------------------------------------------------- /yhttp/src/main/java/com/yutils/http/contract/YHttpProgressListener.java: -------------------------------------------------------------------------------- 1 | package com.yutils.http.contract; 2 | 3 | /** 4 | * 进度监听 5 | * 6 | * @author yujing 2020年7月28日10:23:26 7 | */ 8 | public interface YHttpProgressListener { 9 | void progress(int size, int sizeCount); 10 | } 11 | -------------------------------------------------------------------------------- /yhttp/src/main/java/com/yutils/http/contract/YObjectListener.java: -------------------------------------------------------------------------------- 1 | package com.yutils.http.contract; 2 | 3 | import java.lang.reflect.ParameterizedType; 4 | import java.lang.reflect.Type; 5 | 6 | /** 7 | * 请求结果返回对象监听 8 | * 【注意:】此处不能用interface只能使用 abstract class,因为要取出泛型T的具体实现类型, 9 | * interface不能取出T类型, 10 | * 所以只能采用abstract class。 11 | * 12 | * @param 泛型 13 | * @author 余静 2020年7月28日10:23:26 14 | */ 15 | 16 | public abstract class YObjectListener extends ObjectListener implements YFailListener { 17 | private final Type type; 18 | 19 | protected YObjectListener() { 20 | //取出泛型具体类型 21 | type = getSuperclassTypeParameter(getClass()); 22 | } 23 | 24 | //取出class的父类泛类类型 25 | static Type getSuperclassTypeParameter(Class subclass) { 26 | Type superclass = subclass.getGenericSuperclass(); 27 | if (superclass instanceof Class) { 28 | throw new RuntimeException("Missing type parameter."); 29 | } 30 | ParameterizedType parameterized = (ParameterizedType) superclass; 31 | return parameterized.getActualTypeArguments()[0]; 32 | } 33 | 34 | /** 35 | * 取出泛型的具体类型 36 | * 37 | * @return Type 38 | */ 39 | public Type getType() { 40 | return type; 41 | } 42 | 43 | public abstract void success(byte[] bytes, T value); 44 | } -------------------------------------------------------------------------------- /yhttp/src/main/java/com/yutils/http/contract/YSessionListener.java: -------------------------------------------------------------------------------- 1 | package com.yutils.http.contract; 2 | 3 | /** 4 | * sessionId 监听 5 | * 返回值为新的sessionId 6 | * @author 余静 2020年7月28日10:23:26 7 | */ 8 | public interface YSessionListener { 9 | void sessionId(String sessionId); 10 | } -------------------------------------------------------------------------------- /yhttp/src/main/java/com/yutils/http/contract/YSuccessListener.java: -------------------------------------------------------------------------------- 1 | package com.yutils.http.contract; 2 | 3 | /** 4 | * 成功监听 5 | * 6 | * @author 余静 2021年3月24日23:24:03 7 | */ 8 | public interface YSuccessListener { 9 | void success(byte[] bytes, String value) throws Exception; 10 | } -------------------------------------------------------------------------------- /yhttp/src/main/java/com/yutils/http/model/Upload.java: -------------------------------------------------------------------------------- 1 | package com.yutils.http.model; 2 | 3 | import java.io.File; 4 | 5 | /** 6 | * 上传文件实体 7 | * 8 | * @author yujing 2020年8月28日12:08:34 9 | * 上传文件,检查到bytes不为null就走bytes,其次file,其次bitmap 10 | */ 11 | /* 12 | //java文件上传 13 | String url = "http://192.168.6.9:8090/crash/upload/file"; 14 | List uploads = new ArrayList<>(); 15 | uploads.add(new Upload("file1", new File("D:/1.jpg"))); 16 | uploads.add(new Upload("file2", "ABCDEF".getBytes()).setFilename("abcd.txt")); 17 | 18 | YHttp.create().setSessionId(session).upload(url, "", uploads, new YHttpListener() { 19 | @Override 20 | public void success(byte[] bytes, String value){ 21 | System.out.println("上传成功:" + value); 22 | } 23 | @Override 24 | public void fail(String value) { 25 | System.out.println("上传失败:" + value); 26 | } 27 | }); 28 | */ 29 | public class Upload { 30 | /** 31 | * 上传文件的key值 32 | */ 33 | private String key; 34 | 35 | /** 36 | * 文件内容为byte[],与File,Bitmap,互斥 37 | */ 38 | private byte[] bytes; 39 | 40 | /** 41 | * 文件内容为file,与byte[],Bitmap,互斥 42 | */ 43 | private File file; 44 | 45 | /** 46 | * 文件内容为object,与File,byte[],互斥 47 | * 为了兼容java原生项目,所以此处设置为Object 48 | */ 49 | private Object object; 50 | 51 | /** 52 | * 文件名 53 | */ 54 | private String filename; 55 | 56 | /** 57 | * 此文件的contentType 58 | */ 59 | private String contentType; 60 | 61 | public Upload(String key, byte[] bytes) { 62 | this.key = key; 63 | this.bytes = bytes; 64 | filename = key; 65 | contentType = "application/octet-stream"; 66 | } 67 | 68 | public Upload(String key, File file) { 69 | this.key = key; 70 | this.file = file; 71 | filename = file.getName(); 72 | if (file.getName().lastIndexOf(".png") != -1) { 73 | contentType = "image/png"; 74 | } else if (file.getName().lastIndexOf(".jpg") != -1 || file.getName().lastIndexOf(".jpeg") != -1) { 75 | contentType = "image/jpeg"; 76 | } else { 77 | contentType = "application/octet-stream"; 78 | } 79 | } 80 | 81 | public Upload(String key, Object object) { 82 | this.key = key; 83 | this.object = object; 84 | filename = key; 85 | filename = "image" + System.currentTimeMillis() + ".jpg"; 86 | contentType = "image/jpeg"; 87 | } 88 | 89 | public String getKey() { 90 | return key; 91 | } 92 | 93 | public byte[] getBytes() { 94 | return bytes; 95 | } 96 | 97 | public File getFile() { 98 | return file; 99 | } 100 | 101 | public Object getBitmap() { 102 | return object; 103 | } 104 | 105 | public String getFilename() { 106 | return filename; 107 | } 108 | 109 | public Upload setFilename(String filename) { 110 | this.filename = filename; 111 | return this; 112 | } 113 | 114 | public String getContentType() { 115 | return contentType; 116 | } 117 | 118 | public Upload setContentType(String contentType) { 119 | this.contentType = contentType; 120 | return this; 121 | } 122 | } 123 | --------------------------------------------------------------------------------