resource, int outWidth, int outHeight) {
54 | Bitmap source = resource.get();
55 | int size = Math.min(source.getWidth(), source.getHeight());
56 |
57 | int width = (source.getWidth() - size) / 2;
58 | int height = (source.getHeight() - size) / 2;
59 |
60 | Bitmap bitmap = mBitmapPool.get(size, size, Bitmap.Config.ARGB_8888);
61 | if (bitmap == null) {
62 | bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
63 | }
64 |
65 | Canvas canvas = new Canvas(bitmap);
66 | Paint paint = new Paint();
67 | BitmapShader shader =
68 | new BitmapShader(source, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP);
69 | if (width != 0 || height != 0) {
70 | // source isn't square, move viewport to center
71 | Matrix matrix = new Matrix();
72 | matrix.setTranslate(-width, -height);
73 | shader.setLocalMatrix(matrix);
74 | }
75 | paint.setShader(shader);
76 | paint.setAntiAlias(true);
77 |
78 | float r = size / 2f;
79 | canvas.drawCircle(r, r, r, paint);
80 |
81 | return BitmapResource.obtain(bitmap, mBitmapPool);
82 | }
83 |
84 | @Override
85 | public String getId() {
86 | return "CropCircleTransformation()";
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sunflower/rxandroiddemo/utils/HttpLoggingInterceptor.java:
--------------------------------------------------------------------------------
1 | package com.sunflower.rxandroiddemo.utils;
2 |
3 |
4 | import java.io.IOException;
5 | import java.nio.charset.Charset;
6 | import java.util.concurrent.TimeUnit;
7 |
8 | import okhttp3.Headers;
9 | import okhttp3.Interceptor;
10 | import okhttp3.MediaType;
11 | import okhttp3.MultipartBody;
12 | import okhttp3.Protocol;
13 | import okhttp3.Request;
14 | import okhttp3.RequestBody;
15 | import okhttp3.Response;
16 | import okhttp3.internal.Platform;
17 | import okio.Buffer;
18 |
19 | /**
20 | * Created by Sunflower on 2016/1/12.
21 | */
22 | public class HttpLoggingInterceptor implements Interceptor {
23 | private static final Charset UTF8 = Charset.forName("UTF-8");
24 |
25 | public enum Level {
26 | /**
27 | * No logs.
28 | */
29 | NONE,
30 | /**
31 | * Logs request and response lines.
32 | *
33 | * Example:
34 | * {@code
35 | * --> POST /greeting HTTP/1.1 (3-byte body)
36 | *
37 | * <-- HTTP/1.1 200 OK (22ms, 6-byte body)
38 | * }
39 | */
40 | BASIC,
41 | /**
42 | * Logs request and response lines and their respective headers.
43 | *
44 | * Example:
45 | * {@code
46 | * --> POST /greeting HTTP/1.1
47 | * Host: example.com
48 | * Content-Type: plain/text
49 | * Content-Length: 3
50 | * --> END POST
51 | *
52 | * <-- HTTP/1.1 200 OK (22ms)
53 | * Content-Type: plain/text
54 | * Content-Length: 6
55 | * <-- END HTTP
56 | * }
57 | */
58 | HEADERS,
59 | /**
60 | * Logs request and response lines and their respective headers and bodies (if present).
61 | *
62 | * Example:
63 | * {@code
64 | * --> POST /greeting HTTP/1.1
65 | * Host: example.com
66 | * Content-Type: plain/text
67 | * Content-Length: 3
68 | *
69 | * Hi?
70 | * --> END GET
71 | *
72 | * <-- HTTP/1.1 200 OK (22ms)
73 | * Content-Type: plain/text
74 | * Content-Length: 6
75 | *
76 | * Hello!
77 | * <-- END HTTP
78 | * }
79 | */
80 | BODY
81 | }
82 |
83 | public interface Logger {
84 | void log(String message);
85 |
86 | /**
87 | * A {@link Logger} defaults output appropriate for the current platform.
88 | */
89 | Logger DEFAULT = new Logger() {
90 | @Override
91 | public void log(String message) {
92 | Platform.get().log(message);
93 | }
94 | };
95 | }
96 |
97 | public HttpLoggingInterceptor() {
98 | this(Logger.DEFAULT);
99 | }
100 |
101 | public HttpLoggingInterceptor(Logger logger) {
102 | this.logger = logger;
103 | }
104 |
105 | private final Logger logger;
106 |
107 | private volatile Level level = Level.BODY;
108 |
109 | /**
110 | * Change the level at which this interceptor logs.
111 | */
112 | public HttpLoggingInterceptor setLevel(Level level) {
113 | if (level == null) throw new NullPointerException("level == null. Use Level.NONE instead.");
114 | this.level = level;
115 | return this;
116 | }
117 |
118 | @Override
119 | public Response intercept(Interceptor.Chain chain) throws IOException {
120 | Level level = this.level;
121 |
122 | Request request = chain.request();
123 | if (level == Level.NONE) {
124 | return chain.proceed(request);
125 | }
126 |
127 | boolean logBody = level == Level.BODY;
128 | boolean logHeaders = logBody || level == Level.HEADERS;
129 |
130 | RequestBody requestBody = request.body();
131 | boolean hasRequestBody = requestBody != null;
132 |
133 | String requestStartMessage = request.method() + ' ' + request.url();
134 | if (!logHeaders && hasRequestBody) {
135 | requestStartMessage += " (" + requestBody.contentLength() + "-byte body)";
136 | }
137 | logger.log(requestStartMessage);
138 |
139 | if (logHeaders) {
140 |
141 | if (!logBody || !hasRequestBody) {
142 | logger.log("--> END " + request.method());
143 | } else if (bodyEncoded(request.headers())) {
144 | logger.log("--> END " + request.method() + " (encoded body omitted)");
145 | } else if (request.body() instanceof MultipartBody) {
146 | //如果是MultipartBody,会log出一大推乱码的东东
147 | } else {
148 | Buffer buffer = new Buffer();
149 | requestBody.writeTo(buffer);
150 |
151 | Charset charset = UTF8;
152 | MediaType contentType = requestBody.contentType();
153 | if (contentType != null) {
154 | contentType.charset(UTF8);
155 | }
156 |
157 | logger.log(buffer.readString(charset));
158 |
159 | // logger.log(request.method() + " (" + requestBody.contentLength() + "-byte body)");
160 | }
161 | }
162 |
163 | long startNs = System.nanoTime();
164 | Response response = chain.proceed(request);
165 | long tookMs = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNs);
166 | logger.log(response.code() + ' ' + response.message() + " (" + tookMs + "ms" + ')');
167 |
168 | return response;
169 | }
170 |
171 | private boolean bodyEncoded(Headers headers) {
172 | String contentEncoding = headers.get("Content-Encoding");
173 | return contentEncoding != null && !contentEncoding.equalsIgnoreCase("identity");
174 | }
175 |
176 | private static String protocol(Protocol protocol) {
177 | return protocol == Protocol.HTTP_1_0 ? "HTTP/1.0" : "HTTP/1.1";
178 | }
179 | }
180 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sunflower/rxandroiddemo/utils/ProgressResponseBody.java:
--------------------------------------------------------------------------------
1 | package com.sunflower.rxandroiddemo.utils;
2 |
3 | import java.io.IOException;
4 |
5 | import okhttp3.MediaType;
6 | import okhttp3.ResponseBody;
7 | import okio.Buffer;
8 | import okio.BufferedSource;
9 | import okio.ForwardingSource;
10 | import okio.Okio;
11 | import okio.Source;
12 |
13 | /**
14 | * Created by Sunflower on 2016/1/15.
15 | */
16 | public class ProgressResponseBody extends ResponseBody {
17 | private final ResponseBody responseBody;
18 | private BufferedSource bufferedSource;
19 |
20 | public ProgressResponseBody(ResponseBody responseBody) {
21 | this.responseBody = responseBody;
22 | // this.progressListener = progressListener;
23 | }
24 |
25 | @Override
26 | public MediaType contentType() {
27 | return responseBody.contentType();
28 | }
29 |
30 | @Override
31 | public long contentLength() {
32 | return responseBody.contentLength();
33 | }
34 |
35 | @Override
36 | public BufferedSource source() {
37 | if (bufferedSource == null) {
38 | bufferedSource = Okio.buffer(source(responseBody.source()));
39 | }
40 | return bufferedSource;
41 | }
42 |
43 | private Source source(Source source) {
44 | return new ForwardingSource(source) {
45 | long totalBytesRead = 0L;
46 |
47 | @Override
48 | public long read(Buffer sink, long byteCount) throws IOException {
49 | long bytesRead = super.read(sink, byteCount);
50 | // read() returns the number of bytes read, or -1 if this source is exhausted.
51 | totalBytesRead += bytesRead != -1 ? bytesRead : 0;
52 | // progressListener.update(totalBytesRead, responseBody.contentLength(), bytesRead == -1);
53 | return bytesRead;
54 | }
55 | };
56 | }
57 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/sunflower/rxandroiddemo/utils/RetrofitUtil.java:
--------------------------------------------------------------------------------
1 | package com.sunflower.rxandroiddemo.utils;
2 |
3 | import android.graphics.Bitmap;
4 | import android.util.Log;
5 |
6 | import com.sunflower.rxandroiddemo.api.APIService;
7 | import com.sunflower.rxandroiddemo.dto.Response;
8 |
9 | import java.io.File;
10 |
11 | import okhttp3.MediaType;
12 | import okhttp3.OkHttpClient;
13 | import okhttp3.RequestBody;
14 | import retrofit2.GsonConverterFactory;
15 | import retrofit2.Retrofit;
16 | import retrofit2.RxJavaCallAdapterFactory;
17 | import rx.Observable;
18 | import rx.Subscriber;
19 | import rx.android.schedulers.AndroidSchedulers;
20 | import rx.functions.Func1;
21 | import rx.schedulers.Schedulers;
22 |
23 | /**
24 | * Created by Sunflower on 2015/11/4.
25 | */
26 | public class RetrofitUtil {
27 |
28 | /**
29 | * 服务器地址
30 | */
31 | private static final String API_HOST = SecretConstant.API_HOST;
32 |
33 | private static APIService service;
34 | private static Retrofit retrofit;
35 |
36 | public static APIService getService() {
37 | if (service == null) {
38 | service = getRetrofit().create(APIService.class);
39 | }
40 | return service;
41 | }
42 |
43 | private static Retrofit getRetrofit() {
44 | if (retrofit == null) {
45 | HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
46 | @Override
47 | public void log(String message) {
48 | Log.i("RxJava", message);
49 | }
50 | });
51 | //网络缓存路径文件
52 | // File httpCacheDirectory = new File(BaseApplication.getInstance().getExternalCacheDir(), "responses");
53 | //通过拦截器设置缓存,暂未实现
54 | //CacheInterceptor cacheInterceptor = new CacheInterceptor();
55 |
56 | OkHttpClient client = new OkHttpClient.Builder()
57 | //设置缓存
58 | // .cache(new Cache(httpCacheDirectory, 10 * 1024 * 1024))
59 | //log请求参数
60 | .addInterceptor(interceptor)
61 | //网络请求缓存,未实现
62 | // .addInterceptor(cacheInterceptor)
63 | .build();
64 | retrofit = new Retrofit.Builder()
65 | .client(client)
66 | .baseUrl(API_HOST)
67 | .addConverterFactory(GsonConverterFactory.create())
68 | .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
69 | .build();
70 | }
71 | return retrofit;
72 | }
73 |
74 | /**
75 | * 对网络接口返回的Response进行分割操作
76 | *
77 | * @param response
78 | * @param
79 | * @return
80 | */
81 | public Observable flatResponse(final Response response) {
82 | return Observable.create(new Observable.OnSubscribe() {
83 |
84 | @Override
85 | public void call(Subscriber super T> subscriber) {
86 | if (response.isSuccess()) {
87 | if (!subscriber.isUnsubscribed()) {
88 | subscriber.onNext(response.object);
89 | }
90 | } else {
91 | if (!subscriber.isUnsubscribed()) {
92 | subscriber.onError(new APIException(response.code, response.message));
93 | }
94 | return;
95 | }
96 |
97 | if (!subscriber.isUnsubscribed()) {
98 | subscriber.onCompleted();
99 | }
100 |
101 | }
102 | });
103 | }
104 |
105 |
106 | /**
107 | * 自定义异常,当接口返回的{@link Response#code}不为{@link Constant#OK}时,需要跑出此异常
108 | * eg:登陆时验证码错误;参数为传递等
109 | */
110 | public static class APIException extends Exception {
111 | public String code;
112 | public String message;
113 |
114 | public APIException(String code, String message) {
115 | this.code = code;
116 | this.message = message;
117 | }
118 |
119 | @Override
120 | public String getMessage() {
121 | return message;
122 | }
123 | }
124 |
125 |
126 | /**
127 | * http://www.jianshu.com/p/e9e03194199e
128 | *
129 | * Transformer实际上就是一个Func1, Observable>,
130 | * 换言之就是:可以通过它将一种类型的Observable转换成另一种类型的Observable,
131 | * 和调用一系列的内联操作符是一模一样的。
132 | *
133 | * @param
134 | * @return
135 | */
136 | // protected Observable.Transformer applySchedulers() {
137 | //// return new Observable.Transformer() {
138 | //// @Override
139 | //// public Observable call(Observable observable) {
140 | //// return observable.subscribeOn(Schedulers.io())
141 | //// .observeOn(AndroidSchedulers.mainThread());
142 | //// }
143 | //// };
144 | //
145 | // return (Observable.Transformer) schedulersTransformer;
146 | // }
147 | //
148 | // final Observable.Transformer schedulersTransformer = new Observable.Transformer() {
149 | // @Override
150 | // public Object call(Object observable) {
151 | // return ((Observable) observable).subscribeOn(Schedulers.io())
152 | // .observeOn(AndroidSchedulers.mainThread())
153 | // ;
154 | // }
155 | // };
156 |
157 | protected Observable.Transformer, T> applySchedulers() {
158 | // return new Observable.Transformer, T>() {
159 | // @Override
160 | // public Observable call(Observable> responseObservable) {
161 | // return responseObservable.subscribeOn(Schedulers.io())
162 | // .observeOn(AndroidSchedulers.mainThread())
163 | // .flatMap(new Func1, Observable>() {
164 | // @Override
165 | // public Observable call(Response tResponse) {
166 | // return flatResponse(tResponse);
167 | // }
168 | // })
169 | // ;
170 | // }
171 | // };
172 | return (Observable.Transformer, T>) transformer;
173 | }
174 |
175 | final Observable.Transformer transformer = new Observable.Transformer() {
176 | @Override
177 | public Object call(Object observable) {
178 | return ((Observable) observable).subscribeOn(Schedulers.io())
179 | .observeOn(AndroidSchedulers.mainThread())
180 | .flatMap(new Func1() {
181 | @Override
182 | public Object call(Object response) {
183 | return flatResponse((Response