├── .gitignore ├── EasyRxRetrofit ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── jimi_wu │ │ └── easyrxretrofit │ │ ├── RetrofitManager.java │ │ ├── agent │ │ └── AgentInterceptor.java │ │ ├── build │ │ ├── DefaultRetrofitBuilder.java │ │ └── RetrofitBuilder.java │ │ ├── cookie │ │ ├── CookieManager.java │ │ ├── CookieStore.java │ │ └── OkHttpCookies.java │ │ ├── download │ │ ├── DownLoadOnSubscribe.java │ │ ├── DownLoadService.java │ │ └── DownLoadTransformer.java │ │ ├── exception │ │ └── ServerException.java │ │ ├── observer │ │ ├── BaseObserver.java │ │ ├── DownLoadObserver.java │ │ └── UploadObserver.java │ │ ├── transformer │ │ ├── BaseModel.java │ │ └── BaseModelTransformer.java │ │ ├── upload │ │ ├── UploadOnSubscribe.java │ │ ├── UploadParam.java │ │ ├── UploadRequestBody.java │ │ └── UploadService.java │ │ └── utils │ │ └── FileUtils.java │ └── res │ └── values │ └── strings.xml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── jimi_wu │ │ └── sample │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── jimi_wu │ │ │ └── sample │ │ │ ├── Constants.java │ │ │ ├── FileUtils.java │ │ │ ├── MainActivity.java │ │ │ ├── apiservice │ │ │ └── GetUserService.java │ │ │ ├── application │ │ │ ├── SampleApplication.java │ │ │ └── SampleRetrofitBuilder.java │ │ │ └── model │ │ │ ├── FileBean.java │ │ │ ├── ResultBean.java │ │ │ └── UserBean.java │ └── res │ │ ├── layout │ │ └── activity_main.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 │ └── test │ └── java │ └── com │ └── jimi_wu │ └── sample │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .externalNativeBuild 10 | 11 | .idea/ 12 | gradlew 13 | gradlew.bat -------------------------------------------------------------------------------- /EasyRxRetrofit/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /EasyRxRetrofit/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply plugin: 'com.github.dcendents.android-maven' 3 | apply plugin: 'com.jfrog.bintray' 4 | 5 | android { 6 | compileSdkVersion 25 7 | buildToolsVersion "25.0.0" 8 | resourcePrefix "init" 9 | 10 | defaultConfig { 11 | minSdkVersion 15 12 | targetSdkVersion 25 13 | versionCode 200 14 | versionName "2.0.0" 15 | } 16 | buildTypes { 17 | release { 18 | minifyEnabled false 19 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 20 | } 21 | } 22 | 23 | lintOptions { 24 | abortOnError false 25 | } 26 | } 27 | 28 | dependencies { 29 | // rxjava 30 | implementation 'io.reactivex.rxjava2:rxandroid:2.1.0' 31 | implementation 'io.reactivex.rxjava2:rxjava:2.2.2' 32 | // retrofit 33 | implementation 'com.squareup.retrofit2:retrofit:2.4.0' 34 | implementation 'com.squareup.retrofit2:adapter-rxjava2:2.4.0' 35 | //gson 36 | implementation 'com.squareup.retrofit2:converter-gson:2.4.0' 37 | } 38 | 39 | version = "2.0.0" 40 | def siteUrl = 'https://github.com/whichname/EasyRxRetrofit' // 项目的主页 41 | def gitUrl = 'https://github.com/whichname/EasyRxRetrofit.git' // Git仓库的url 42 | group = "com.jimi_wu" // Maven Group ID for the artifact,一般填你唯一的包名 43 | install { 44 | repositories.mavenInstaller { 45 | // This generates POM.xml with proper parameters 46 | pom { 47 | project { 48 | packaging 'aar' 49 | // Add your description here 50 | name 'EasyRxRetrofit' 51 | url siteUrl 52 | // Set your license 53 | licenses { 54 | license { 55 | name 'The Apache Software License, Version 2.0' 56 | url 'http://www.apache.org/licenses/LICENSE-2.0.txt' 57 | } 58 | } 59 | developers { 60 | developer { 61 | id 'whichname' //填写的一些基本信息 62 | name 'jimi_wu' 63 | } 64 | } 65 | scm { 66 | connection gitUrl 67 | developerConnection siteUrl 68 | url siteUrl 69 | } 70 | } 71 | } 72 | } 73 | } 74 | task sourcesJar(type: Jar) { 75 | from android.sourceSets.main.java.srcDirs 76 | classifier = 'sources' 77 | } 78 | task javadoc(type: Javadoc) { 79 | options.encoding = "utf-8" 80 | source = android.sourceSets.main.java.srcDirs 81 | classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) 82 | } 83 | task javadocJar(type: Jar, dependsOn: javadoc) { 84 | classifier = 'javadoc' 85 | from javadoc.destinationDir 86 | } 87 | artifacts { 88 | archives javadocJar 89 | archives sourcesJar 90 | } 91 | Properties properties = new Properties() 92 | properties.load(project.rootProject.file('local.properties').newDataInputStream()) 93 | bintray { 94 | user = properties.getProperty("bintray.user") 95 | key = properties.getProperty("bintray.apikey") 96 | configurations = ['archives'] 97 | pkg { 98 | repo = "maven" 99 | name = "EasyRxRetrofit" //发布到JCenter上的项目名字 100 | websiteUrl = siteUrl 101 | vcsUrl = gitUrl 102 | licenses = ["Apache-2.0"] 103 | publish = true 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /EasyRxRetrofit/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/wuzhiming/Library/Android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | # Uncomment this to preserve the line number information for 20 | # debugging stack traces. 21 | #-keepattributes SourceFile,LineNumberTable 22 | 23 | # If you keep the line number information, uncomment this to 24 | # hide the original source file name. 25 | #-renamesourcefileattribute SourceFile 26 | -------------------------------------------------------------------------------- /EasyRxRetrofit/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | 9 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /EasyRxRetrofit/src/main/java/com/jimi_wu/easyrxretrofit/RetrofitManager.java: -------------------------------------------------------------------------------- 1 | package com.jimi_wu.easyrxretrofit; 2 | 3 | import android.text.TextUtils; 4 | 5 | import com.jimi_wu.easyrxretrofit.build.DefaultRetrofitBuilder; 6 | import com.jimi_wu.easyrxretrofit.build.RetrofitBuilder; 7 | import com.jimi_wu.easyrxretrofit.download.DownLoadService; 8 | import com.jimi_wu.easyrxretrofit.download.DownLoadTransformer; 9 | import com.jimi_wu.easyrxretrofit.transformer.BaseModel; 10 | import com.jimi_wu.easyrxretrofit.transformer.BaseModelTransformer; 11 | import com.jimi_wu.easyrxretrofit.upload.UploadOnSubscribe; 12 | import com.jimi_wu.easyrxretrofit.upload.UploadParam; 13 | import com.jimi_wu.easyrxretrofit.upload.UploadRequestBody; 14 | import com.jimi_wu.easyrxretrofit.upload.UploadService; 15 | import com.jimi_wu.easyrxretrofit.utils.FileUtils; 16 | 17 | import java.util.ArrayList; 18 | import java.util.Arrays; 19 | import java.util.List; 20 | 21 | import io.reactivex.Observable; 22 | import io.reactivex.ObservableTransformer; 23 | import okhttp3.MultipartBody; 24 | import okhttp3.ResponseBody; 25 | import retrofit2.Retrofit; 26 | 27 | /** 28 | * Created by wzm on 2017/6/14. 29 | */ 30 | public class RetrofitManager { 31 | 32 | /** 33 | * 初始化 34 | */ 35 | private static Retrofit mRetrofit; 36 | 37 | public static void init(RetrofitBuilder builder) { 38 | mRetrofit = builder.initRetrofit(); 39 | } 40 | 41 | public static Retrofit getRetrofit() { 42 | if (mRetrofit == null) { 43 | mRetrofit = new DefaultRetrofitBuilder().initRetrofit(); 44 | } 45 | return mRetrofit; 46 | } 47 | 48 | /** 49 | * 创建请求 50 | */ 51 | public static T createService(final Class service) { 52 | return getRetrofit().create(service); 53 | } 54 | 55 | /** 56 | * 转换 57 | */ 58 | public static ObservableTransformer, T> handleResult() { 59 | return new BaseModelTransformer<>(); 60 | } 61 | 62 | 63 | /** 64 | * 下载 65 | */ 66 | public static Observable download(String url) { 67 | return RetrofitManager.download(url, null, null); 68 | } 69 | 70 | public static Observable download(String url, String savePath, String fileName) { 71 | return RetrofitManager.createService(DownLoadService.class) 72 | .startDownLoad(url) 73 | .compose(RetrofitManager.handleDownload(url, savePath, fileName)); 74 | } 75 | 76 | /** 77 | * 下载监听转换 78 | */ 79 | public static ObservableTransformer handleDownload(String url, String savePath, String fileName) { 80 | if (TextUtils.isEmpty(savePath)) { 81 | savePath = FileUtils.getDefaultDownLoadPath(); 82 | } 83 | if (TextUtils.isEmpty(fileName)) { 84 | fileName = FileUtils.getDefaultDownLoadFileName(url); 85 | } 86 | return new DownLoadTransformer(savePath, fileName); 87 | } 88 | 89 | 90 | /** 91 | * 上传 92 | */ 93 | public static Observable uploadFile(String url, List params) { 94 | // 进度Observable 95 | UploadOnSubscribe uploadOnSubscribe = new UploadOnSubscribe(); 96 | Observable progressObservable = Observable.create(uploadOnSubscribe); 97 | 98 | // 组装请求 99 | List parts = new ArrayList<>(params.size()); 100 | for (UploadParam param : params) { 101 | switch (param.getType()) { 102 | // 文本 103 | case UploadParam.TYPE_STRING: 104 | parts.add(MultipartBody.Part.createFormData(param.getName(), param.getValue())); 105 | break; 106 | // 文件 107 | case UploadParam.TYPE_FILE: 108 | if (param.getFile() == null || !param.getFile().exists()) { 109 | break; 110 | } 111 | UploadRequestBody uploadRequestBody = new UploadRequestBody(param.getFile()); 112 | // 设置总长度 113 | uploadOnSubscribe.addSumLength(param.getFile().length()); 114 | uploadRequestBody.setUploadOnSubscribe(uploadOnSubscribe); 115 | parts.add(MultipartBody.Part.createFormData(param.getName(), param.getFileName(), uploadRequestBody)); 116 | break; 117 | default: 118 | break; 119 | } 120 | } 121 | 122 | // 发起请求 123 | Observable uploadObservable = RetrofitManager 124 | .createService(UploadService.class) 125 | .upload(url, parts); 126 | 127 | return Observable.merge(progressObservable, uploadObservable); 128 | } 129 | 130 | public static Observable uploadFile(String url, UploadParam... params) { 131 | return RetrofitManager.uploadFile(url, Arrays.asList(params)); 132 | } 133 | 134 | } -------------------------------------------------------------------------------- /EasyRxRetrofit/src/main/java/com/jimi_wu/easyrxretrofit/agent/AgentInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.jimi_wu.easyrxretrofit.agent; 2 | 3 | import java.io.IOException; 4 | 5 | import okhttp3.Interceptor; 6 | import okhttp3.Request; 7 | import okhttp3.Response; 8 | 9 | /** 10 | * Created by wuzhiming on 2016/11/14. 11 | */ 12 | 13 | public class AgentInterceptor implements Interceptor { 14 | private static final String USER_AGENT_HEADER_NAME = "User-Agent"; 15 | protected String agent; 16 | 17 | public AgentInterceptor(String agent) { 18 | this.agent = agent; 19 | } 20 | 21 | @Override 22 | public Response intercept(Chain chain) throws IOException { 23 | final Request oldRequest = chain.request(); 24 | final Request newRequest = oldRequest.newBuilder() 25 | .removeHeader(USER_AGENT_HEADER_NAME) 26 | .addHeader(USER_AGENT_HEADER_NAME,agent) 27 | .build(); 28 | return chain.proceed(newRequest); 29 | } 30 | 31 | 32 | } 33 | -------------------------------------------------------------------------------- /EasyRxRetrofit/src/main/java/com/jimi_wu/easyrxretrofit/build/DefaultRetrofitBuilder.java: -------------------------------------------------------------------------------- 1 | package com.jimi_wu.easyrxretrofit.build; 2 | 3 | import java.util.concurrent.TimeUnit; 4 | 5 | import okhttp3.OkHttpClient; 6 | import retrofit2.Retrofit; 7 | import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory; 8 | import retrofit2.converter.gson.GsonConverterFactory; 9 | 10 | /** 11 | * created by wuzhiming on 2019/2/21 12 | */ 13 | public class DefaultRetrofitBuilder implements RetrofitBuilder { 14 | 15 | @Override 16 | public Retrofit initRetrofit() { 17 | OkHttpClient okHttpClient = new OkHttpClient.Builder() 18 | .connectTimeout(60, TimeUnit.SECONDS) 19 | .readTimeout(60, TimeUnit.SECONDS) 20 | .retryOnConnectionFailure(true) 21 | .build(); 22 | 23 | return new Retrofit.Builder() 24 | .baseUrl("http://8.8.8.8") 25 | .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) 26 | .addConverterFactory(GsonConverterFactory.create()) 27 | .client(okHttpClient) 28 | .build(); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /EasyRxRetrofit/src/main/java/com/jimi_wu/easyrxretrofit/build/RetrofitBuilder.java: -------------------------------------------------------------------------------- 1 | package com.jimi_wu.easyrxretrofit.build; 2 | 3 | import retrofit2.Retrofit; 4 | 5 | /** 6 | * created by wuzhiming on 2019/2/21 7 | */ 8 | public interface RetrofitBuilder { 9 | 10 | Retrofit initRetrofit(); 11 | 12 | } 13 | -------------------------------------------------------------------------------- /EasyRxRetrofit/src/main/java/com/jimi_wu/easyrxretrofit/cookie/CookieManager.java: -------------------------------------------------------------------------------- 1 | package com.jimi_wu.easyrxretrofit.cookie; 2 | 3 | import android.content.Context; 4 | 5 | import java.util.List; 6 | 7 | import okhttp3.Cookie; 8 | import okhttp3.CookieJar; 9 | import okhttp3.HttpUrl; 10 | 11 | /** 12 | * Created by Administrator on 2016/9/6. 13 | */ 14 | public class CookieManager implements CookieJar { 15 | 16 | private CookieStore cookieStore; 17 | 18 | public CookieManager(Context context) { 19 | cookieStore = new CookieStore(context); 20 | } 21 | 22 | @Override 23 | public void saveFromResponse(HttpUrl url, List cookies) { 24 | if (cookies != null && cookies.size() > 0) { 25 | for (Cookie item : cookies) { 26 | cookieStore.add(url, item); 27 | } 28 | } 29 | } 30 | 31 | 32 | @Override 33 | public List loadForRequest(HttpUrl url) { 34 | List cookies =cookieStore.get(url); 35 | return cookies; 36 | } 37 | 38 | 39 | } 40 | -------------------------------------------------------------------------------- /EasyRxRetrofit/src/main/java/com/jimi_wu/easyrxretrofit/cookie/CookieStore.java: -------------------------------------------------------------------------------- 1 | package com.jimi_wu.easyrxretrofit.cookie; 2 | 3 | import android.content.Context; 4 | import android.content.SharedPreferences; 5 | import android.text.TextUtils; 6 | 7 | import java.io.ByteArrayInputStream; 8 | import java.io.ByteArrayOutputStream; 9 | import java.io.IOException; 10 | import java.io.ObjectInputStream; 11 | import java.io.ObjectOutputStream; 12 | import java.util.ArrayList; 13 | import java.util.HashMap; 14 | import java.util.List; 15 | import java.util.Locale; 16 | import java.util.Map; 17 | import java.util.concurrent.ConcurrentHashMap; 18 | 19 | import okhttp3.Cookie; 20 | import okhttp3.HttpUrl; 21 | 22 | /** 23 | * Created by Administrator on 2016/9/6. 24 | */ 25 | public class CookieStore { 26 | 27 | private static final String COOKIE_PREFERENCES = "WzmCookies"; 28 | 29 | private final Map> cookies; 30 | private final SharedPreferences cookiePrefs; 31 | 32 | public CookieStore(Context context) { 33 | cookies = new HashMap<>(); 34 | cookiePrefs = context.getSharedPreferences(COOKIE_PREFERENCES, Context.MODE_PRIVATE); 35 | 36 | //将持久化的cookies缓存到内存中 即map cookies 37 | Map prefsMap = cookiePrefs.getAll(); 38 | for (Map.Entry entry : prefsMap.entrySet()) { 39 | String[] cookieNames = TextUtils.split((String) entry.getValue(), ","); 40 | for (String name : cookieNames) { 41 | String encodedCookie = cookiePrefs.getString(name, null); 42 | if (encodedCookie != null) { 43 | Cookie decodedCookie = decodeCookie(encodedCookie); 44 | if (decodedCookie != null) { 45 | if (!cookies.containsKey(entry.getKey())) { 46 | cookies.put(entry.getKey(), new ConcurrentHashMap()); 47 | } 48 | cookies.get(entry.getKey()).put(name, decodedCookie); 49 | } 50 | } 51 | } 52 | } 53 | 54 | } 55 | 56 | protected String getCookieToken(Cookie cookie) { 57 | return cookie.name() + "@" + cookie.domain(); 58 | } 59 | 60 | public void add(HttpUrl url, Cookie cookie) { 61 | String name = getCookieToken(cookie); 62 | 63 | //将cookies缓存到内存中 如果缓存过期 就重置此cookie 64 | if (cookie.expiresAt() > System.currentTimeMillis()) { 65 | if (!cookies.containsKey(url.host())) { 66 | cookies.put(url.host(), new ConcurrentHashMap()); 67 | } 68 | cookies.get(url.host()).put(name, cookie); 69 | } else { 70 | if (cookies.containsKey(url.host())) { 71 | cookies.get(url.host()).remove(name); 72 | } 73 | } 74 | 75 | //讲cookies持久化到本地 76 | SharedPreferences.Editor prefsWriter = cookiePrefs.edit(); 77 | if (cookies.get(url.host()) == null) 78 | cookies.put(url.host(),new ConcurrentHashMap()); 79 | prefsWriter.putString(url.host(), TextUtils.join(",", cookies.get(url.host()).keySet())); 80 | prefsWriter.putString(name, encodeCookie(new OkHttpCookies(cookie))); 81 | prefsWriter.apply(); 82 | } 83 | 84 | public List get(HttpUrl url) { 85 | ArrayList ret = new ArrayList<>(); 86 | if (cookies.containsKey(url.host())) 87 | ret.addAll(cookies.get(url.host()).values()); 88 | return ret; 89 | } 90 | 91 | public boolean removeAll() { 92 | SharedPreferences.Editor prefsWriter = cookiePrefs.edit(); 93 | prefsWriter.clear(); 94 | prefsWriter.apply(); 95 | cookies.clear(); 96 | return true; 97 | } 98 | 99 | public boolean remove(HttpUrl url, Cookie cookie) { 100 | String name = getCookieToken(cookie); 101 | 102 | if (cookies.containsKey(url.host()) && cookies.get(url.host()).containsKey(name)) { 103 | cookies.get(url.host()).remove(name); 104 | 105 | SharedPreferences.Editor prefsWriter = cookiePrefs.edit(); 106 | if (cookiePrefs.contains(name)) { 107 | prefsWriter.remove(name); 108 | } 109 | prefsWriter.putString(url.host(), TextUtils.join(",", cookies.get(url.host()).keySet())); 110 | prefsWriter.apply(); 111 | 112 | return true; 113 | } else { 114 | return false; 115 | } 116 | } 117 | 118 | public List getCookies() { 119 | ArrayList ret = new ArrayList<>(); 120 | for (String key : cookies.keySet()) 121 | ret.addAll(cookies.get(key).values()); 122 | 123 | return ret; 124 | } 125 | 126 | /** 127 | * cookies 序列化成 string 128 | * 129 | * @param cookie 要序列化的cookie 130 | * @return 序列化之后的string 131 | */ 132 | protected String encodeCookie(OkHttpCookies cookie) { 133 | if (cookie == null) 134 | return null; 135 | ByteArrayOutputStream os = new ByteArrayOutputStream(); 136 | try { 137 | ObjectOutputStream outputStream = new ObjectOutputStream(os); 138 | outputStream.writeObject(cookie); 139 | } catch (IOException e) { 140 | e.printStackTrace(); 141 | return null; 142 | } 143 | 144 | return byteArrayToHexString(os.toByteArray()); 145 | } 146 | 147 | /** 148 | * 将字符串反序列化成cookies 149 | * 150 | * @param cookieString cookies string 151 | * @return cookie object 152 | */ 153 | protected Cookie decodeCookie(String cookieString) { 154 | byte[] bytes = hexStringToByteArray(cookieString); 155 | ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes); 156 | Cookie cookie = null; 157 | try { 158 | ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream); 159 | cookie = ((OkHttpCookies) objectInputStream.readObject()).getCookies(); 160 | } catch (IOException e) { 161 | e.printStackTrace(); 162 | } catch (ClassNotFoundException e) { 163 | e.printStackTrace(); 164 | } 165 | 166 | return cookie; 167 | } 168 | 169 | /** 170 | * 二进制数组转十六进制字符串 171 | * 172 | * @param bytes byte array to be converted 173 | * @return string containing hex values 174 | */ 175 | protected String byteArrayToHexString(byte[] bytes) { 176 | StringBuilder sb = new StringBuilder(bytes.length * 2); 177 | for (byte element : bytes) { 178 | int v = element & 0xff; 179 | if (v < 16) { 180 | sb.append('0'); 181 | } 182 | sb.append(Integer.toHexString(v)); 183 | } 184 | return sb.toString().toUpperCase(Locale.US); 185 | } 186 | 187 | /** 188 | * 十六进制字符串转二进制数组 189 | * 190 | * @param hexString string of hex-encoded values 191 | * @return decoded byte array 192 | */ 193 | protected byte[] hexStringToByteArray(String hexString) { 194 | int len = hexString.length(); 195 | byte[] data = new byte[len / 2]; 196 | for (int i = 0; i < len; i += 2) { 197 | data[i / 2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4) + Character.digit(hexString.charAt(i + 1), 16)); 198 | } 199 | return data; 200 | } 201 | 202 | 203 | } 204 | -------------------------------------------------------------------------------- /EasyRxRetrofit/src/main/java/com/jimi_wu/easyrxretrofit/cookie/OkHttpCookies.java: -------------------------------------------------------------------------------- 1 | package com.jimi_wu.easyrxretrofit.cookie; 2 | 3 | import java.io.IOException; 4 | import java.io.ObjectInputStream; 5 | import java.io.ObjectOutputStream; 6 | import java.io.Serializable; 7 | 8 | import okhttp3.Cookie; 9 | 10 | /** 11 | * Created by Administrator on 2016/9/6. 12 | */ 13 | public class OkHttpCookies implements Serializable { 14 | 15 | private transient final Cookie cookies; 16 | private transient Cookie clientCookies; 17 | 18 | public OkHttpCookies(Cookie cookies) { 19 | this.cookies = cookies; 20 | } 21 | 22 | public Cookie getCookies() { 23 | Cookie bestCookies = cookies; 24 | if (clientCookies != null) { 25 | bestCookies = clientCookies; 26 | } 27 | return bestCookies; 28 | } 29 | 30 | private void writeObject(ObjectOutputStream out) throws IOException { 31 | out.writeObject(cookies.name()); 32 | out.writeObject(cookies.value()); 33 | out.writeLong(cookies.expiresAt()); 34 | out.writeObject(cookies.domain()); 35 | out.writeObject(cookies.path()); 36 | out.writeBoolean(cookies.secure()); 37 | out.writeBoolean(cookies.httpOnly()); 38 | out.writeBoolean(cookies.hostOnly()); 39 | out.writeBoolean(cookies.persistent()); 40 | } 41 | 42 | private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { 43 | String name = (String) in.readObject(); 44 | String value = (String) in.readObject(); 45 | long expiresAt = in.readLong(); 46 | String domain = (String) in.readObject(); 47 | String path = (String) in.readObject(); 48 | boolean secure = in.readBoolean(); 49 | boolean httpOnly = in.readBoolean(); 50 | boolean hostOnly = in.readBoolean(); 51 | boolean persistent = in.readBoolean(); 52 | Cookie.Builder builder = new Cookie.Builder(); 53 | builder = builder.name(name); 54 | builder = builder.value(value); 55 | builder = builder.expiresAt(expiresAt); 56 | builder = hostOnly ? builder.hostOnlyDomain(domain) : builder.domain(domain); 57 | builder = builder.path(path); 58 | builder = secure ? builder.secure() : builder; 59 | builder = httpOnly ? builder.httpOnly() : builder; 60 | clientCookies =builder.build(); 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /EasyRxRetrofit/src/main/java/com/jimi_wu/easyrxretrofit/download/DownLoadOnSubscribe.java: -------------------------------------------------------------------------------- 1 | package com.jimi_wu.easyrxretrofit.download; 2 | 3 | import android.util.Pair; 4 | 5 | import java.io.File; 6 | import java.io.IOException; 7 | 8 | import io.reactivex.ObservableEmitter; 9 | import io.reactivex.ObservableOnSubscribe; 10 | import io.reactivex.annotations.NonNull; 11 | import okhttp3.ResponseBody; 12 | import okio.Buffer; 13 | import okio.BufferedSink; 14 | import okio.ForwardingSource; 15 | import okio.Okio; 16 | import okio.Source; 17 | 18 | /** 19 | * Created by wzm on 2017/6/15. 20 | */ 21 | 22 | public class DownLoadOnSubscribe implements ObservableOnSubscribe { 23 | 24 | private ObservableEmitter mObservableEmitter; 25 | 26 | // 默认保存地址 27 | private String mPath; 28 | // 文件名 29 | private String mFileName; 30 | // 临时文件名 31 | private String mFileNameTmp; 32 | 33 | // 已下载 34 | private long mDownLoaded = 0l; 35 | // 总长度 36 | private long mSumLength = 0l; 37 | 38 | private Source mSource; 39 | private Source mProgressSource; 40 | private BufferedSink mSink; 41 | 42 | public DownLoadOnSubscribe(ResponseBody responseBody, String path, String fileName) throws IOException { 43 | this.mPath = path; 44 | this.mFileName = fileName; 45 | this.mFileNameTmp = fileName + ".tmp"; 46 | createFile(); 47 | init(responseBody); 48 | } 49 | 50 | @Override 51 | public void subscribe(@NonNull ObservableEmitter e) { 52 | this.mObservableEmitter = e; 53 | try { 54 | mSink.writeAll(Okio.buffer(mProgressSource)); 55 | mSink.close(); 56 | File file = new File(mPath +File.separator + mFileNameTmp); 57 | File destFile = new File(mPath +File.separator + mFileName); 58 | if (destFile.exists()) { 59 | destFile.delete(); 60 | } 61 | file.renameTo(new File(mPath +File.separator + mFileName)); 62 | mObservableEmitter.onNext(mPath+File.separator+mFileName); 63 | mObservableEmitter.onComplete(); 64 | } catch (Exception exception) { 65 | mObservableEmitter.onError(exception); 66 | } 67 | } 68 | 69 | 70 | private void init(ResponseBody responseBody) throws IOException { 71 | mSumLength = responseBody.contentLength(); 72 | 73 | mSource = responseBody.source(); 74 | 75 | mProgressSource = getProgressSource(mSource); 76 | 77 | mSink = Okio.buffer(Okio.sink(new File(mPath +File.separator + mFileNameTmp))); 78 | 79 | } 80 | 81 | public void onRead(long read) { 82 | mDownLoaded += read == -1 ? 0 : read; 83 | if (mObservableEmitter == null) return; 84 | if (mDownLoaded >= mSumLength) { 85 | mDownLoaded = mSumLength; 86 | } 87 | mObservableEmitter.onNext(Pair.create(mDownLoaded, mSumLength)); 88 | } 89 | 90 | private ForwardingSource getProgressSource(Source source) { 91 | return new ForwardingSource(source) { 92 | @Override 93 | public long read(Buffer sink, long byteCount) throws IOException { 94 | long read = super.read(sink, byteCount); 95 | onRead(read); 96 | return read; 97 | } 98 | }; 99 | } 100 | 101 | private void createFile() throws IOException { 102 | File path = new File(mPath); 103 | if (!path.exists()) { 104 | path.mkdirs(); 105 | } 106 | File file = new File(mPath + File.separator + mFileNameTmp); 107 | if (!file.exists()) { 108 | file.createNewFile(); 109 | } 110 | } 111 | 112 | } 113 | -------------------------------------------------------------------------------- /EasyRxRetrofit/src/main/java/com/jimi_wu/easyrxretrofit/download/DownLoadService.java: -------------------------------------------------------------------------------- 1 | package com.jimi_wu.easyrxretrofit.download; 2 | 3 | import io.reactivex.Observable; 4 | import okhttp3.ResponseBody; 5 | import retrofit2.http.GET; 6 | import retrofit2.http.Streaming; 7 | import retrofit2.http.Url; 8 | 9 | /** 10 | * Created by wzm on 2017/6/15. 11 | */ 12 | 13 | public interface DownLoadService { 14 | 15 | @Streaming 16 | @GET 17 | Observable startDownLoad(@Url String fileUrl); 18 | 19 | } 20 | -------------------------------------------------------------------------------- /EasyRxRetrofit/src/main/java/com/jimi_wu/easyrxretrofit/download/DownLoadTransformer.java: -------------------------------------------------------------------------------- 1 | package com.jimi_wu.easyrxretrofit.download; 2 | 3 | import io.reactivex.Observable; 4 | import io.reactivex.ObservableSource; 5 | import io.reactivex.ObservableTransformer; 6 | import io.reactivex.functions.Function; 7 | import okhttp3.ResponseBody; 8 | 9 | /** 10 | * Created by wzm on 2017/6/16. 11 | */ 12 | 13 | public class DownLoadTransformer implements ObservableTransformer { 14 | 15 | // 默认保存地址 16 | private String mPath; 17 | // 文件名 18 | private String mFileName; 19 | 20 | public DownLoadTransformer(String mPath, String mFileName) { 21 | this.mPath = mPath; 22 | this.mFileName = mFileName; 23 | } 24 | 25 | @Override 26 | public ObservableSource apply(Observable upstream) { 27 | return upstream.flatMap(new Function>() { 28 | @Override 29 | public ObservableSource apply(ResponseBody responseBody) throws Exception { 30 | return Observable.create(new DownLoadOnSubscribe(responseBody, mPath, mFileName)); 31 | } 32 | }); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /EasyRxRetrofit/src/main/java/com/jimi_wu/easyrxretrofit/exception/ServerException.java: -------------------------------------------------------------------------------- 1 | package com.jimi_wu.easyrxretrofit.exception; 2 | 3 | /** 4 | * Created by Administrator on 2016/9/5. 5 | */ 6 | public class ServerException extends Exception { 7 | 8 | public ServerException() { 9 | } 10 | 11 | public ServerException(String message) { 12 | super(message); 13 | } 14 | 15 | public ServerException(String message, Throwable cause) { 16 | super(message, cause); 17 | } 18 | 19 | public ServerException(Throwable cause) { 20 | super(cause); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /EasyRxRetrofit/src/main/java/com/jimi_wu/easyrxretrofit/observer/BaseObserver.java: -------------------------------------------------------------------------------- 1 | package com.jimi_wu.easyrxretrofit.observer; 2 | 3 | import io.reactivex.Observer; 4 | import io.reactivex.disposables.Disposable; 5 | 6 | /** 7 | * created by wuzhiming on 2019/2/21 8 | */ 9 | public abstract class BaseObserver implements Observer { 10 | 11 | @Override 12 | public void onSubscribe(Disposable d) { 13 | } 14 | 15 | @Override 16 | public void onNext(T t) { 17 | _onNext(t); 18 | } 19 | 20 | @Override 21 | public void onError(Throwable e) { 22 | _onError(e); 23 | } 24 | 25 | @Override 26 | public void onComplete() { 27 | } 28 | 29 | protected abstract void _onNext(T t); 30 | protected abstract void _onError(Throwable e); 31 | 32 | } 33 | -------------------------------------------------------------------------------- /EasyRxRetrofit/src/main/java/com/jimi_wu/easyrxretrofit/observer/DownLoadObserver.java: -------------------------------------------------------------------------------- 1 | package com.jimi_wu.easyrxretrofit.observer; 2 | 3 | 4 | import android.util.Pair; 5 | 6 | import io.reactivex.Observer; 7 | import io.reactivex.disposables.Disposable; 8 | 9 | /** 10 | * created by wuzhiming on 2019/2/21 11 | */ 12 | public abstract class DownLoadObserver implements Observer { 13 | 14 | private int mPercent = 0; 15 | 16 | @Override 17 | public void onSubscribe(Disposable d) { 18 | } 19 | 20 | @Override 21 | public void onNext(Object o) { 22 | if (o instanceof Pair) { 23 | long uploaded = (long)(((Pair) o).first); 24 | long sumLength = (long)(((Pair) o).second); 25 | _onProgress(uploaded, sumLength); 26 | int percent = (int) (uploaded*100f / sumLength); 27 | if (percent < 0) { 28 | percent = 0; 29 | } 30 | if (percent > 100) { 31 | percent = 100; 32 | } 33 | if (percent == mPercent) { 34 | return; 35 | } 36 | mPercent = percent; 37 | _onProgress(mPercent); 38 | } 39 | if(o instanceof String) { 40 | _onNext((String) o); 41 | } 42 | } 43 | 44 | @Override 45 | public void onError(Throwable e) { 46 | _onError(e); 47 | } 48 | 49 | @Override 50 | public void onComplete() { 51 | } 52 | 53 | public abstract void _onNext(String result); 54 | public void _onProgress(Integer percent) {} 55 | public abstract void _onError(Throwable e); 56 | public void _onProgress(long uploaded, long sumLength) {} 57 | 58 | } 59 | -------------------------------------------------------------------------------- /EasyRxRetrofit/src/main/java/com/jimi_wu/easyrxretrofit/observer/UploadObserver.java: -------------------------------------------------------------------------------- 1 | package com.jimi_wu.easyrxretrofit.observer; 2 | 3 | import android.util.Pair; 4 | 5 | import com.google.gson.Gson; 6 | import com.google.gson.JsonElement; 7 | import com.google.gson.JsonObject; 8 | 9 | import java.lang.reflect.ParameterizedType; 10 | import java.lang.reflect.Type; 11 | 12 | import io.reactivex.Observer; 13 | import io.reactivex.disposables.Disposable; 14 | 15 | /** 16 | * created by wuzhiming on 2019/2/21 17 | */ 18 | public abstract class UploadObserver implements Observer { 19 | 20 | private int mPercent = 0; 21 | private Type mType; 22 | 23 | public UploadObserver() { 24 | mType = ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]; 25 | } 26 | 27 | @Override 28 | public void onSubscribe(Disposable d) { 29 | } 30 | 31 | @Override 32 | public void onNext(Object o) { 33 | if (o instanceof Pair) { 34 | long uploaded = (long)(((Pair) o).first); 35 | long sumLength = (long)(((Pair) o).second); 36 | _onProgress(uploaded, sumLength); 37 | int percent = (int) (uploaded*100f / sumLength); 38 | if (percent < 0) { 39 | percent = 0; 40 | } 41 | if (percent > 100) { 42 | percent = 100; 43 | } 44 | if (percent == mPercent) { 45 | return; 46 | } 47 | mPercent = percent; 48 | _onProgress(mPercent); 49 | return; 50 | } 51 | if (o instanceof JsonObject) { 52 | Gson gson = new Gson(); 53 | try { 54 | T result = gson.fromJson((JsonElement) o, mType); 55 | _onNext(result); 56 | } catch (Exception e) { 57 | e.printStackTrace(); 58 | _onError(e); 59 | } 60 | } 61 | } 62 | 63 | @Override 64 | public void onError(Throwable e) { 65 | _onError(e); 66 | } 67 | 68 | @Override 69 | public void onComplete() { 70 | } 71 | 72 | public abstract void _onNext(T t); 73 | 74 | public void _onProgress(Integer percent) {} 75 | 76 | public void _onProgress(long uploaded, long sumLength) {} 77 | 78 | public abstract void _onError(Throwable e); 79 | 80 | } 81 | -------------------------------------------------------------------------------- /EasyRxRetrofit/src/main/java/com/jimi_wu/easyrxretrofit/transformer/BaseModel.java: -------------------------------------------------------------------------------- 1 | package com.jimi_wu.easyrxretrofit.transformer; 2 | 3 | /** 4 | * created by wuzhiming on 2019/2/21 5 | */ 6 | public interface BaseModel { 7 | 8 | boolean isError(); 9 | 10 | String getMsg(); 11 | 12 | T getResult(); 13 | 14 | } 15 | -------------------------------------------------------------------------------- /EasyRxRetrofit/src/main/java/com/jimi_wu/easyrxretrofit/transformer/BaseModelTransformer.java: -------------------------------------------------------------------------------- 1 | package com.jimi_wu.easyrxretrofit.transformer; 2 | 3 | 4 | import com.jimi_wu.easyrxretrofit.exception.ServerException; 5 | 6 | import io.reactivex.Observable; 7 | import io.reactivex.ObservableEmitter; 8 | import io.reactivex.ObservableOnSubscribe; 9 | import io.reactivex.ObservableSource; 10 | import io.reactivex.ObservableTransformer; 11 | import io.reactivex.functions.Function; 12 | 13 | /** 14 | * created by wuzhiming on 2019/2/21 15 | * 16 | * 转换器 17 | * from BaseModel 18 | * to T 19 | */ 20 | public class BaseModelTransformer implements ObservableTransformer, T> { 21 | 22 | 23 | @Override 24 | public ObservableSource apply(Observable> upstream) { 25 | return upstream.flatMap(new Function, ObservableSource>() { 26 | @Override 27 | public ObservableSource apply(BaseModel tBaseModel) throws Exception { 28 | if (!tBaseModel.isError()) { 29 | return createData(tBaseModel.getResult()); 30 | } 31 | return Observable.error(new ServerException(tBaseModel.getMsg())); 32 | } 33 | }); 34 | } 35 | 36 | /** 37 | * 创建Flowable 38 | */ 39 | private static Observable createData(final T result) { 40 | return Observable.create(new ObservableOnSubscribe() { 41 | @Override 42 | public void subscribe(ObservableEmitter emitter) { 43 | try { 44 | emitter.onNext(result); 45 | emitter.onComplete(); 46 | } catch (Exception exception) { 47 | emitter.onError(exception); 48 | } 49 | } 50 | }); 51 | } 52 | 53 | 54 | 55 | } 56 | -------------------------------------------------------------------------------- /EasyRxRetrofit/src/main/java/com/jimi_wu/easyrxretrofit/upload/UploadOnSubscribe.java: -------------------------------------------------------------------------------- 1 | package com.jimi_wu.easyrxretrofit.upload; 2 | 3 | 4 | import android.util.Pair; 5 | 6 | import io.reactivex.ObservableEmitter; 7 | import io.reactivex.ObservableOnSubscribe; 8 | 9 | /** 10 | * Created by wzm on 2017/6/11. 11 | */ 12 | 13 | public class UploadOnSubscribe implements ObservableOnSubscribe { 14 | 15 | private ObservableEmitter mObservableEmitter; 16 | private long mSumLength = 0L; 17 | private long mUploaded = 0L; 18 | 19 | public UploadOnSubscribe() { 20 | } 21 | 22 | public void setSumLength(long sumLength) { 23 | this.mSumLength = sumLength; 24 | } 25 | 26 | public long getSumLength() { 27 | return mSumLength; 28 | } 29 | 30 | public void addSumLength(long length) { 31 | this.mSumLength += length; 32 | } 33 | 34 | public void onRead(long read) { 35 | mUploaded += read; 36 | if (mObservableEmitter == null) return; 37 | if (mUploaded >= mSumLength) { 38 | mUploaded = mSumLength; 39 | } 40 | mObservableEmitter.onNext(Pair.create(mUploaded, mSumLength)); 41 | } 42 | 43 | @Override 44 | public void subscribe(ObservableEmitter emitter) throws Exception { 45 | mObservableEmitter = emitter; 46 | } 47 | 48 | 49 | } 50 | -------------------------------------------------------------------------------- /EasyRxRetrofit/src/main/java/com/jimi_wu/easyrxretrofit/upload/UploadParam.java: -------------------------------------------------------------------------------- 1 | package com.jimi_wu.easyrxretrofit.upload; 2 | 3 | import java.io.File; 4 | 5 | import io.reactivex.annotations.NonNull; 6 | 7 | /** 8 | * created by wuzhiming on 2019/2/21 9 | */ 10 | public class UploadParam { 11 | 12 | public static final String TYPE_STRING = "string"; 13 | public static final String TYPE_FILE = "file"; 14 | 15 | private String type; 16 | 17 | private String name; 18 | private String value; 19 | 20 | private File file; 21 | private String fileName; 22 | 23 | public UploadParam(@NonNull String name, @NonNull String value) { 24 | this.name = name; 25 | this.value = value; 26 | this.type = TYPE_STRING; 27 | } 28 | 29 | public UploadParam(@NonNull String name, @NonNull File file) { 30 | this.name = name; 31 | this.file = file; 32 | this.fileName = file.getName(); 33 | this.type = TYPE_FILE; 34 | } 35 | 36 | public UploadParam(@NonNull String name, @NonNull File file, @NonNull String fileName) { 37 | this.name = name; 38 | this.file = file; 39 | this.fileName = fileName; 40 | this.type = TYPE_FILE; 41 | } 42 | 43 | public String getType() { 44 | return type; 45 | } 46 | 47 | public void setType(String type) { 48 | this.type = type; 49 | } 50 | 51 | public String getName() { 52 | return name; 53 | } 54 | 55 | public void setName(String name) { 56 | this.name = name; 57 | } 58 | 59 | public String getValue() { 60 | return value; 61 | } 62 | 63 | public void setValue(String value) { 64 | this.value = value; 65 | } 66 | 67 | public File getFile() { 68 | return file; 69 | } 70 | 71 | public void setFile(File file) { 72 | this.file = file; 73 | } 74 | 75 | public String getFileName() { 76 | return fileName; 77 | } 78 | 79 | public void setFileName(String fileName) { 80 | this.fileName = fileName; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /EasyRxRetrofit/src/main/java/com/jimi_wu/easyrxretrofit/upload/UploadRequestBody.java: -------------------------------------------------------------------------------- 1 | package com.jimi_wu.easyrxretrofit.upload; 2 | 3 | import java.io.File; 4 | import java.io.FileInputStream; 5 | import java.io.IOException; 6 | 7 | import okhttp3.MediaType; 8 | import okhttp3.RequestBody; 9 | import okio.BufferedSink; 10 | 11 | /** 12 | * Created by wzm on 2017/6/11. 13 | */ 14 | public class UploadRequestBody extends RequestBody { 15 | 16 | private File mFile; 17 | private static final int DEFAULT_BUFFER_SIZE = 2048; 18 | 19 | public UploadRequestBody(File mFile) { 20 | this.mFile = mFile; 21 | } 22 | 23 | private UploadOnSubscribe mUploadOnSubscribe; 24 | 25 | public void setUploadOnSubscribe(UploadOnSubscribe uploadOnSubscribe) { 26 | this.mUploadOnSubscribe = uploadOnSubscribe; 27 | } 28 | 29 | @Override 30 | public MediaType contentType() { 31 | return MediaType.parse("multipart/form-data"); 32 | } 33 | 34 | @Override 35 | public long contentLength() throws IOException { 36 | return mFile.length(); 37 | } 38 | 39 | @Override 40 | public void writeTo(BufferedSink sink) throws IOException { 41 | byte[] buffer = new byte[DEFAULT_BUFFER_SIZE]; 42 | FileInputStream in = new FileInputStream(mFile); 43 | 44 | try { 45 | int read; 46 | 47 | while ((read = in.read(buffer)) != -1) { 48 | 49 | // update progress on UI thread 50 | if(mUploadOnSubscribe != null) { 51 | mUploadOnSubscribe.onRead(read); 52 | } 53 | 54 | sink.write(buffer, 0, read); 55 | } 56 | 57 | } finally { 58 | in.close(); 59 | } 60 | 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /EasyRxRetrofit/src/main/java/com/jimi_wu/easyrxretrofit/upload/UploadService.java: -------------------------------------------------------------------------------- 1 | package com.jimi_wu.easyrxretrofit.upload; 2 | 3 | import com.google.gson.JsonObject; 4 | 5 | import java.util.List; 6 | 7 | import io.reactivex.Observable; 8 | import okhttp3.MultipartBody; 9 | import retrofit2.http.Multipart; 10 | import retrofit2.http.POST; 11 | import retrofit2.http.Part; 12 | import retrofit2.http.Url; 13 | 14 | /** 15 | * created by wuzhiming on 2019/2/21 16 | */ 17 | public interface UploadService { 18 | 19 | @Multipart 20 | @POST 21 | Observable upload(@Url String url, @Part List params); 22 | 23 | } 24 | -------------------------------------------------------------------------------- /EasyRxRetrofit/src/main/java/com/jimi_wu/easyrxretrofit/utils/FileUtils.java: -------------------------------------------------------------------------------- 1 | package com.jimi_wu.easyrxretrofit.utils; 2 | 3 | import android.os.Environment; 4 | 5 | import java.io.File; 6 | 7 | /** 8 | * Created by wzm on 2017/6/16. 9 | */ 10 | 11 | public class FileUtils { 12 | 13 | /** 14 | * 检查sd卡状态 15 | */ 16 | public static boolean checkSDStatus() { 17 | //判断sd是否可用 18 | String sdStatus = Environment.getExternalStorageState(); 19 | if (!sdStatus.equals(Environment.MEDIA_MOUNTED)) 20 | { 21 | return false; 22 | } 23 | return true; 24 | } 25 | 26 | 27 | /** 28 | * 获得下载保存默认地址 29 | */ 30 | public static String getDefaultDownLoadPath() { 31 | if (checkSDStatus()) 32 | return Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath()+ File.separator; 33 | return ""; 34 | } 35 | 36 | 37 | /** 38 | * 从url中,获得默认文件名 39 | */ 40 | public static String getDefaultDownLoadFileName(String url) { 41 | if (url == null || url.length() == 0) return ""; 42 | int nameStart = url.lastIndexOf('/')+1; 43 | return url.substring(nameStart); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /EasyRxRetrofit/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | EasyRxRetrofit 3 | 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### 依赖 2 | 3 | ``` 4 | implementation 'com.jimi_wu:EasyRxRetrofit:2.0.0' 5 | ``` 6 | 7 | ### 在你的application中注册 8 | ```java 9 | @Override 10 | public void onCreate() { 11 | super.onCreate(); 12 | // 在此处初始化Retrofit 13 | RetrofitManager.init(new YourRetrofitBuilder()); 14 | } 15 | ``` 16 | 17 | ### 创建你的返回数据基类 18 | `EasyRxRetrofit`封装了对返回数据的统一处理,你需要创建你自己的返回数据基类,并实现`BaseModel`接口的三个方法: 19 | 20 | - isError(): 返回请求是否出错; 21 | - getMsg():返回错误信息; 22 | - getResult():返回请求成功的数据。 23 | 24 | 比如,如果你的返回格式为 25 | ``` 26 | { 27 | code: 200, 28 | errMsg: "success", 29 | data: {...} 30 | } 31 | ``` 32 | 那么,你的返回数据基类应该为 33 | ```Java 34 | public class ResultBean implements BaseModel { 35 | 36 | private int code; 37 | private String errMsg; 38 | private T data; 39 | 40 | @Override 41 | public boolean isError() {return code != 200;} 42 | 43 | @Override 44 | public String getMsg() {return errMsg;} 45 | 46 | @Override 47 | public T getResult() {return data;} 48 | 49 | /** getter and setter*/ 50 | ... 51 | } 52 | ``` 53 | **提醒:基类记得使用泛型** 54 | 55 | ### 调用get/post请求 56 | 57 | 要调用`get/post`请求,你首先需要创建自己的`ApiService`,跟你使用`retrofit`时一样,只是**返回类型必须为`Observable>`,其中ResultBean是你创建的返回数据基类**: 58 | 59 | ```java 60 | public interface GetUserService { 61 | 62 | @POST("/getUser") 63 | Observable> start(); 64 | 65 | } 66 | ``` 67 | 68 | 69 | 然后,执行你的请求,**调用`.compose(RetrofitManager.handleResult())`来实现返回数据的处理,并使用BaseObserver来订阅结果**,如: 70 | ```java 71 | RetrofitManager 72 | .createService(GetUserService.class) 73 | .start() 74 | .compose(RetrofitManager.handleResult()) 75 | .subscribeOn(Schedulers.io()) 76 | .observeOn(AndroidSchedulers.mainThread()) 77 | .subscribe(new BaseObserver(this) { 78 | 79 | @Override 80 | protected void _onNext(UserBean userBean) { 81 | Log.i("retrofit", "onNext=========>" + userBean.getName()); 82 | tv.setText("请求成功:" + userBean.getName()); 83 | } 84 | 85 | @Override 86 | protected void _onError(Throwable e) { 87 | Log.i("retrofit", "onError=========>" + e.getMessage()); 88 | tv.setText("请求失败:" + e.getMessage()); 89 | } 90 | }); 91 | ``` 92 | 93 | ### 上传单个/多个文件,监听上传进度 94 | 95 | 上传文件不需自己创建`ApiService`,只需新建`UploadParam`对象,然后调用`RetrofitManager.uploadFile`方法,传入接口地址和`UploadParam`对象即可。 96 | 97 | `uploadFile`方法有两个定义: 98 | 99 | ```java 100 | uploadFile(String url, UploadParam... params); 101 | uploadFile(String url, List params); 102 | ``` 103 | 104 | 因此,上传单个文件与上传多个文件的方法是相同的: 105 | 106 | ```java 107 | // 上传单个文件 108 | RetrofitManager.uploadFile(Constants.UPLOAD_URL, new UploadParam("upload", file)) 109 | // 上传多个文件 110 | RetrofitManager.uploadFile(Constants.UPLOAD_URL, 111 | new UploadParam("upload", file1), 112 | new UploadParam("upload", file2)); 113 | // 使用List上传多个文件 114 | ArrayList uploadParams = new ArrayList<>(files.size()); 115 | for (File file : files) { 116 | uploadParams.add(new UploadParam("upload", file)); 117 | } 118 | RetrofitManager.uploadFile(Constants.UPLOADS_URL, uploadParams); 119 | ``` 120 | 121 | 需要注意的是,上传文件需要使用`UploadObserver`来订阅: 122 | 123 | ```java 124 | ArrayList uploadParams = new ArrayList<>(files.size()); 125 | for (File file : files) { 126 | uploadParams.add(new UploadParam("upload", file)); 127 | } 128 | RetrofitManager 129 | .uploadFile(Constants.UPLOADS_URL, uploadParams) 130 | .subscribeOn(Schedulers.io()) 131 | .observeOn(AndroidSchedulers.mainThread()) 132 | .subscribe(new UploadObserver>>() { 133 | 134 | @Override 135 | public void _onNext(ResultBean> arrayListResultBean) { 136 | ArrayList fileBeans = arrayListResultBean.getData(); 137 | StringBuilder stringBuilder = new StringBuilder(); 138 | for (FileBean fileBean : fileBeans) { 139 | stringBuilder.append("上传成功:" + fileBean.getUrl() + "\n"); 140 | } 141 | Log.d("retrofit", "onNext=======>" + stringBuilder); 142 | tv.setText("上传成功:" + stringBuilder); 143 | } 144 | 145 | @Override 146 | public void _onProgress(Integer percent) { 147 | Log.i("retrofit", "onProgress=======>" + percent); 148 | tv.setText("上传中:" + percent); 149 | } 150 | 151 | @Override 152 | public void _onProgress(long uploaded, long sumLength) { 153 | tvActualProgress.setText("下载中:" + uploaded + "/" + sumLength); 154 | } 155 | 156 | @Override 157 | public void _onError(Throwable e) { 158 | Log.d("retrofit", "onError======>" + e.getMessage()); 159 | tv.setText("上传失败:" + e.getMessage()); 160 | } 161 | }); 162 | ``` 163 | 164 | 其中`_onProgress(Integer percent)`方法回调百分比进度,`_onProgress(long uploaded, long sumLength)`方法回调文件长度进度,这两个方法并非抽象方法,因此可按需选择监听或不监听。 165 | 166 | 结果如下: 167 | 168 | ``` 169 | 06-20 10:52:49.095 32377-32377/com.jimi_wu.sample I/retrofit: onProgress=======>95 170 | 06-20 10:52:49.095 32377-32377/com.jimi_wu.sample I/retrofit: onProgress=======>96 171 | 06-20 10:52:49.116 32377-32377/com.jimi_wu.sample I/retrofit: onProgress=======>97 172 | 06-20 10:52:49.117 32377-32377/com.jimi_wu.sample I/retrofit: onProgress=======>98 173 | 06-20 10:52:49.118 32377-32377/com.jimi_wu.sample I/retrofit: onProgress=======>99 174 | 06-20 10:52:49.118 32377-32377/com.jimi_wu.sample I/retrofit: onProgress=======>100 175 | 06-20 10:52:49.160 32377-32377/com.jimi_wu.sample I/retrofit: onNext=======>上传成功:http://192.168.5.127:3000/uploads/wx_camera_1497846596539.jpg 176 | 上传成功:http://192.168.5.127:3000/uploads/wx_camera_1497774775994.jpg 177 | 上传成功:http://192.168.5.127:3000/uploads/wx_camera_1497774700027.jpg 178 | ``` 179 | 180 | 181 | ### 文件下载,监听下载进度 182 | 183 | 与上传文件类似,下载文件只需调用`RetrofitManager.download("")`方法,并使用`DownLoadObserver`订阅即可: 184 | 185 | ```java 186 | RetrofitManager 187 | .download("/uploads/test.pdf") 188 | .subscribeOn(Schedulers.io()) 189 | .observeOn(AndroidSchedulers.mainThread()) 190 | .subscribe(new DownLoadObserver() { 191 | @Override 192 | public void _onNext(String result) { 193 | Log.i("retrofit", "onNext=======>" + result); 194 | tv.setText("下载成功:" + result); 195 | } 196 | 197 | @Override 198 | public void _onProgress(Integer percent) { 199 | Log.i("retrofit", "onProgress=======>" + percent); 200 | tv.setText("下载中:" + percent); 201 | } 202 | 203 | @Override 204 | public void _onProgress(long uploaded, long sumLength) { 205 | tvActualProgress.setText("下载中:" + uploaded + "/" + sumLength); 206 | } 207 | 208 | @Override 209 | public void _onError(Throwable e) { 210 | Log.i("retrofit", "onProgress=======>" + e.getMessage()); 211 | tv.setText("下载失败:" + e.getMessage()); 212 | } 213 | }); 214 | ``` 215 | 216 | 当然,你也可以使用 `download(String url, String savePath, String fileName)` 来设置下载的保存路径和文件名。 217 | 218 | `EasyRxRetrofit `内部在下载文件时,会使用.tmp后缀作为临时文件名,待下载完成后再重命名为真正的名字。与上传一样,`DownLoadObserver`内部也含有两个`_onProgress`回调,可按需监听或不监听。 219 | 220 | 结果如下: 221 | ``` 222 | 06-20 10:54:01.590 32377-32377/com.jimi_wu.sample I/retrofit: onProgress=======>95 223 | 06-20 10:54:01.686 32377-32377/com.jimi_wu.sample I/retrofit: onProgress=======>96 224 | 06-20 10:54:01.793 32377-32377/com.jimi_wu.sample I/retrofit: onProgress=======>97 225 | 06-20 10:54:01.884 32377-32377/com.jimi_wu.sample I/retrofit: onProgress=======>98 226 | 06-20 10:54:01.985 32377-32377/com.jimi_wu.sample I/retrofit: onProgress=======>99 227 | 06-20 10:54:02.086 32377-32377/com.jimi_wu.sample I/retrofit: onProgress=======>100 228 | 06-20 10:54:02.100 32377-32377/com.jimi_wu.sample I/retrofit: onNext=======>/storage/emulated/0/Download/VID_20170616_122618.mp4 229 | ``` 230 | 231 | ### 说明 232 | 233 | - 可通过实现`RetrofitBuilder`接口返回`Retrofit`实例,管理各项配置。 234 | - `EasyRxRetrofit`内部不会进行**线程切换**,需手动按需切换。 235 | - `EasyRxRetrofit`内部未包含**生命周期类的管理**,需手动管理。 236 | 237 | --- 238 | 239 | 博客地址:[http://blog.csdn.net/anyfive/article/details/73469365](http://blog.csdn.net/anyfive/article/details/73469365) -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 25 5 | buildToolsVersion "25.0.0" 6 | defaultConfig { 7 | applicationId "com.jimi_wu.sample" 8 | minSdkVersion 15 9 | targetSdkVersion 25 10 | versionCode 1 11 | versionName "1.0" 12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 13 | } 14 | buildTypes { 15 | debug { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | release { 20 | minifyEnabled true 21 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 22 | } 23 | } 24 | 25 | lintOptions { 26 | abortOnError false 27 | } 28 | 29 | 30 | } 31 | 32 | dependencies { 33 | implementation fileTree(include: ['*.jar'], dir: 'libs') 34 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 35 | exclude group: 'com.android.support', module: 'support-annotations' 36 | }) 37 | implementation 'com.android.support:appcompat-v7:25.4.0' 38 | testImplementation 'junit:junit:4.12' 39 | // rxjava 40 | implementation "io.reactivex.rxjava2:rxandroid:2.1.0" 41 | implementation 'io.reactivex.rxjava2:rxjava:2.2.2' 42 | // retrofit 43 | implementation 'com.squareup.retrofit2:retrofit:2.4.0' 44 | implementation 'com.squareup.retrofit2:adapter-rxjava2:2.4.0' 45 | //gson 46 | implementation 'com.squareup.retrofit2:converter-gson:2.4.0' 47 | implementation project(':EasyRxRetrofit') 48 | } 49 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/wuzhiming/Library/Android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | # Uncomment this to preserve the line number information for 20 | # debugging stack traces. 21 | #-keepattributes SourceFile,LineNumberTable 22 | 23 | # If you keep the line number information, uncomment this to 24 | # hide the original source file name. 25 | #-renamesourcefileattribute SourceFile 26 | -dontwarn com.tuputech.base.** 27 | 28 | # gson https://github.com/google/gson/blob/master/examples/android-proguard-example/proguard.cfg 29 | # removes such information by default, so configure it to keep all of it. 30 | -keepattributes Signature 31 | # For using GSON @Expose annotation 32 | -keepattributes *Annotation* 33 | # Gson specific classes 34 | -dontwarn sun.misc.** 35 | #-keep class com.google.gson.stream.** { *; } 36 | # Application classes that will be serialized/deserialized over Gson 37 | # Prevent proguard from stripping interface information from TypeAdapterFactory, 38 | # JsonSerializer, JsonDeserializer instances (so they can be used in @JsonAdapter) 39 | -keep class * implements com.google.gson.TypeAdapterFactory 40 | -keep class * implements com.google.gson.JsonSerializer 41 | -keep class * implements com.google.gson.JsonDeserializer 42 | 43 | #retrofit2 https://github.com/square/retrofit 44 | -keepattributes Signature 45 | -keepclassmembernames,allowobfuscation interface * { 46 | @retrofit2.http.* ; 47 | } 48 | -keep class com.android.tools.** { *; } 49 | -dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement 50 | -dontwarn retrofit2.Platform$Java8 51 | 52 | #okhttp3 https://github.com/square/okhttp 53 | -dontwarn okhttp3.** 54 | -dontwarn okio.** 55 | -dontwarn javax.annotation.** 56 | -dontwarn org.conscrypt.** 57 | # A resource is loaded with a relative path so the package of this class must be preserved. 58 | -keepnames class okhttp3.internal.publicsuffix.PublicSuffixDatabase 59 | 60 | # okio https://github.com/square/okio 61 | -dontwarn okio.** 62 | 63 | -keep class com.jimi_wu.easyrxretrofit.** {*;} -------------------------------------------------------------------------------- /app/src/androidTest/java/com/jimi_wu/sample/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.jimi_wu.sample; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumentation test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.jimi_wu.sample", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/java/com/jimi_wu/sample/Constants.java: -------------------------------------------------------------------------------- 1 | package com.jimi_wu.sample; 2 | 3 | /** 4 | * Created by Administrator on 2016/11/9. 5 | */ 6 | public class Constants { 7 | 8 | public static final String BASE_URL = "http://192.168.5.127:3000"; 9 | 10 | public static final String GET_USER_URL = "/user"; //获得启动页用户 11 | 12 | public static final String UPLOAD_URL = "/upload/file"; //上传单文件 13 | 14 | public static final String UPLOADS_URL = "/upload/files"; 15 | 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/com/jimi_wu/sample/FileUtils.java: -------------------------------------------------------------------------------- 1 | package com.jimi_wu.sample; 2 | 3 | import android.content.ContentUris; 4 | import android.content.Context; 5 | import android.database.Cursor; 6 | import android.net.Uri; 7 | import android.os.Build; 8 | import android.os.Environment; 9 | import android.provider.DocumentsContract; 10 | import android.provider.MediaStore; 11 | 12 | import java.io.File; 13 | import java.io.FileNotFoundException; 14 | import java.io.FileOutputStream; 15 | import java.io.IOException; 16 | 17 | /** 18 | * Created by wuzhiming on 2016/11/16. 19 | */ 20 | 21 | public class FileUtils { 22 | 23 | /** 24 | * 根据uri获得file 25 | */ 26 | public static File getFile(Context context, Uri uri) { 27 | File file = new File(getPath(context,uri)); 28 | return file; 29 | } 30 | 31 | /** 32 | * 根据path获得file 33 | */ 34 | public static File getFile(String pathname) { 35 | File file = new File(pathname); 36 | return file; 37 | } 38 | 39 | /** 40 | * 根据Uri删除文件 41 | */ 42 | public static boolean deleteFile(Context context, Uri uri) { 43 | File file = new File(getPath(context,uri)); 44 | if (file == null || !file.exists()) 45 | return false; 46 | return file.delete(); 47 | } 48 | 49 | /** 50 | * 根据path获得file 51 | */ 52 | public static boolean deleteFile(String pathname) { 53 | File file = new File(pathname); 54 | if (file == null || !file.exists()) 55 | return false; 56 | return file.delete(); 57 | } 58 | 59 | /** 60 | * 创建路径 61 | */ 62 | public static String getDirPath() { 63 | File dir = new File(Environment.getExternalStorageDirectory()+"/wzm"); 64 | // 创建文件夹 65 | if (!dir.exists()) dir.mkdirs(); 66 | return dir.getPath(); 67 | } 68 | 69 | /** 70 | * 获得图片Uri,若没有文件,新建 71 | */ 72 | public static Uri getImgUri() { 73 | File file = createImg(); 74 | if (file == null) 75 | return Uri.EMPTY; 76 | return Uri.fromFile(file); 77 | } 78 | 79 | /** 80 | * 获得图片地址,若没有文件,新建 81 | */ 82 | public static String getImgPath(Context context) { 83 | Uri uri = getImgUri(); 84 | if (uri == Uri.EMPTY) return null; 85 | return getPath(context,uri); 86 | } 87 | 88 | /** 89 | * 创建图片 90 | */ 91 | public static File createImg() { 92 | //文件名 93 | String fileName= System.currentTimeMillis() +".jpeg"; 94 | return createFile(fileName); 95 | } 96 | 97 | /** 98 | * 获得文件 99 | */ 100 | public static File createFile(String fileName) { 101 | if (!checkSDStatus()) return null; 102 | 103 | //创建文件 104 | File file = new File(getDirPath(),fileName); 105 | if (file.exists()) 106 | file.delete(); 107 | if (!file.exists()) 108 | try { 109 | file.createNewFile(); 110 | return file; 111 | } catch (IOException e) { 112 | e.printStackTrace(); 113 | } 114 | return file; 115 | } 116 | 117 | /** 118 | * 检查sd卡状态 119 | */ 120 | public static boolean checkSDStatus() { 121 | //判断sd是否可用 122 | String sdStatus = Environment.getExternalStorageState(); 123 | if (!sdStatus.equals(Environment.MEDIA_MOUNTED)) 124 | { 125 | return false; 126 | } 127 | return true; 128 | } 129 | 130 | 131 | /** 132 | * 根据uri获取图片路径的函数,由于4.4之后uri发生变化,不能采用之前的方式获取路径 133 | * @param context 134 | * @param uri 135 | * @return 136 | */ 137 | public static String getPath(final Context context, final Uri uri) { 138 | final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT; 139 | // DocumentProvider 140 | if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) { 141 | // ExternalStorageProvider 142 | if (isExternalStorageDocument(uri)) { 143 | final String docId = DocumentsContract.getDocumentId(uri); 144 | final String[] split = docId.split(":"); 145 | final String type = split[0]; 146 | if ("primary".equalsIgnoreCase(type)) { 147 | return Environment.getExternalStorageDirectory() + "/" + split[1]; 148 | } 149 | // TODO handle non-primary volumes 150 | } 151 | // DownloadsProvider 152 | else if (isDownloadsDocument(uri)) { 153 | final String id = DocumentsContract.getDocumentId(uri); 154 | final Uri contentUri = ContentUris.withAppendedId( 155 | Uri.parse("content://downloads/public_downloads"), Long.valueOf(id)); 156 | return getDataColumn(context, contentUri, null, null); 157 | } 158 | // MediaProvider 159 | else if (isMediaDocument(uri)) { 160 | final String docId = DocumentsContract.getDocumentId(uri); 161 | final String[] split = docId.split(":"); 162 | final String type = split[0]; 163 | Uri contentUri = null; 164 | if ("image".equals(type)) { 165 | contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; 166 | } else if ("video".equals(type)) { 167 | contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI; 168 | } else if ("audio".equals(type)) { 169 | contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; 170 | } 171 | final String selection = "_id=?"; 172 | final String[] selectionArgs = new String[] { 173 | split[1] 174 | }; 175 | return getDataColumn(context, contentUri, selection, selectionArgs); 176 | } 177 | } 178 | // MediaStore (and general) 179 | else if ("content".equalsIgnoreCase(uri.getScheme())) { 180 | // Return the remote address 181 | if (isGooglePhotosUri(uri)) 182 | return uri.getLastPathSegment(); 183 | return getDataColumn(context, uri, null, null); 184 | } 185 | // File 186 | else if ("file".equalsIgnoreCase(uri.getScheme())) { 187 | return uri.getPath(); 188 | } 189 | return null; 190 | } 191 | /** 192 | * Get the value of the data column for this Uri. This is useful for 193 | * MediaStore Uris, and other file-based ContentProviders. 194 | * 195 | * @param context The context. 196 | * @param uri The Uri to query. 197 | * @param selection (Optional) Filter used in the query. 198 | * @param selectionArgs (Optional) Selection arguments used in the query. 199 | * @return The value of the _data column, which is typically a file path. 200 | */ 201 | public static String getDataColumn(Context context, Uri uri, String selection, 202 | String[] selectionArgs) { 203 | Cursor cursor = null; 204 | final String column = "_data"; 205 | final String[] projection = { 206 | column 207 | }; 208 | try { 209 | cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, 210 | null); 211 | if (cursor != null && cursor.moveToFirst()) { 212 | final int index = cursor.getColumnIndexOrThrow(column); 213 | return cursor.getString(index); 214 | } 215 | } finally { 216 | if (cursor != null) 217 | cursor.close(); 218 | } 219 | return null; 220 | } 221 | /** 222 | * @param uri The Uri to check. 223 | * @return Whether the Uri authority is ExternalStorageProvider. 224 | */ 225 | public static boolean isExternalStorageDocument(Uri uri) { 226 | return "com.android.externalstorage.documents".equals(uri.getAuthority()); 227 | } 228 | /** 229 | * @param uri The Uri to check. 230 | * @return Whether the Uri authority is DownloadsProvider. 231 | */ 232 | public static boolean isDownloadsDocument(Uri uri) { 233 | return "com.android.providers.downloads.documents".equals(uri.getAuthority()); 234 | } 235 | /** 236 | * @param uri The Uri to check. 237 | * @return Whether the Uri authority is MediaProvider. 238 | */ 239 | public static boolean isMediaDocument(Uri uri) { 240 | return "com.android.providers.media.documents".equals(uri.getAuthority()); 241 | } 242 | /** 243 | * @param uri The Uri to check. 244 | * @return Whether the Uri authority is Google Photos. 245 | */ 246 | public static boolean isGooglePhotosUri(Uri uri) { 247 | return "com.google.android.apps.photos.content".equals(uri.getAuthority()); 248 | } 249 | 250 | /** 251 | * 将byte[]写入文件 252 | * @param filePath 253 | * @param bytes 254 | */ 255 | public static void writeToFile(String filePath, byte[] bytes) 256 | { 257 | try { 258 | FileOutputStream fileOutputStream = new FileOutputStream(filePath); 259 | fileOutputStream.write(bytes); 260 | fileOutputStream.close(); 261 | } catch (FileNotFoundException e) { 262 | e.printStackTrace(); 263 | } catch (IOException e) { 264 | e.printStackTrace(); 265 | } 266 | } 267 | 268 | 269 | } 270 | -------------------------------------------------------------------------------- /app/src/main/java/com/jimi_wu/sample/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.jimi_wu.sample; 2 | 3 | import android.content.Intent; 4 | import android.net.Uri; 5 | import android.os.Bundle; 6 | import android.support.v7.app.AppCompatActivity; 7 | import android.util.Log; 8 | import android.view.View; 9 | import android.widget.TextView; 10 | 11 | import com.jimi_wu.easyrxretrofit.RetrofitManager; 12 | import com.jimi_wu.easyrxretrofit.observer.BaseObserver; 13 | import com.jimi_wu.easyrxretrofit.observer.DownLoadObserver; 14 | import com.jimi_wu.easyrxretrofit.observer.UploadObserver; 15 | import com.jimi_wu.easyrxretrofit.upload.UploadParam; 16 | import com.jimi_wu.sample.apiservice.GetUserService; 17 | import com.jimi_wu.sample.model.FileBean; 18 | import com.jimi_wu.sample.model.ResultBean; 19 | import com.jimi_wu.sample.model.UserBean; 20 | 21 | import java.io.File; 22 | import java.util.ArrayList; 23 | 24 | import io.reactivex.android.schedulers.AndroidSchedulers; 25 | import io.reactivex.schedulers.Schedulers; 26 | 27 | public class MainActivity extends AppCompatActivity implements View.OnClickListener { 28 | 29 | private String TAG; 30 | 31 | private static int REQUEST_CODE_UPLOAD = 1; 32 | private static int REQUEST_CODE_UPLOADS = 2; 33 | 34 | private TextView tv; 35 | private TextView tvActualProgress; 36 | 37 | @Override 38 | protected void onCreate(Bundle savedInstanceState) { 39 | super.onCreate(savedInstanceState); 40 | TAG = getClass().getSimpleName(); 41 | setContentView(R.layout.activity_main); 42 | findViewById(R.id.btn).setOnClickListener(this); 43 | findViewById(R.id.btn_upload).setOnClickListener(this); 44 | findViewById(R.id.btn_uploads).setOnClickListener(this); 45 | findViewById(R.id.btn_download).setOnClickListener(this); 46 | tv = (TextView) findViewById(R.id.tv); 47 | tvActualProgress = (TextView) findViewById(R.id.tv_actual_progress); 48 | } 49 | 50 | @Override 51 | public void onClick(View v) { 52 | switch (v.getId()) { 53 | case R.id.btn: 54 | tvActualProgress.setText(""); 55 | RetrofitManager 56 | .createService(GetUserService.class) 57 | .start() 58 | .compose(RetrofitManager.handleResult()) 59 | .subscribeOn(Schedulers.io()) 60 | .observeOn(AndroidSchedulers.mainThread()) 61 | .subscribe(new BaseObserver() { 62 | @Override 63 | protected void _onNext(UserBean userBean) { 64 | Log.i("retrofit", "onNext=========>" + userBean.getName()); 65 | tv.setText("请求成功:" + userBean.getName()); 66 | } 67 | 68 | @Override 69 | protected void _onError(Throwable e) { 70 | Log.i("retrofit", "onError=========>" + e.getMessage()); 71 | tv.setText("请求失败:" + e.getMessage()); 72 | } 73 | }); 74 | break; 75 | case R.id.btn_upload: 76 | Intent uploadIntent = new Intent(); 77 | uploadIntent.setType("*/*"); 78 | uploadIntent.setAction(Intent.ACTION_GET_CONTENT); 79 | startActivityForResult(Intent.createChooser(uploadIntent, "单文件选择"), REQUEST_CODE_UPLOAD); 80 | break; 81 | case R.id.btn_uploads: 82 | Intent uploadsIntent = new Intent(); 83 | uploadsIntent.setType("*/*"); 84 | uploadsIntent.setAction(Intent.ACTION_GET_CONTENT); 85 | startActivityForResult(Intent.createChooser(uploadsIntent, "单文件选择"), REQUEST_CODE_UPLOADS); 86 | break; 87 | case R.id.btn_download: 88 | downLoad(); 89 | break; 90 | } 91 | } 92 | 93 | private ArrayList uris = new ArrayList<>(); 94 | 95 | @Override 96 | protected void onActivityResult(int requestCode, int resultCode, Intent data) { 97 | super.onActivityResult(requestCode, resultCode, data); 98 | if (resultCode == RESULT_OK) { 99 | if (requestCode == REQUEST_CODE_UPLOAD) { 100 | Uri uri = data.getData(); 101 | File file = FileUtils.getFile(this, uri); 102 | upload(file); 103 | return; 104 | } 105 | if (requestCode == REQUEST_CODE_UPLOADS) { 106 | uris.add(data.getData()); 107 | if (uris.size() < 3) { 108 | tv.setText("当前选择 " + uris.size() + " 个文件\n请继续选择\n3 个文件时将上传"); 109 | return; 110 | } 111 | ArrayList files = new ArrayList<>(); 112 | for (Uri uri : uris) { 113 | File file = FileUtils.getFile(this, uri); 114 | files.add(file); 115 | } 116 | uploads(files); 117 | uris.clear(); 118 | return; 119 | } 120 | } 121 | } 122 | 123 | /** 124 | * 单图上传 125 | */ 126 | public void upload(File file) { 127 | RetrofitManager 128 | .uploadFile(Constants.UPLOAD_URL, new UploadParam("upload", file)) 129 | .subscribeOn(Schedulers.io()) 130 | .observeOn(AndroidSchedulers.mainThread()) 131 | .subscribe(new UploadObserver>() { 132 | 133 | @Override 134 | public void _onNext(ResultBean fileBeanResultBean) { 135 | Log.i("retrofit", "onNext=======>url:" + fileBeanResultBean.getData().getUrl()); 136 | tv.setText("上传成功:" + fileBeanResultBean.getData().getUrl()); 137 | } 138 | 139 | @Override 140 | public void _onProgress(Integer percent) { 141 | Log.i("retrofit", "onProgress======>" + percent); 142 | tv.setText("上传中:" + percent); 143 | } 144 | 145 | @Override 146 | public void _onProgress(long uploaded, long sumLength) { 147 | tvActualProgress.setText("上传中:" + uploaded + "/" + sumLength); 148 | } 149 | 150 | @Override 151 | public void _onError(Throwable e) { 152 | Log.i("retrofit", "onError======>" + e.getMessage()); 153 | tv.setText("上传失败:" + e.getMessage()); 154 | } 155 | }); 156 | } 157 | 158 | 159 | /** 160 | * 多图上传 161 | */ 162 | public void uploads(ArrayList files) { 163 | ArrayList uploadParams = new ArrayList<>(files.size()); 164 | for (File file : files) { 165 | uploadParams.add(new UploadParam("upload", file)); 166 | } 167 | RetrofitManager 168 | .uploadFile(Constants.UPLOADS_URL, 169 | uploadParams) 170 | .subscribeOn(Schedulers.io()) 171 | .observeOn(AndroidSchedulers.mainThread()) 172 | .subscribe(new UploadObserver>>() { 173 | 174 | @Override 175 | public void _onNext(ResultBean> arrayListResultBean) { 176 | ArrayList fileBeans = arrayListResultBean.getData(); 177 | StringBuilder stringBuilder = new StringBuilder(); 178 | for (FileBean fileBean : fileBeans) { 179 | stringBuilder.append("上传成功:" + fileBean.getUrl() + "\n"); 180 | } 181 | Log.d("retrofit", "onNext=======>" + stringBuilder); 182 | tv.setText("上传成功:" + stringBuilder); 183 | } 184 | 185 | @Override 186 | public void _onProgress(Integer percent) { 187 | Log.i("retrofit", "onProgress=======>" + percent); 188 | tv.setText("上传中:" + percent); 189 | } 190 | 191 | @Override 192 | public void _onProgress(long uploaded, long sumLength) { 193 | tvActualProgress.setText("上传中:" + uploaded + "/" + sumLength); 194 | } 195 | 196 | @Override 197 | public void _onError(Throwable e) { 198 | Log.d("retrofit", "onError======>" + e.getMessage()); 199 | tv.setText("上传失败:" + e.getMessage()); 200 | } 201 | }); 202 | } 203 | 204 | /** 205 | * 文件下载 206 | */ 207 | public void downLoad() { 208 | RetrofitManager 209 | .download("/uploads/test.pdf") 210 | .subscribeOn(Schedulers.io()) 211 | .observeOn(AndroidSchedulers.mainThread()) 212 | .subscribe(new DownLoadObserver() { 213 | @Override 214 | public void _onNext(String result) { 215 | Log.i("retrofit", "onNext=======>" + result); 216 | tv.setText("下载成功:" + result); 217 | } 218 | 219 | @Override 220 | public void _onProgress(Integer percent) { 221 | Log.i("retrofit", "onProgress=======>" + percent); 222 | tv.setText("下载中:" + percent); 223 | } 224 | 225 | @Override 226 | public void _onProgress(long uploaded, long sumLength) { 227 | tvActualProgress.setText("下载中:" + uploaded + "/" + sumLength); 228 | } 229 | 230 | @Override 231 | public void _onError(Throwable e) { 232 | Log.i("retrofit", "onProgress=======>" + e.getMessage()); 233 | tv.setText("下载失败:" + e.getMessage()); 234 | } 235 | }); 236 | } 237 | 238 | 239 | } 240 | -------------------------------------------------------------------------------- /app/src/main/java/com/jimi_wu/sample/apiservice/GetUserService.java: -------------------------------------------------------------------------------- 1 | package com.jimi_wu.sample.apiservice; 2 | 3 | 4 | import com.jimi_wu.sample.Constants; 5 | import com.jimi_wu.sample.model.ResultBean; 6 | import com.jimi_wu.sample.model.UserBean; 7 | 8 | import io.reactivex.Observable; 9 | import retrofit2.http.POST; 10 | 11 | /** 12 | * Created by Administrator on 2016/11/9. 13 | */ 14 | public interface GetUserService { 15 | 16 | @POST(Constants.GET_USER_URL) 17 | Observable> start(); 18 | 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/java/com/jimi_wu/sample/application/SampleApplication.java: -------------------------------------------------------------------------------- 1 | package com.jimi_wu.sample.application; 2 | 3 | import android.app.Application; 4 | 5 | import com.jimi_wu.easyrxretrofit.RetrofitManager; 6 | import com.jimi_wu.easyrxretrofit.build.DefaultRetrofitBuilder; 7 | import com.jimi_wu.sample.Constants; 8 | 9 | /** 10 | * Created by Administrator on 2016/11/9. 11 | */ 12 | public class SampleApplication extends Application { 13 | 14 | @Override 15 | public void onCreate() { 16 | super.onCreate(); 17 | // 在此处初始化Retrofit 18 | RetrofitManager 19 | .init(new SampleRetrofitBuilder()); 20 | } 21 | 22 | 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/java/com/jimi_wu/sample/application/SampleRetrofitBuilder.java: -------------------------------------------------------------------------------- 1 | package com.jimi_wu.sample.application; 2 | 3 | import com.jimi_wu.easyrxretrofit.agent.AgentInterceptor; 4 | import com.jimi_wu.easyrxretrofit.build.RetrofitBuilder; 5 | import com.jimi_wu.sample.Constants; 6 | 7 | import java.util.concurrent.TimeUnit; 8 | 9 | import okhttp3.OkHttpClient; 10 | import retrofit2.Retrofit; 11 | import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory; 12 | import retrofit2.converter.gson.GsonConverterFactory; 13 | 14 | /** 15 | * created by wuzhiming on 2019/2/21 16 | */ 17 | public class SampleRetrofitBuilder implements RetrofitBuilder { 18 | 19 | @Override 20 | public Retrofit initRetrofit() { 21 | OkHttpClient okHttpClient = new OkHttpClient.Builder() 22 | .connectTimeout(60, TimeUnit.SECONDS) 23 | .readTimeout(60, TimeUnit.SECONDS) 24 | .retryOnConnectionFailure(true) 25 | .addInterceptor(new AgentInterceptor("EasyRxRetrofit")) 26 | .build(); 27 | 28 | return new Retrofit.Builder() 29 | .baseUrl(Constants.BASE_URL) 30 | .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) 31 | .addConverterFactory(GsonConverterFactory.create()) 32 | .client(okHttpClient) 33 | .build(); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /app/src/main/java/com/jimi_wu/sample/model/FileBean.java: -------------------------------------------------------------------------------- 1 | package com.jimi_wu.sample.model; 2 | 3 | /** 4 | * Created by wzm on 2017/6/14. 5 | */ 6 | 7 | public class FileBean extends ResultBean { 8 | 9 | private String url; 10 | 11 | public String getUrl() { 12 | return url; 13 | } 14 | 15 | public void setUrl(String url) { 16 | this.url = url; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /app/src/main/java/com/jimi_wu/sample/model/ResultBean.java: -------------------------------------------------------------------------------- 1 | package com.jimi_wu.sample.model; 2 | 3 | 4 | import com.jimi_wu.easyrxretrofit.transformer.BaseModel; 5 | 6 | /** 7 | * Created by wzm on 2017/6/14. 8 | */ 9 | 10 | public class ResultBean implements BaseModel { 11 | 12 | private int code; 13 | 14 | private T data; 15 | 16 | private String errMsg; 17 | 18 | public String getErrMsg() { 19 | return errMsg; 20 | } 21 | 22 | public void setErrMsg(String errMsg) { 23 | this.errMsg = errMsg; 24 | } 25 | 26 | public int getCode() { 27 | return code; 28 | } 29 | 30 | public void setCode(int code) { 31 | this.code = code; 32 | } 33 | 34 | public T getData() { 35 | return data; 36 | } 37 | 38 | public void setData(T data) { 39 | this.data = data; 40 | } 41 | 42 | @Override 43 | public boolean isError() { 44 | return code != 200; 45 | } 46 | 47 | @Override 48 | public String getMsg() { 49 | return errMsg; 50 | } 51 | 52 | @Override 53 | public T getResult() { 54 | return data; 55 | } 56 | 57 | 58 | } 59 | -------------------------------------------------------------------------------- /app/src/main/java/com/jimi_wu/sample/model/UserBean.java: -------------------------------------------------------------------------------- 1 | package com.jimi_wu.sample.model; 2 | 3 | /** 4 | * Created by Administrator on 2016/11/9. 5 | */ 6 | public class UserBean { 7 | 8 | private String id; 9 | private String avatar; 10 | private String name; 11 | 12 | public String getId() { 13 | return id; 14 | } 15 | 16 | public void setId(String id) { 17 | this.id = id; 18 | } 19 | 20 | public String getAvatar() { 21 | return avatar; 22 | } 23 | 24 | public void setAvatar(String avatar) { 25 | this.avatar = avatar; 26 | } 27 | 28 | public String getName() { 29 | return name; 30 | } 31 | 32 | public void setName(String name) { 33 | this.name = name; 34 | } 35 | 36 | 37 | } 38 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 |