> cacheData = memoryCacheManager.getDataFromMemoryCache(key);
130 | if (cacheData != null && cacheData.getEntry() != null && cacheData.getEntry().result != null) {
131 | return (T) cacheData.getEntry().result;
132 | }
133 | return null;
134 | }
135 |
136 | }
137 |
--------------------------------------------------------------------------------
/XDroidRequest/src/com/xdroid/request/network/ByteArrayPool.java:
--------------------------------------------------------------------------------
1 | package com.xdroid.request.network;
2 |
3 | import java.util.ArrayList;
4 | import java.util.Collections;
5 | import java.util.Comparator;
6 | import java.util.LinkedList;
7 | import java.util.List;
8 |
9 | /**
10 | * ByteArrayPool is a source and repository of byte[] objects. Its
11 | * purpose is to supply those buffers to consumers who need to use them for a
12 | * short period of time and then dispose of them. Simply creating and disposing
13 | * such buffers in the conventional manner can considerable heap churn and
14 | * garbage collection delays on Android, which lacks good management of
15 | * short-lived heap objects. It may be advantageous to trade off some memory in
16 | * the form of a permanently allocated pool of buffers in order to gain heap
17 | * performance improvements; that is what this class does.
18 | *
19 | * A good candidate user for this class is something like an I/O system that
20 | * uses large temporary byte[] buffers to copy data around. In
21 | * these use cases, often the consumer wants the buffer to be a certain minimum
22 | * size to ensure good performance (e.g. when copying data chunks off of a
23 | * stream), but doesn't mind if the buffer is larger than the minimum. Taking
24 | * this into account and also to maximize the odds of being able to reuse a
25 | * recycled buffer, this class is free to return buffers larger than the
26 | * requested size. The caller needs to be able to gracefully deal with getting
27 | * buffers any size over the minimum.
28 | *
29 | * If there is not a suitably-sized buffer in its recycling pool when a buffer
30 | * is requested, this class will allocate a new buffer and return it.
31 | *
32 | * This class has no special ownership of buffers it creates; the caller is free
33 | * to take a buffer it receives from this pool, use it permanently, and never
34 | * return it to the pool; additionally, it is not harmful to return to this pool
35 | * a buffer that was allocated elsewhere, provided there are no other lingering
36 | * references to it.
37 | *
38 | * This class ensures that the total size of the buffers in its recycling pool
39 | * never exceeds a certain byte limit. When a buffer is returned that would
40 | * cause the pool to exceed the limit, least-recently-used buffers are disposed.
41 | */
42 | public class ByteArrayPool {
43 | /** The buffer pool, arranged both by last use and by buffer size */
44 | private final List mBuffersByLastUse = new LinkedList();
45 | private final List mBuffersBySize = new ArrayList(64);
46 |
47 | /** The total size of the buffers in the pool */
48 | private int mCurrentSize = 0;
49 |
50 | /**
51 | * The maximum aggregate size of the buffers in the pool. Old buffers are
52 | * discarded to stay under this limit.
53 | */
54 | private final int mSizeLimit;
55 |
56 | /** Compares buffers by size */
57 | protected static final Comparator BUF_COMPARATOR = new Comparator() {
58 | @Override
59 | public int compare(byte[] lhs, byte[] rhs) {
60 | return lhs.length - rhs.length;
61 | }
62 | };
63 |
64 | /**
65 | * @param sizeLimit
66 | * the maximum size of the pool, in bytes
67 | */
68 | private ByteArrayPool(int sizeLimit) {
69 | mSizeLimit = sizeLimit;
70 | }
71 |
72 | /** Singleton for this class. */
73 | private static ByteArrayPool mPool = new ByteArrayPool(4096);
74 |
75 | /** Get the singleton instance. */
76 | public static ByteArrayPool get() {
77 | return mPool;
78 | }
79 |
80 | /** Init and persisting the singleton instance. */
81 | public static void init(int poolSize) {
82 | mPool = new ByteArrayPool(poolSize);
83 | }
84 |
85 | /**
86 | * Returns a buffer from the pool if one is available in the requested size,
87 | * or allocates a new one if a pooled one is not available.
88 | *
89 | * @param len
90 | * the minimum size, in bytes, of the requested buffer. The
91 | * returned buffer may be larger.
92 | * @return a byte[] buffer is always returned.
93 | */
94 | public synchronized byte[] getBuf(int len) {
95 | for (int i = 0; i < mBuffersBySize.size(); i++) {
96 | byte[] buf = mBuffersBySize.get(i);
97 | if (buf.length >= len) {
98 | mCurrentSize -= buf.length;
99 | mBuffersBySize.remove(i);
100 | mBuffersByLastUse.remove(buf);
101 | return buf;
102 | }
103 | }
104 | return new byte[len];
105 | }
106 |
107 | /**
108 | * Returns a buffer to the pool, throwing away old buffers if the pool would
109 | * exceed its allotted size.
110 | *
111 | * @param buf
112 | * the buffer to return to the pool.
113 | */
114 | public synchronized void returnBuf(byte[] buf) {
115 | if (buf == null || buf.length > mSizeLimit) {
116 | return;
117 | }
118 | mBuffersByLastUse.add(buf);
119 | int pos = Collections.binarySearch(mBuffersBySize, buf, BUF_COMPARATOR);
120 | if (pos < 0) {
121 | pos = -pos - 1;
122 | }
123 | mBuffersBySize.add(pos, buf);
124 | mCurrentSize += buf.length;
125 | trim();
126 | }
127 |
128 | /**
129 | * Removes buffers from the pool until it is under its size limit.
130 | */
131 | private synchronized void trim() {
132 | while (mCurrentSize > mSizeLimit) {
133 | byte[] buf = mBuffersByLastUse.remove(0);
134 | mBuffersBySize.remove(buf);
135 | mCurrentSize -= buf.length;
136 | }
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/XDroidRequest/src/com/xdroid/request/dispatcher/NetworkDispatcher.java:
--------------------------------------------------------------------------------
1 | package com.xdroid.request.dispatcher;
2 | import java.util.Timer;
3 | import java.util.TimerTask;
4 | import java.util.concurrent.BlockingQueue;
5 |
6 | import com.xdroid.request.RequestContext;
7 | import com.xdroid.request.base.Request;
8 | import com.xdroid.request.cache.CacheData;
9 | import com.xdroid.request.delivered.IDelivery;
10 | import com.xdroid.request.network.HttpError;
11 | import com.xdroid.request.network.HttpException;
12 | import com.xdroid.request.network.Network;
13 | import com.xdroid.request.response.NetworkResponse;
14 | import com.xdroid.request.response.Response;
15 | import com.xdroid.request.utils.CLog;
16 | import com.xdroid.request.utils.NetworkUtils;
17 |
18 | import android.annotation.TargetApi;
19 | import android.net.TrafficStats;
20 | import android.os.Build;
21 | import android.os.Process;
22 |
23 | /**
24 | * Provides a thread for performing network dispatch from a queue of requests.
25 | *@author Robin
26 | *@since 2015-05-08 12:30
27 | */
28 | public class NetworkDispatcher extends Thread {
29 | /** The queue of requests to service. */
30 | private final BlockingQueue> mQueue;
31 |
32 | private final Network mNetwork;
33 | private final IDelivery mDelivery;
34 |
35 | /** Used for telling us to die. */
36 | private volatile boolean mQuit = false;
37 |
38 |
39 | /**
40 | * Creates a new network dispatcher thread. You must call {@link #start()}
41 | * in order to begin processing.
42 | *
43 | * @param queue Queue of incoming requests for triage
44 | */
45 | public NetworkDispatcher(BlockingQueue> queue,Network network, IDelivery delivery) {
46 | mQueue = queue;
47 | mNetwork=network;
48 | mDelivery=delivery;
49 | }
50 |
51 | /**
52 | * Forces this dispatcher to quit immediately. If any requests are still in
53 | * the queue, they are not guaranteed to be processed.
54 | */
55 | public void quit() {
56 | mQuit = true;
57 | interrupt();
58 | }
59 |
60 | @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
61 | private void addTrafficStatsTag(Request> request) {
62 | // Tag the request (if API >= 14)
63 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
64 | TrafficStats.setThreadStatsTag(request.getTrafficStatsTag());
65 | }
66 | }
67 |
68 | @Override
69 | public void run() {
70 | Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
71 | while (true) {
72 | final Request> request;
73 | try {
74 | // Take a request from the queue.
75 | request = mQueue.take();
76 | } catch (InterruptedException e) {
77 | // We may have been interrupted because it was time to quit.
78 | if (mQuit) {
79 | return;
80 | }
81 | continue;
82 | }
83 |
84 | try {
85 | CLog.d("network-queue-take");
86 |
87 | // If the request was cancelled already, do not perform the
88 | // network request.
89 | if (request.isCanceled()) {
90 | request.finish();
91 | CLog.e("cache-discard-canceled-----------cacheKey:"+request.getCacheKey());
92 | continue;
93 | }
94 |
95 | addTrafficStatsTag(request);
96 |
97 | //Reset the current request has not been paid for
98 | request.resetDelivered();
99 |
100 | //prepare to request
101 | mDelivery.postRequestPrepare(request);
102 |
103 | //if set "UseCacheDataWhenTimeout"
104 | if (request.getRequestCacheConfig().isUseCacheDataWhenTimeout()) {
105 | final CacheData> cacheData = request.getCache(request.getCacheKey());
106 | if (cacheData != null) {
107 | new Timer().schedule(new TimerTask() {
108 |
109 | @Override
110 | public void run() {
111 | //hand in main thread to call "onCacheDataLoadFinish"
112 | CLog.d("Time has come , Delivered:%s ",request.hasHadResponseDelivered());
113 | if (!request.hasHadResponseDelivered()) {
114 | mDelivery.postCacheResponse(request, cacheData);
115 | }
116 |
117 | }
118 | }, request.getRequestCacheConfig().getTimeController().getTimeout());
119 | }
120 |
121 | }
122 |
123 | // Perform the network request.
124 | if (NetworkUtils.checkNet(RequestContext.getInstance())){
125 | //request.doRequest();
126 | NetworkResponse networkResponse=mNetwork.performRequest(request);
127 | /*Response response=Response.success(networkResponse.data, networkResponse.headers);*/
128 | Response> response=request.parseNetworkResponse(networkResponse);
129 | mDelivery.postRequestResponse(request, response);
130 | }else{
131 | mDelivery.postError(request, new HttpException("No Network",HttpError.ERROR_NOT_NETWORK));
132 |
133 | }
134 |
135 | }catch (HttpException e) {
136 | CLog.e( "network-http-error NetworkDispatcher Unhandled exception : "+ e.toString());
137 | mDelivery.postError(request, e);
138 | } catch (Exception e) {
139 | CLog.e( "network-http-error NetworkDispatcher Unhandled exception : "+ e.toString());
140 | mDelivery.postError(request, new HttpException(e.getMessage()));
141 | }
142 | }
143 | }
144 |
145 | }
146 |
--------------------------------------------------------------------------------
/XDroidRequest/src/com/xdroid/request/ex/RequestParams.java:
--------------------------------------------------------------------------------
1 | package com.xdroid.request.ex;
2 |
3 | import java.io.File;
4 | import java.io.UnsupportedEncodingException;
5 | import java.net.URLEncoder;
6 | import java.util.Map;
7 | import java.util.concurrent.ConcurrentHashMap;
8 |
9 | import com.xdroid.request.utils.CLog;
10 |
11 | import android.text.TextUtils;
12 |
13 | /**
14 | * Request parameters
15 | *
16 | * @author Robin
17 | * @since 2016-01-08 14:21:27
18 | *
19 | */
20 | public class RequestParams extends ConcurrentHashMap {
21 | private static final long serialVersionUID = 1L;
22 |
23 | private final Map mHeaders = new ConcurrentHashMap();
24 | private String mJsonParams;
25 |
26 | /*
27 | * =========================================================================
28 | * Constructor
29 | * =========================================================================
30 | */
31 |
32 | public RequestParams() {
33 | }
34 |
35 | public RequestParams(String cookie) {
36 | mHeaders.put("cookie", cookie);
37 | }
38 |
39 | /*
40 | * =========================================================================
41 | * Override Super
42 | * =========================================================================
43 | */
44 |
45 | @Override
46 | public Object put(String key, Object value) {
47 | if (value instanceof String || value instanceof Integer || value instanceof File) {
48 | return super.put(key, value);
49 | } else {
50 | CLog.e("Parameters must be \"String\", \"int\" and \"File\" one of the three types");
51 | return null;
52 | }
53 | }
54 |
55 | /*
56 | * =========================================================================
57 | * Public Method
58 | * =========================================================================
59 | */
60 |
61 | public void putParams(String key, int value) {
62 | this.putParams(key, value + "");
63 | }
64 |
65 | public void putParams(String key, String value) {
66 | put(key, value);
67 | }
68 |
69 | public void putParams(String key, File value) {
70 | put(key, value);
71 | }
72 |
73 | public void putParams(String jsonString) {
74 | this.mJsonParams = jsonString;
75 | }
76 |
77 | public void putHeaders(String key, int value) {
78 | this.putHeaders(key, value + "");
79 | }
80 |
81 | public void putHeaders(String key, String value) {
82 | mHeaders.put(key, value);
83 | }
84 |
85 | public String buildJsonParams() {
86 | return mJsonParams;
87 | }
88 |
89 | /**
90 | * Converts params into an application/x-www-form-urlencoded encoded string.
91 | */
92 | public StringBuilder buildParameters() {
93 | StringBuilder result = new StringBuilder();
94 | try {
95 | for (ConcurrentHashMap.Entry entry : this.entrySet()) {
96 | Object value = entry.getValue();
97 | if (value == null) {
98 | continue;
99 | }
100 | if (value instanceof String || value instanceof Integer) {
101 | result.append("&");
102 | result.append(URLEncoder.encode(entry.getKey(), "utf-8"));
103 | result.append("=");
104 | result.append(URLEncoder.encode(String.valueOf(value), "utf-8"));
105 | } else {
106 | CLog.e("Filter value,Type : %s,Value : %s", value.getClass().getName());
107 | }
108 | }
109 | return result;
110 | } catch (UnsupportedEncodingException e) {
111 | throw new RuntimeException("Encoding not supported: " + "utf-8", e);
112 | }
113 |
114 | }
115 |
116 | public Map buildParametersToMap() {
117 | Map result = new ConcurrentHashMap();
118 | for (ConcurrentHashMap.Entry entry : this.entrySet()) {
119 | Object value = entry.getValue();
120 | if (value == null) {
121 | continue;
122 | }
123 | if (value instanceof String) {
124 | result.put(entry.getKey(), (String) value);
125 | } else if (value instanceof Integer) {
126 | result.put(entry.getKey(), (Integer) value + "");
127 | }
128 | }
129 | return result;
130 | }
131 |
132 | public Map buildFileParameters() {
133 | Map fileParams = new ConcurrentHashMap();
134 | for (ConcurrentHashMap.Entry entry : this.entrySet()) {
135 | Object value = entry.getValue();
136 | if (value == null) {
137 | continue;
138 | }
139 | if (value instanceof File) {
140 | fileParams.put(entry.getKey(), (File) value);
141 | }
142 | }
143 | return fileParams;
144 | }
145 |
146 | public StringBuilder buildQueryParameters() {
147 | StringBuilder result = new StringBuilder();
148 | boolean isFirst = true;
149 | try {
150 | for (ConcurrentHashMap.Entry entry : this.entrySet()) {
151 | Object value = entry.getValue();
152 | if (value == null) {
153 | continue;
154 | }
155 | if (value instanceof String || value instanceof Integer) {
156 | if (!isFirst) {
157 | result.append("&");
158 | } else {
159 | result.append("?");
160 | isFirst = false;
161 | }
162 | result.append(URLEncoder.encode(entry.getKey(), "utf-8"));
163 | result.append("=");
164 | result.append(URLEncoder.encode(String.valueOf(value), "utf-8"));
165 | } else {
166 | CLog.e("Filter value,Type : %s,Value : %s", value.getClass().getName());
167 | }
168 |
169 | }
170 | return result;
171 | } catch (UnsupportedEncodingException e) {
172 | throw new RuntimeException("Encoding not supported: " + "utf-8", e);
173 | }
174 |
175 | }
176 |
177 | public Map buildHeaders() {
178 | return mHeaders;
179 | }
180 |
181 | public boolean hasFileInParams() {
182 | return buildFileParameters().size() > 0;
183 | }
184 |
185 | public boolean hasJsonInParams() {
186 | return !TextUtils.isEmpty(mJsonParams);
187 | }
188 |
189 | public boolean hasNameValuePairInParams() {
190 | return buildParameters().length() > 0;
191 | }
192 |
193 | @Override
194 | public String toString() {
195 | if (!TextUtils.isEmpty(mJsonParams)) {
196 | return mJsonParams;
197 | }
198 | return super.toString();
199 | }
200 |
201 | }
202 |
--------------------------------------------------------------------------------
/XDroidRequest/src/com/xdroid/request/ex/RequestBodyConstants.java:
--------------------------------------------------------------------------------
1 | package com.xdroid.request.ex;
2 |
3 | import java.io.File;
4 | import java.nio.charset.Charset;
5 | import java.util.Map;
6 |
7 | /**
8 | * Constants for Request
9 | * @author Robin
10 | * @since 2016-01-07 17:01:11
11 | *
12 | */
13 | public class RequestBodyConstants {
14 |
15 | public static final String CRLF = "\r\n";
16 | public static final String HEADER_CONTENT_TYPE = "Content-Type";
17 | public static final String HEADER_USER_AGENT = "User-Agent";
18 | public static final String HEADER_CONTENT_DISPOSITION = "Content-Disposition";
19 | public static final String HEADER_CONTENT_TRANSFER_ENCODING = "Content-Transfer-Encoding";
20 | public static final String CONTENT_TYPE_MULTIPART = "multipart/form-data; charset=%s; boundary=%s";
21 | public static final String CONTENT_TYPE_TEXT = "text/plain";
22 | public static final String BINARY = "binary";
23 | public static final String EIGHT_BIT = "8bit";
24 | public static final String FORM_DATA = "form-data; name=\"%s\"";
25 | public static final String BOUNDARY_PREFIX = "--";
26 | public static final String CONTENT_TYPE_OCTET_STREAM = "application/octet-stream";
27 | public static final String FILENAME = "filename=\"%s\"";
28 | public static final String COLON_SPACE = ": ";
29 | public static final String SEMICOLON_SPACE = "; ";
30 |
31 | public static final int CRLF_LENGTH = CRLF.getBytes().length;
32 | public static final int HEADER_CONTENT_DISPOSITION_LENGTH = HEADER_CONTENT_DISPOSITION.getBytes().length;
33 | public static final int COLON_SPACE_LENGTH = COLON_SPACE.getBytes().length;
34 | public static final int HEADER_CONTENT_TYPE_LENGTH = HEADER_CONTENT_TYPE.getBytes().length;
35 | public static final int CONTENT_TYPE_OCTET_STREAM_LENGTH = CONTENT_TYPE_OCTET_STREAM.getBytes().length;
36 | public static final int HEADER_CONTENT_TRANSFER_ENCODING_LENGTH = HEADER_CONTENT_TRANSFER_ENCODING.getBytes().length;
37 | public static final int BINARY_LENGTH = BINARY.getBytes().length;
38 | public static final int BOUNDARY_PREFIX_LENGTH = BOUNDARY_PREFIX.getBytes().length;
39 |
40 | public static final Charset ASCII = Charset.forName("US-ASCII");
41 |
42 | public static final byte[] CRLF_BYTES = getAsciiBytes(CRLF);
43 |
44 | /*public static int getContentLengthForMultipartRequest(String boundary, Map multipartParams, Map filesToUpload) {
45 | final int boundaryLength = boundary.getBytes().length;
46 | int contentLength = 0;
47 | for (String key : multipartParams.keySet()) {
48 | MultiPartRequest.MultiPartValue param = multipartParams.get(key);
49 | int size = boundaryLength +
50 | CRLF_LENGTH + HEADER_CONTENT_DISPOSITION_LENGTH + COLON_SPACE_LENGTH + String.format(FORM_DATA, key).getBytes().length +
51 | CRLF_LENGTH + HEADER_CONTENT_TYPE_LENGTH + COLON_SPACE_LENGTH + param.contentType.getBytes().length +
52 | CRLF_LENGTH + CRLF_LENGTH + param.value.getBytes().length + CRLF_LENGTH;
53 |
54 | contentLength += size;
55 | }
56 |
57 | for (String key : filesToUpload.keySet()) {
58 | File file = new File(filesToUpload.get(key));
59 | int size = boundaryLength +
60 | CRLF_LENGTH + HEADER_CONTENT_DISPOSITION_LENGTH + COLON_SPACE_LENGTH + String.format(FORM_DATA + SEMICOLON_SPACE + FILENAME, key, file.getName()).getBytes().length +
61 | CRLF_LENGTH + HEADER_CONTENT_TYPE_LENGTH + COLON_SPACE_LENGTH + CONTENT_TYPE_OCTET_STREAM_LENGTH +
62 | CRLF_LENGTH + HEADER_CONTENT_TRANSFER_ENCODING_LENGTH + COLON_SPACE_LENGTH + BINARY_LENGTH + CRLF_LENGTH + CRLF_LENGTH;
63 |
64 | size += (int) file.length();
65 | size += CRLF_LENGTH;
66 | contentLength += size;
67 | }
68 |
69 | int size = boundaryLength + BOUNDARY_PREFIX_LENGTH + CRLF_LENGTH;
70 | contentLength += size;
71 | return contentLength;
72 | }*/
73 |
74 | public static int getContentLength(String boundary, Map, ?> requestParams) {
75 | final int boundaryLength = boundary.getBytes().length;
76 | int contentLength = 0;
77 | for (Object key : requestParams.keySet()) {
78 | Object value = requestParams.get(key);
79 | if (value instanceof File) {
80 | File fileValue = (File) value;
81 | int size = boundaryLength +
82 | CRLF_LENGTH + HEADER_CONTENT_DISPOSITION_LENGTH + COLON_SPACE_LENGTH + String.format(FORM_DATA + SEMICOLON_SPACE + FILENAME, key, fileValue.getName()).getBytes().length +
83 | CRLF_LENGTH + HEADER_CONTENT_TYPE_LENGTH + COLON_SPACE_LENGTH + CONTENT_TYPE_OCTET_STREAM_LENGTH +
84 | CRLF_LENGTH + HEADER_CONTENT_TRANSFER_ENCODING_LENGTH + COLON_SPACE_LENGTH + BINARY_LENGTH + CRLF_LENGTH + CRLF_LENGTH;
85 |
86 | size += (int) fileValue.length();
87 | size += CRLF_LENGTH;
88 | contentLength += size;
89 | }else {
90 | String stringValue = "";
91 | if (value instanceof String) {
92 | stringValue = (String) value;
93 | }else if (value instanceof Integer) {
94 | stringValue = (Integer) value +"";
95 | }
96 | int size = boundaryLength +
97 | CRLF_LENGTH + HEADER_CONTENT_DISPOSITION_LENGTH + COLON_SPACE_LENGTH + String.format(FORM_DATA, key).getBytes().length +
98 | CRLF_LENGTH + HEADER_CONTENT_TYPE_LENGTH + COLON_SPACE_LENGTH +
99 | // param.contentType.getBytes().length +
100 | CRLF_LENGTH + CRLF_LENGTH + stringValue.getBytes().length + CRLF_LENGTH;
101 |
102 | contentLength += size;
103 | }
104 | }
105 |
106 | int size = boundaryLength + BOUNDARY_PREFIX_LENGTH + CRLF_LENGTH;
107 | contentLength += size;
108 | return contentLength;
109 | }
110 |
111 | public static byte[] getAsciiBytes(final String data) {
112 | notNull(data, "Input");
113 | return data.getBytes(ASCII);
114 | }
115 |
116 | private static T notNull(final T argument, final String name) {
117 | if (argument == null) {
118 | throw new IllegalArgumentException(name + " may not be null");
119 | }
120 | return argument;
121 | }
122 |
123 |
124 | }
125 |
--------------------------------------------------------------------------------
/XDroidRequest/src/com/xdroid/request/dispatcher/CacheDispatcher.java:
--------------------------------------------------------------------------------
1 | package com.xdroid.request.dispatcher;
2 |
3 | import java.util.concurrent.BlockingQueue;
4 |
5 | import com.xdroid.request.base.Request;
6 | import com.xdroid.request.cache.CacheData;
7 | import com.xdroid.request.delivered.IDelivery;
8 | import com.xdroid.request.utils.CLog;
9 |
10 | import android.os.Process;
11 |
12 | /**
13 | * Provides a thread for performing cache triage on a queue of requests.
14 | *@author Robin
15 | *@since 2015-05-08 16:20:45
16 | */
17 | public class CacheDispatcher extends Thread {
18 |
19 | /** The queue of requests coming in for triage. */
20 | private final BlockingQueue> mCacheQueue;
21 |
22 | /** The queue of requests going out to the network. */
23 | private final BlockingQueue> mNetworkQueue;
24 |
25 | /** Used for telling us to die. */
26 | private volatile boolean mQuit = false;
27 |
28 | private final IDelivery mDelivery;
29 |
30 | /* @SuppressLint("HandlerLeak")
31 | private Handler handler=new Handler(){
32 | @SuppressWarnings("unchecked")
33 | public void handleMessage(Message msg) {
34 | HashMap hashMap=(HashMap) msg.obj;
35 | CacheData cacheData = (CacheData) hashMap.get("data");
36 | Request> request=(Request>) hashMap.get("request");
37 |
38 | //Reset the current request has not been paid for
39 | request.resetDelivered();
40 |
41 | request.onCacheDataLoadFinish(cacheData);
42 | };
43 | };*/
44 |
45 | /**
46 | * Creates a new cache triage dispatcher thread. You must call {@link #start()}
47 | * in order to begin processing.
48 | *
49 | * @param cacheQueue Queue of incoming requests for triage
50 | * @param networkQueue Queue to post requests that require network to
51 | */
52 | public CacheDispatcher(BlockingQueue> cacheQueue, BlockingQueue> networkQueue,IDelivery delivery) {
53 | mCacheQueue = cacheQueue;
54 | mNetworkQueue = networkQueue;
55 | mDelivery=delivery;
56 | }
57 |
58 | /**
59 | * Forces this dispatcher to quit immediately. If any requests are still in
60 | * the queue, they are not guaranteed to be processed.
61 | */
62 | public void quit() {
63 | mQuit = true;
64 | interrupt();
65 | }
66 |
67 | @Override
68 | public void run() {
69 | CLog.v("start new dispatcher");
70 | Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
71 |
72 | while (true) {
73 | try {
74 | // Get a request from the cache triage queue, blocking until
75 | // at least one is available.
76 | final Request> request = mCacheQueue.take();
77 | CLog.d("cache-queue-take");
78 |
79 | // If the request has been canceled, don't bother dispatching it.
80 | if (request.isCanceled()) {
81 | request.finish();
82 | CLog.e( "cache-discard-canceled-----------cacheKey:"+request.getCacheKey());
83 | continue;
84 | }
85 | // use the cache data always
86 | if (request.getRequestCacheConfig().isUseCacheDataAnyway()) {
87 | CacheData> cacheData = request.getCache(request.getCacheKey());
88 | // Attempt to retrieve this item from cache.
89 | if (cacheData == null) {
90 | CLog.d("cache-miss");
91 | // Cache miss; send off to the network dispatcher.
92 | mNetworkQueue.put(request);
93 | continue;
94 | }
95 |
96 | // We have a cache hit; parse its data for delivery back to the request.
97 | CLog.d("cache-hit");
98 |
99 | //hand in main thread to call "onCacheDataLoadFinish"
100 | /*Message msg = handler.obtainMessage();
101 | HashMap hashMap=new HashMap<>();
102 | hashMap.put("data", cacheData);
103 | hashMap.put("request", request);
104 | msg.obj = hashMap;
105 | handler.sendMessage(msg);*/
106 |
107 | mDelivery.postCacheResponse(request, cacheData);
108 |
109 | mNetworkQueue.put(request);
110 |
111 | continue;
112 | }
113 |
114 | // use the cache data when the cache data is not expired
115 | if (request.getRequestCacheConfig().isUseCacheDataWhenUnexpired()) {
116 | CacheData> cacheData = request.getCache(request.getCacheKey());
117 | // Attempt to retrieve this item from cache.
118 | if ( cacheData == null) {
119 | CLog.d("cache-miss");
120 | // Cache miss; send off to the network dispatcher.
121 | mNetworkQueue.put(request);
122 | continue;
123 | }
124 |
125 | // If it is completely expired, just send it to the network.
126 | if (cacheData.isExpired()) {
127 | CLog.d("cache-hit-expired");
128 | //request.setCacheEntry(entry);
129 | mNetworkQueue.put(request);
130 | continue;
131 | }
132 |
133 | // We have a cache hit; parse its data for delivery back to the request.
134 | CLog.d("cache-hit");
135 |
136 | //hand in main thread to call "onCacheDataLoadFinish"
137 | /*Message msg = handler.obtainMessage();
138 | HashMap hashMap=new HashMap<>();
139 | hashMap.put("data", cacheData);
140 | hashMap.put("request", request);
141 | msg.obj = hashMap;
142 | handler.sendMessage(msg);*/
143 |
144 | mDelivery.postCacheResponse(request, cacheData);
145 |
146 | }else {
147 | mNetworkQueue.put(request);
148 | }
149 |
150 |
151 | } catch (InterruptedException e) {
152 | // We may have been interrupted because it was time to quit.
153 | if (mQuit) {
154 | return;
155 | }
156 | continue;
157 | }
158 | }
159 | }
160 | }
161 |
--------------------------------------------------------------------------------
/XDroidRequest/src/com/xdroid/request/network/HurlStack.java:
--------------------------------------------------------------------------------
1 | package com.xdroid.request.network;
2 |
3 | import static com.xdroid.request.ex.RequestBodyConstants.HEADER_USER_AGENT;
4 |
5 | import java.io.IOException;
6 | import java.io.InputStream;
7 | import java.net.HttpURLConnection;
8 | import java.net.URL;
9 | import java.util.HashMap;
10 | import java.util.List;
11 | import java.util.Map;
12 | import java.util.Map.Entry;
13 |
14 | import javax.net.ssl.HttpsURLConnection;
15 | import javax.net.ssl.SSLSocketFactory;
16 |
17 | import com.xdroid.request.base.Request;
18 | import com.xdroid.request.config.HttpMethod;
19 |
20 | import android.text.TextUtils;
21 |
22 | /**
23 | * HttpUrlConnection request body
24 | *
25 | * @author Robin
26 | * @since 2015-07-02 16:40:21
27 | */
28 | public class HurlStack implements HttpStack {
29 |
30 | private final UrlRewriter mUrlRewriter;
31 | private final SSLSocketFactory mSslSocketFactory;
32 | private String mUserAgent;
33 |
34 | public interface UrlRewriter {
35 | /**
36 | * Rewrite the URL for the request.
37 | */
38 | public String rewriteUrl(String originalUrl);
39 | }
40 |
41 | public HurlStack() {
42 | this(null);
43 | }
44 |
45 | public HurlStack(UrlRewriter urlRewriter) {
46 | this(urlRewriter, null);
47 | }
48 |
49 | public HurlStack(UrlRewriter urlRewriter, SSLSocketFactory sslSocketFactory) {
50 | mUrlRewriter = urlRewriter;
51 | mSslSocketFactory = sslSocketFactory;
52 | }
53 |
54 | /**
55 | * @param urlRewriter
56 | * Rewriter to use for request URLs
57 | * @param sslSocketFactory
58 | * SSL factory to use for HTTPS connections
59 | * @param userAgent
60 | * User Agent for HTTPS connections
61 | */
62 | public HurlStack(UrlRewriter urlRewriter, SSLSocketFactory sslSocketFactory, String userAgent) {
63 |
64 | mUrlRewriter = urlRewriter;
65 | mSslSocketFactory = sslSocketFactory;
66 | mUserAgent = userAgent;
67 | }
68 |
69 | @Override
70 | public HttpResponse performRequest(Request> request, Map additionalHeaders) throws IOException {
71 | String url = request.getUrl();
72 | HashMap map = new HashMap();
73 | map.putAll(request.getHeaders());
74 | map.putAll(additionalHeaders);
75 |
76 | if (mUrlRewriter != null) {
77 | String rewritten = mUrlRewriter.rewriteUrl(url);
78 | if (rewritten == null) {
79 | throw new IOException("URL blocked by rewriter: " + url);
80 | }
81 | url = rewritten;
82 | }
83 | URL parsedUrl = new URL(url);
84 | HttpURLConnection connection = openConnection(parsedUrl, request);
85 |
86 | if (!TextUtils.isEmpty(mUserAgent)) {
87 | connection.setRequestProperty(HEADER_USER_AGENT, mUserAgent);
88 | }
89 |
90 | for (String headerName : map.keySet()) {
91 | connection.addRequestProperty(headerName, map.get(headerName));
92 | }
93 |
94 | setConnectionParametersForRequest(connection, request);
95 |
96 | HttpResponse response = responseFromConnection(connection);
97 | return response;
98 | }
99 |
100 | private HttpURLConnection openConnection(URL url, Request> request) throws IOException {
101 | HttpURLConnection connection = (HttpURLConnection) url.openConnection();
102 |
103 | // Timeout is actually the timeout of the retry strategy
104 | int timeoutMs = request.getRetryPolicy().getCurrentTimeout();
105 | connection.setConnectTimeout(timeoutMs);
106 | connection.setReadTimeout(timeoutMs);
107 | connection.setUseCaches(false);
108 | connection.setDoInput(true);
109 |
110 | // getContentLength()
111 | // 为“-1”,在2.2版本以上开启了GZIP压缩,导致长度始终为-1,使用如下一行代码禁止GZIP压缩,
112 | // 但是不推荐,建议与服务器端协商,在请求头中添加content length.
113 | // connection .setRequestProperty("Accept-Encoding", "identity");
114 |
115 | // use caller-provided custom SslSocketFactory, if any, for HTTPS
116 | if ("https".equals(url.getProtocol())) {
117 | if (mSslSocketFactory != null) {
118 | ((HttpsURLConnection) connection).setSSLSocketFactory(mSslSocketFactory);
119 | } else {
120 | // Trust all certificates
121 | HTTPSTrustManager.allowAllSSL();
122 | }
123 | }
124 |
125 | return connection;
126 | }
127 |
128 | /**
129 | * Create HttpResponse from a given HttpUrlConnection
130 | */
131 | private HttpResponse responseFromConnection(HttpURLConnection connection) throws IOException {
132 | HttpResponse response = new HttpResponse();
133 | int responseCode = connection.getResponseCode();
134 | if (responseCode == -1) {
135 | throw new IOException("Could not retrieve response code from HttpUrlConnection.");
136 | }
137 | response.setResponseCode(responseCode);
138 | response.setResponseMessage(connection.getResponseMessage());
139 | // contentStream
140 | InputStream inputStream;
141 | try {
142 | inputStream = connection.getInputStream();
143 | } catch (IOException ioe) {
144 | inputStream = connection.getErrorStream();
145 | }
146 | response.setContentStream(inputStream);
147 |
148 | response.setContentLength(connection.getContentLength());
149 | response.setContentEncoding(connection.getContentEncoding());
150 | response.setContentType(connection.getContentType());
151 | // header
152 | Map headerMap = new HashMap();
153 | for (Entry> header : connection.getHeaderFields().entrySet()) {
154 | if (header.getKey() != null) {
155 | String value = "";
156 | for (String v : header.getValue()) {
157 | value += (v + "; ");
158 | }
159 | headerMap.put(header.getKey(), value);
160 | response.setHeaders(headerMap);
161 | }
162 | }
163 | return response;
164 | }
165 |
166 |
167 | private static void setConnectionParametersForRequest(HttpURLConnection connection, Request> request)
168 | throws IOException {
169 | switch (request.getHttpMethod()) {
170 | case HttpMethod.GET:
171 | connection.setRequestMethod("GET");
172 | break;
173 | case HttpMethod.DELETE:
174 | connection.setRequestMethod("DELETE");
175 | break;
176 | case HttpMethod.POST:
177 | connection.setRequestMethod("POST");
178 | addBodyIfExists(connection, request);
179 | break;
180 | case HttpMethod.PUT:
181 | connection.setRequestMethod("PUT");
182 | addBodyIfExists(connection, request);
183 | break;
184 | case HttpMethod.HEAD:
185 | connection.setRequestMethod("HEAD");
186 | break;
187 | case HttpMethod.OPTIONS:
188 | connection.setRequestMethod("OPTIONS");
189 | break;
190 | case HttpMethod.TRACE:
191 | connection.setRequestMethod("TRACE");
192 | break;
193 | case HttpMethod.PATCH:
194 | // connection.setRequestMethod("PATCH");
195 | // If server doesnt support patch uncomment this
196 | connection.setRequestMethod("POST");
197 | connection.setRequestProperty("X-HTTP-Method-Override", "PATCH");
198 | addBodyIfExists(connection, request);
199 | break;
200 | default:
201 | throw new IllegalStateException("Unknown method type.");
202 | }
203 | }
204 |
205 | /**
206 | * If there is body then add
207 | */
208 | private static void addBodyIfExists(HttpURLConnection connection, Request> request) throws IOException {
209 | request.buildBody(connection);
210 | }
211 | }
212 |
--------------------------------------------------------------------------------
/XDroidRequest/src/com/xdroid/request/config/RequestCacheConfig.java:
--------------------------------------------------------------------------------
1 | package com.xdroid.request.config;
2 |
3 | /**
4 | * cache used configuration
5 | *
6 | * @author Robin
7 | * @since 2015-05-07 13:06:54
8 | */
9 | public class RequestCacheConfig {
10 |
11 | /** Default expiration time */
12 | public static final long DEFAULT_EXPIRATION_TIME=30*1000;
13 |
14 | /** Default timeout */
15 | public static final long DEFAULT_TIMEOUT=20*1000;
16 |
17 | /**
18 | * whether allow cache data
19 | */
20 | private boolean shouldCache;
21 |
22 | /**
23 | * use cache data first ,no matter the cache have expired ,then update cache
24 | * when request finish
25 | */
26 | private boolean useCacheDataAnyway;
27 |
28 | /**
29 | * use cache data if request failed
30 | */
31 | private boolean useCacheDataWhenRequestFailed;
32 |
33 | /**
34 | * use cache data if the cache data is not expired
35 | */
36 | private boolean useCacheDataWhenUnexpired;
37 |
38 | /**
39 | * use cache data if timeout
40 | */
41 | private boolean useCacheDataWhenTimeout;
42 |
43 | /**
44 | * Retry if request failed
45 | */
46 | private boolean retryWhenRequestFailed;
47 |
48 | /**
49 | * Set cache never expired.
50 | */
51 | private boolean isNeverExpired;
52 |
53 | /**
54 | * control expirationtime and timeout
55 | */
56 | private TimeController timeController;
57 |
58 | public RequestCacheConfig() {
59 | super();
60 | }
61 |
62 | public RequestCacheConfig(boolean shouldCache, boolean useCacheDataAnyway, boolean useCacheDataWhenRequestFailed,
63 | boolean useCacheDataWhenUnexpired, boolean useCacheDataWhenTimeout, boolean retryWhenRequestFailed,
64 | boolean isNeverExpired,TimeController timeController) {
65 | super();
66 | this.shouldCache = shouldCache;
67 | this.useCacheDataAnyway = useCacheDataAnyway;
68 | this.useCacheDataWhenRequestFailed = useCacheDataWhenRequestFailed;
69 | this.useCacheDataWhenUnexpired = useCacheDataWhenUnexpired;
70 | this.useCacheDataWhenTimeout = useCacheDataWhenTimeout;
71 | this.retryWhenRequestFailed = retryWhenRequestFailed;
72 | this.isNeverExpired = isNeverExpired;
73 | this.timeController = timeController;
74 | }
75 |
76 | public boolean isShouldCache() {
77 | return shouldCache;
78 | }
79 |
80 | public RequestCacheConfig setShouldCache(boolean shouldCache) {
81 | this.shouldCache = shouldCache;
82 | return this;
83 | }
84 |
85 | public boolean isUseCacheDataAnyway() {
86 | return useCacheDataAnyway;
87 | }
88 |
89 | public RequestCacheConfig setUseCacheDataAnyway(boolean useCacheDataAnyway) {
90 | this.useCacheDataAnyway = useCacheDataAnyway;
91 | return this;
92 | }
93 |
94 | public boolean isUseCacheDataWhenRequestFailed() {
95 | return useCacheDataWhenRequestFailed;
96 | }
97 |
98 | public RequestCacheConfig setUseCacheDataWhenRequestFailed(boolean useCacheDataWhenRequestFailed) {
99 | this.useCacheDataWhenRequestFailed = useCacheDataWhenRequestFailed;
100 | return this;
101 | }
102 |
103 | public boolean isUseCacheDataWhenUnexpired() {
104 | return useCacheDataWhenUnexpired;
105 | }
106 |
107 | public RequestCacheConfig setUseCacheDataWhenUnexpired(boolean useCacheDataWhenUnexpired) {
108 | this.useCacheDataWhenUnexpired = useCacheDataWhenUnexpired;
109 | return this;
110 | }
111 |
112 | public boolean isUseCacheDataWhenTimeout() {
113 | return useCacheDataWhenTimeout;
114 | }
115 |
116 | public RequestCacheConfig setUseCacheDataWhenTimeout(boolean useCacheDataWhenTimeout) {
117 | this.useCacheDataWhenTimeout = useCacheDataWhenTimeout;
118 | return this;
119 | }
120 |
121 | public boolean isRetryWhenRequestFailed() {
122 | return retryWhenRequestFailed;
123 | }
124 |
125 | public RequestCacheConfig setRetryWhenRequestFailed(boolean retryWhenRequestFailed) {
126 | this.retryWhenRequestFailed = retryWhenRequestFailed;
127 | return this;
128 | }
129 |
130 | public boolean isNeverExpired() {
131 | return isNeverExpired;
132 | }
133 |
134 | public RequestCacheConfig setNeverExpired(boolean isNeverExpired) {
135 | this.isNeverExpired = isNeverExpired;
136 | return this;
137 | }
138 |
139 | public TimeController getTimeController() {
140 | return timeController;
141 | }
142 |
143 | public RequestCacheConfig setTimeController(TimeController timeController) {
144 | this.timeController = timeController;
145 | return this;
146 | }
147 |
148 | @Override
149 | public String toString() {
150 | return "RequestCacheConfig [shouldCache=" + shouldCache + ", useCacheDataAnyway=" + useCacheDataAnyway
151 | + ", useCacheDataWhenRequestFailed=" + useCacheDataWhenRequestFailed + ", useCacheDataWhenUnexpired="
152 | + useCacheDataWhenUnexpired + ", useCacheDataWhenTimeout=" + useCacheDataWhenTimeout
153 | + ", retryWhenRequestFailed=" + retryWhenRequestFailed + ", isNeverExpired=" + isNeverExpired
154 | + ", timeController=" + timeController + "]";
155 | }
156 |
157 | /**
158 | * create a default cache configuration when cacheConfig is null
159 | * @return
160 | */
161 | public static RequestCacheConfig buildDefaultCacheConfig() {
162 | RequestCacheConfig cacheConfig=new RequestCacheConfig();
163 | cacheConfig.setShouldCache(true);
164 | cacheConfig.setUseCacheDataAnyway(false);
165 | cacheConfig.setUseCacheDataWhenRequestFailed(true);
166 | cacheConfig.setUseCacheDataWhenTimeout(false);
167 | cacheConfig.setUseCacheDataWhenUnexpired(true);
168 | cacheConfig.setRetryWhenRequestFailed(true);
169 | cacheConfig.setNeverExpired(false);
170 |
171 | TimeController timeController=new TimeController();
172 | timeController.setExpirationTime(DEFAULT_EXPIRATION_TIME);
173 | timeController.setTimeout(DEFAULT_TIMEOUT);
174 | cacheConfig.setTimeController(timeController);
175 |
176 | return cacheConfig;
177 | }
178 |
179 | public static RequestCacheConfig buildNoCacheConfig() {
180 | RequestCacheConfig cacheConfig=new RequestCacheConfig();
181 | cacheConfig.setShouldCache(false);
182 | cacheConfig.setUseCacheDataAnyway(false);
183 | cacheConfig.setUseCacheDataWhenRequestFailed(false);
184 | cacheConfig.setUseCacheDataWhenTimeout(false);
185 | cacheConfig.setUseCacheDataWhenUnexpired(false);
186 | cacheConfig.setRetryWhenRequestFailed(false);
187 | cacheConfig.setNeverExpired(false);
188 |
189 | TimeController timeController=new TimeController();
190 | timeController.setExpirationTime(0);
191 | timeController.setTimeout(DEFAULT_TIMEOUT);
192 | cacheConfig.setTimeController(timeController);
193 |
194 | return cacheConfig;
195 | }
196 |
197 | public static RequestCacheConfig buildImageCacheConfig() {
198 | RequestCacheConfig cacheConfig=new RequestCacheConfig();
199 | cacheConfig.setShouldCache(true);
200 | cacheConfig.setUseCacheDataAnyway(false);
201 | cacheConfig.setUseCacheDataWhenRequestFailed(false);
202 | cacheConfig.setUseCacheDataWhenTimeout(false);
203 | cacheConfig.setUseCacheDataWhenUnexpired(true);
204 | cacheConfig.setRetryWhenRequestFailed(true);
205 | cacheConfig.setNeverExpired(true);
206 |
207 | TimeController timeController=new TimeController();
208 | timeController.setTimeout(DEFAULT_TIMEOUT);
209 | cacheConfig.setTimeController(timeController);
210 |
211 | return cacheConfig;
212 | }
213 | }
214 |
--------------------------------------------------------------------------------
/XDroidRequestExample/src/com/xdroid/request/example/log/LogProcessor.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2009 Michael Novak
3 | *
4 | * This program is free software; you can redistribute it and/or
5 | * modify it under the terms of the GNU General Public License
6 | * as published by the Free Software Foundation; either version 2
7 | * of the License, or (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 |
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program; if not, write to the Free Software
16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 | */
18 | package com.xdroid.request.example.log;
19 |
20 | import android.annotation.SuppressLint;
21 | import android.app.Service;
22 | import android.content.Intent;
23 | import android.os.IBinder;
24 | import android.os.Handler;
25 | import android.os.Message;
26 | import android.util.Log;
27 |
28 | import java.io.BufferedReader;
29 | import java.io.File;
30 | import java.io.FileWriter;
31 | import java.io.IOException;
32 | import java.io.InputStreamReader;
33 | import java.util.Vector;
34 |
35 | public class LogProcessor extends Service {
36 |
37 | private static Handler mHandler;
38 | private String mFile;
39 | private String mBuffer = "main";
40 | private Vector mScrollback;
41 | private int mLines;
42 | private int mType;
43 | private String mFilterTag;
44 | private volatile boolean threadKill = false;
45 | private volatile boolean mStatus = false;
46 | public int MAX_LINES = 250;
47 | public static final int MSG_READ_FAIL = 1;
48 | public static final int MSG_LOG_FAIL = 2;
49 | public static final int MSG_NEW_LINE = 3;
50 | public static final int MSG_RESET_LOG = 4;
51 | public static final int MSG_LOG_SAVE = 5;
52 |
53 | @Override
54 | public void onCreate() {
55 | super.onCreate();
56 | }
57 |
58 | @SuppressWarnings("deprecation")
59 | @Override
60 | public void onStart(Intent intent, int startId) {
61 | super.onStart(intent, startId);
62 | Log.i("Logger", "Logger Service has hit the onStart method.");
63 | }
64 |
65 | Runnable worker = new Runnable() {
66 | public void run() {
67 | runLog();
68 | mStatus = true;
69 | Log.d("Logger", "status... " + mStatus);
70 | return;
71 | }
72 | };
73 |
74 | private void runLog() {
75 | Process process = null;
76 |
77 | try {
78 |
79 | if (mType == 0) {
80 | process = Runtime.getRuntime().exec("/system/bin/logcat -b " + mBuffer);
81 | } else if (mType == 1) {
82 | process = Runtime.getRuntime().exec("dmesg -s 1000000");
83 | }
84 |
85 | } catch (IOException e) {
86 | communicate(MSG_LOG_FAIL);
87 | }
88 |
89 | BufferedReader reader = null;
90 |
91 | try {
92 | reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
93 |
94 | String line;
95 |
96 | while (!killRequested()) {
97 | line = reader.readLine();
98 |
99 | logLine(line);
100 |
101 | if (mLines == MAX_LINES) {
102 | mScrollback.removeElementAt(0);
103 | }
104 |
105 | mScrollback.add(line);
106 | mLines++;
107 | }
108 |
109 | Log.i("Logger", "Prepping thread for termination");
110 | reader.close();
111 | process.destroy();
112 | process = null;
113 | reader = null;
114 | mScrollback.removeAllElements();
115 | mScrollback = null;
116 | mLines = 0;
117 | } catch (IOException e) {
118 | communicate(MSG_READ_FAIL);
119 | }
120 |
121 | Log.d("Logger", "Exiting thread...");
122 | return;
123 | }
124 |
125 | private synchronized void requestKill() {
126 | threadKill = true;
127 | }
128 |
129 | private synchronized boolean killRequested() {
130 | return threadKill;
131 | }
132 |
133 | private void communicate(int msg) {
134 | Message.obtain(mHandler, msg, "error").sendToTarget();
135 | }
136 |
137 | private void logLine(String line) {
138 | Message.obtain(mHandler, MSG_NEW_LINE, line).sendToTarget();
139 | }
140 |
141 | public static void setHandler(Handler handler) {
142 | mHandler = handler;
143 | }
144 |
145 | public IBinder onBind(Intent intent) {
146 | return mBinder;
147 | }
148 |
149 | @Override
150 | public boolean onUnbind(Intent intent) {
151 | requestKill();
152 | stopSelf();
153 |
154 | return false;
155 | }
156 |
157 | private final ILogProcessor.Stub mBinder = new ILogProcessor.Stub() {
158 | @SuppressLint("DefaultLocale")
159 | public void reset(String buffer) {
160 | requestKill();
161 |
162 | while (!mStatus) {
163 | try {
164 | Log.d("Logger", "waiting...");
165 | } catch (Exception e) {
166 | Log.d("Logger", "Woot! obj has been interrupted!");
167 | }
168 | }
169 |
170 | threadKill = false;
171 | mBuffer = buffer.toLowerCase();
172 | mLines = 0;
173 | mScrollback = new Vector();
174 | Thread thr = new Thread(worker);
175 | thr.start();
176 | }
177 |
178 | public void run(int type) {
179 | mType = type;
180 | mLines = 0;
181 | mScrollback = new Vector();
182 | Thread thr = new Thread(worker);
183 | thr.start();
184 | }
185 |
186 | public void restart(int type) {
187 | requestKill();
188 |
189 | while(!mStatus) {
190 | try {
191 | Log.d("Logger", "waiting...");
192 | } catch (Exception e) {
193 | Log.d("Logger", "Woot! we have an exception");
194 | }
195 | }
196 |
197 | threadKill = false;
198 | run(type);
199 | }
200 |
201 | public void stop() {
202 | Log.i("Logger", "stop() method called in service.");
203 | requestKill();
204 | stopSelf();
205 | }
206 |
207 | public void write(String file, String tag) {
208 | mFilterTag = tag;
209 | mFile = file;
210 | Thread thr = new Thread(writer);
211 | thr.start();
212 | }
213 | };
214 |
215 | Runnable writer = new Runnable() {
216 | public void run() {
217 | writeLog();
218 | return;
219 | }
220 | };
221 |
222 | @SuppressLint({ "DefaultLocale", "SdCardPath" })
223 | private void writeLog() {
224 |
225 | try {
226 | File f = new File("/sdcard/" + mFile);
227 | FileWriter w = new FileWriter(f);
228 |
229 | for (int i = 0; i < mScrollback.size(); i++) {
230 | String line = mScrollback.elementAt(i);
231 |
232 | if (!mFilterTag.equals("")) {
233 | String tag = line.substring(2, line.indexOf("("));
234 |
235 | if (mFilterTag.toLowerCase().equals(tag.toLowerCase().trim())) {
236 | w.write(line + "\n");
237 | }
238 | } else {
239 | w.write(mScrollback.elementAt(i) + "\n");
240 | }
241 |
242 | i++;
243 | }
244 |
245 | if (!mFile.equals("tmp.log")) {
246 | Message.obtain(mHandler, MSG_LOG_SAVE, "saved").sendToTarget();
247 | } else {
248 | Message.obtain(mHandler, MSG_LOG_SAVE, "attachment").sendToTarget();
249 | }
250 |
251 | w.close();
252 | f = null;
253 | } catch (Exception e) {
254 | Log.e("Logger", "Error writing the log to a file. Exception: " + e.toString());
255 | Message.obtain(mHandler, MSG_LOG_SAVE, "error").sendToTarget();
256 | }
257 |
258 | return;
259 | }
260 |
261 | }
262 |
--------------------------------------------------------------------------------
/XDroidRequest/src/com/xdroid/request/ex/MultipartRequest.java:
--------------------------------------------------------------------------------
1 | package com.xdroid.request.ex;
2 |
3 | import static com.xdroid.request.ex.RequestBodyConstants.*;
4 |
5 | import java.io.BufferedInputStream;
6 | import java.io.File;
7 | import java.io.FileInputStream;
8 | import java.io.FileNotFoundException;
9 | import java.io.IOException;
10 | import java.io.OutputStream;
11 | import java.io.OutputStreamWriter;
12 | import java.io.PrintWriter;
13 | import java.net.HttpURLConnection;
14 | import java.util.Map;
15 |
16 | import com.xdroid.request.base.Request;
17 | import com.xdroid.request.config.Priority;
18 | import com.xdroid.request.config.RequestCacheConfig;
19 | import com.xdroid.request.interfaces.OnRequestListener;
20 | import com.xdroid.request.retry.DefaultRetryPolicyImpl;
21 | import com.xdroid.request.utils.CLog;
22 |
23 | /**
24 | * Can submit key/value pair, files, key/value pair and files, JSON,
25 | * If the request parameter contains a JSON parameters, send JSON parameters,
26 | * this time even contain key/value pair or file parameter will not be sent
27 | * @author Robin
28 | * @since 2016-01-07 18:53:19
29 | *
30 | * @param
31 | */
32 | public abstract class MultipartRequest extends Request{
33 |
34 | private static final String PROTOCOL_CHARSET = "utf-8";
35 | public static final int TIMEOUT_MS = 2500;
36 | private boolean isFixedStreamingMode;
37 |
38 | private RequestParams mRequestParams;
39 |
40 | public MultipartRequest() {
41 | super();
42 | setPriority(Priority.NORMAL);
43 | setRetryPolicy(new DefaultRetryPolicyImpl(TIMEOUT_MS, DefaultRetryPolicyImpl.DEFAULT_MAX_RETRIES, DefaultRetryPolicyImpl.DEFAULT_BACKOFF_MULT));
44 |
45 | mRequestParams = new RequestParams();
46 | }
47 |
48 | public MultipartRequest(RequestCacheConfig cacheConfig, String url, String cacheKey, OnRequestListener onRequestListener) {
49 | super(cacheConfig, url, cacheKey, onRequestListener);
50 |
51 | setPriority(Priority.NORMAL);
52 | setRetryPolicy(new DefaultRetryPolicyImpl(TIMEOUT_MS, DefaultRetryPolicyImpl.DEFAULT_MAX_RETRIES, DefaultRetryPolicyImpl.DEFAULT_BACKOFF_MULT));
53 | setUrl(url);
54 |
55 | mRequestParams = new RequestParams();
56 | }
57 |
58 | /*======================================================
59 | * Override Super
60 | *======================================================
61 | */
62 |
63 | @Override
64 | public Map getHeaders() {
65 | return mRequestParams.buildHeaders();
66 | }
67 |
68 | @Override
69 | public String getParams() {
70 | return mRequestParams.toString();
71 | }
72 |
73 | public String buildBodyContentType(int curTime) {
74 | if (mRequestParams.hasJsonInParams()) {
75 | return String.format( "application/json; charset=%s", "utf-8");
76 | }
77 |
78 | return String.format(CONTENT_TYPE_MULTIPART, PROTOCOL_CHARSET, curTime);
79 | }
80 |
81 | @Override
82 | public void buildBody(HttpURLConnection connection) {
83 | connection.setDoOutput(true);
84 | final String charset =PROTOCOL_CHARSET;
85 | final int curTime = (int) (System.currentTimeMillis() / 1000);
86 | final String boundary = BOUNDARY_PREFIX + curTime;
87 | connection.setRequestProperty(HEADER_CONTENT_TYPE, buildBodyContentType(curTime));
88 |
89 | if (isFixedStreamingMode()) {
90 | int contentLength = getContentLength(boundary, mRequestParams);
91 | connection.setFixedLengthStreamingMode(contentLength);
92 | } else {
93 | connection.setChunkedStreamingMode(0);
94 | }
95 |
96 | // Write parameters
97 | PrintWriter writer = null;
98 | try {
99 | OutputStream out = connection.getOutputStream();
100 | writer = new PrintWriter(new OutputStreamWriter(out, charset), true);
101 |
102 | if (mRequestParams.hasJsonInParams()) {
103 | // append json
104 | writer.append(mRequestParams.buildJsonParams()).flush();
105 |
106 | }else {
107 | writeFieldToOutputStream(boundary, writer);
108 | writeFileToOutputStream(boundary, writer, out);
109 |
110 | // End of multipart/form-data.
111 | writer.append(boundary + BOUNDARY_PREFIX).append(CRLF).flush();
112 | }
113 |
114 | } catch (Exception e) {
115 | e.printStackTrace();
116 |
117 | } finally {
118 | if (writer != null) {
119 | writer.close();
120 | }
121 | }
122 |
123 | }
124 |
125 | private void writeFieldToOutputStream(final String boundary, PrintWriter writer) {
126 | // add field
127 | Map stringOrIntParams = mRequestParams.buildParametersToMap();
128 | for (String key : stringOrIntParams.keySet()) {
129 | String param = stringOrIntParams.get(key);
130 |
131 | writer.append(boundary).append(CRLF)
132 | .append(String.format(HEADER_CONTENT_DISPOSITION + COLON_SPACE + FORM_DATA, key)).append(CRLF)
133 | .append(HEADER_CONTENT_TYPE + COLON_SPACE + CONTENT_TYPE_TEXT)
134 | .append(CRLF).append(CRLF)
135 | .append(param).append(CRLF).flush();
136 | }
137 | }
138 |
139 | private void writeFileToOutputStream(final String boundary, PrintWriter writer, OutputStream out)
140 | throws IOException, FileNotFoundException {
141 | // add file
142 | Map fileParams = mRequestParams.buildFileParameters();
143 | int currentFileIndex = 1;
144 | for (String key : fileParams.keySet()) {
145 |
146 | File file = fileParams.get(key);
147 |
148 | if (!file.exists()) {
149 | CLog.e("File not found: %s", file.getAbsolutePath());
150 | throw new IOException(String.format("File not found: %s", file.getAbsolutePath()));
151 | }
152 |
153 | if (file.isDirectory()) {
154 | CLog.e("File is a directory: %s", file.getAbsolutePath());
155 | throw new IOException(String.format("File is a directory: %s", file.getAbsolutePath()));
156 | }
157 |
158 | writer.append(boundary).append(CRLF)
159 | .append(String.format(
160 | HEADER_CONTENT_DISPOSITION + COLON_SPACE + FORM_DATA + SEMICOLON_SPACE + FILENAME, key,
161 | file.getName()))
162 | .append(CRLF).append(HEADER_CONTENT_TYPE + COLON_SPACE + CONTENT_TYPE_OCTET_STREAM).append(CRLF)
163 | .append(HEADER_CONTENT_TRANSFER_ENCODING + COLON_SPACE + BINARY).append(CRLF).append(CRLF)
164 | .flush();
165 |
166 | BufferedInputStream input = null;
167 | try {
168 | FileInputStream fis = new FileInputStream(file);
169 | int transferredBytesSize = 0;
170 | int totalSize = (int) file.length();
171 | input = new BufferedInputStream(fis);
172 | int bufferLength = 0;
173 |
174 | byte[] buffer = new byte[1024];
175 | while ((bufferLength = input.read(buffer)) > 0) {
176 | CLog.w(" thread name : %s" ,Thread.currentThread().getName());
177 | out.write(buffer, 0, bufferLength);
178 | transferredBytesSize += bufferLength;
179 | //super.getRequestQueue().getDelivery().postRequestUploadProgress(this, transferredBytesSize,totalSize); //UI Thread
180 | super.onRequestUploadProgress(transferredBytesSize, totalSize,currentFileIndex,file); //Thread
181 | }
182 | // Important! Output cannot be closed. Close of writer will
183 | // close output as well.
184 | out.flush();
185 | } finally {
186 | if (input != null)
187 | try {
188 | input.close();
189 | } catch (IOException ex) {
190 | ex.printStackTrace();
191 | }
192 | }
193 | // CRLF is important! It indicates end of binary boundary.
194 | writer.append(CRLF).flush();
195 |
196 | currentFileIndex ++;
197 | }
198 | }
199 |
200 | public boolean isFixedStreamingMode() {
201 | return isFixedStreamingMode;
202 | }
203 |
204 | public void setFixedStreamingMode(boolean isFixedStreamingMode) {
205 | this.isFixedStreamingMode = isFixedStreamingMode;
206 | }
207 |
208 | public void setRequestParams(RequestParams requestParams){
209 | this.mRequestParams = requestParams;
210 | }
211 |
212 | public RequestParams getRequestParams() {
213 | return mRequestParams;
214 | }
215 |
216 |
217 | }
218 |
--------------------------------------------------------------------------------
/XDroidRequest/src/com/xdroid/request/cache/diskcache/StrictLineReader.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.xdroid.request.cache.diskcache;
18 |
19 | import java.io.ByteArrayOutputStream;
20 | import java.io.Closeable;
21 | import java.io.EOFException;
22 | import java.io.IOException;
23 | import java.io.InputStream;
24 | import java.io.UnsupportedEncodingException;
25 | import java.nio.charset.Charset;
26 |
27 | /**
28 | * Buffers input from an {@link java.io.InputStream} for reading lines.
29 | *
30 | * This class is used for buffered reading of lines. For purposes of this class, a line ends
31 | * with "\n" or "\r\n". End of input is reported by throwing {@code EOFException}. Unterminated
32 | * line at end of input is invalid and will be ignored, the caller may use {@code
33 | * hasUnterminatedLine()} to detect it after catching the {@code EOFException}.
34 | *
35 | *
This class is intended for reading input that strictly consists of lines, such as line-based
36 | * cache entries or cache journal. Unlike the {@link java.io.BufferedReader} which in conjunction
37 | * with {@link java.io.InputStreamReader} provides similar functionality, this class uses different
38 | * end-of-input reporting and a more restrictive definition of a line.
39 | *
40 | *
This class supports only charsets that encode '\r' and '\n' as a single byte with value 13
41 | * and 10, respectively, and the representation of no other character contains these values.
42 | * We currently check in constructor that the charset is one of US-ASCII, UTF-8 and ISO-8859-1.
43 | * The default charset is US_ASCII.
44 | */
45 | class StrictLineReader implements Closeable {
46 | private static final byte CR = (byte) '\r';
47 | private static final byte LF = (byte) '\n';
48 |
49 | private final InputStream in;
50 | private final Charset charset;
51 |
52 | /*
53 | * Buffered data is stored in {@code buf}. As long as no exception occurs, 0 <= pos <= end
54 | * and the data in the range [pos, end) is buffered for reading. At end of input, if there is
55 | * an unterminated line, we set end == -1, otherwise end == pos. If the underlying
56 | * {@code InputStream} throws an {@code IOException}, end may remain as either pos or -1.
57 | */
58 | private byte[] buf;
59 | private int pos;
60 | private int end;
61 |
62 | /**
63 | * Constructs a new {@code LineReader} with the specified charset and the default capacity.
64 | *
65 | * @param in the {@code InputStream} to read data from.
66 | * @param charset the charset used to decode data. Only US-ASCII, UTF-8 and ISO-8859-1 are
67 | * supported.
68 | * @throws NullPointerException if {@code in} or {@code charset} is null.
69 | * @throws IllegalArgumentException if the specified charset is not supported.
70 | */
71 | public StrictLineReader(InputStream in, Charset charset) {
72 | this(in, 8192, charset);
73 | }
74 |
75 | /**
76 | * Constructs a new {@code LineReader} with the specified capacity and charset.
77 | *
78 | * @param in the {@code InputStream} to read data from.
79 | * @param capacity the capacity of the buffer.
80 | * @param charset the charset used to decode data. Only US-ASCII, UTF-8 and ISO-8859-1 are
81 | * supported.
82 | * @throws NullPointerException if {@code in} or {@code charset} is null.
83 | * @throws IllegalArgumentException if {@code capacity} is negative or zero
84 | * or the specified charset is not supported.
85 | */
86 | public StrictLineReader(InputStream in, int capacity, Charset charset) {
87 | if (in == null || charset == null) {
88 | throw new NullPointerException();
89 | }
90 | if (capacity < 0) {
91 | throw new IllegalArgumentException("capacity <= 0");
92 | }
93 | if (!(charset.equals(Util.US_ASCII))) {
94 | throw new IllegalArgumentException("Unsupported encoding");
95 | }
96 |
97 | this.in = in;
98 | this.charset = charset;
99 | buf = new byte[capacity];
100 | }
101 |
102 | /**
103 | * Closes the reader by closing the underlying {@code InputStream} and
104 | * marking this reader as closed.
105 | *
106 | * @throws java.io.IOException for errors when closing the underlying {@code InputStream}.
107 | */
108 | public void close() throws IOException {
109 | synchronized (in) {
110 | if (buf != null) {
111 | buf = null;
112 | in.close();
113 | }
114 | }
115 | }
116 |
117 | /**
118 | * Reads the next line. A line ends with {@code "\n"} or {@code "\r\n"},
119 | * this end of line marker is not included in the result.
120 | *
121 | * @return the next line from the input.
122 | * @throws java.io.IOException for underlying {@code InputStream} errors.
123 | * @throws java.io.EOFException for the end of source stream.
124 | */
125 | public String readLine() throws IOException {
126 | synchronized (in) {
127 | if (buf == null) {
128 | throw new IOException("LineReader is closed");
129 | }
130 |
131 | // Read more data if we are at the end of the buffered data.
132 | // Though it's an error to read after an exception, we will let {@code fillBuf()}
133 | // throw again if that happens; thus we need to handle end == -1 as well as end == pos.
134 | if (pos >= end) {
135 | fillBuf();
136 | }
137 | // Try to find LF in the buffered data and return the line if successful.
138 | for (int i = pos; i != end; ++i) {
139 | if (buf[i] == LF) {
140 | int lineEnd = (i != pos && buf[i - 1] == CR) ? i - 1 : i;
141 | String res = new String(buf, pos, lineEnd - pos, charset.name());
142 | pos = i + 1;
143 | return res;
144 | }
145 | }
146 |
147 | // Let's anticipate up to 80 characters on top of those already read.
148 | ByteArrayOutputStream out = new ByteArrayOutputStream(end - pos + 80) {
149 | @Override
150 | public String toString() {
151 | int length = (count > 0 && buf[count - 1] == CR) ? count - 1 : count;
152 | try {
153 | return new String(buf, 0, length, charset.name());
154 | } catch (UnsupportedEncodingException e) {
155 | throw new AssertionError(e); // Since we control the charset this will never happen.
156 | }
157 | }
158 | };
159 |
160 | while (true) {
161 | out.write(buf, pos, end - pos);
162 | // Mark unterminated line in case fillBuf throws EOFException or IOException.
163 | end = -1;
164 | fillBuf();
165 | // Try to find LF in the buffered data and return the line if successful.
166 | for (int i = pos; i != end; ++i) {
167 | if (buf[i] == LF) {
168 | if (i != pos) {
169 | out.write(buf, pos, i - pos);
170 | }
171 | pos = i + 1;
172 | return out.toString();
173 | }
174 | }
175 | }
176 | }
177 | }
178 |
179 | public boolean hasUnterminatedLine() {
180 | return end == -1;
181 | }
182 |
183 | /**
184 | * Reads new input data into the buffer. Call only with pos == end or end == -1,
185 | * depending on the desired outcome if the function throws.
186 | */
187 | private void fillBuf() throws IOException {
188 | int result = in.read(buf, 0, buf.length);
189 | if (result == -1) {
190 | throw new EOFException();
191 | }
192 | pos = 0;
193 | end = result;
194 | }
195 | }
196 |
197 |
--------------------------------------------------------------------------------
/XDroidRequest/src/com/xdroid/request/network/Network.java:
--------------------------------------------------------------------------------
1 | package com.xdroid.request.network;
2 |
3 | import java.io.IOException;
4 | import java.io.InputStream;
5 | import java.net.MalformedURLException;
6 | import java.net.SocketTimeoutException;
7 | import java.util.HashMap;
8 | import java.util.Map;
9 |
10 | import com.xdroid.request.base.Request;
11 | import com.xdroid.request.response.NetworkResponse;
12 | import com.xdroid.request.retry.RetryPolicy;
13 | import com.xdroid.request.utils.CLog;
14 |
15 | /**
16 | * The network requests the HttpStack to use the Request client to initiate a network request and returns a NetworkRespond result.
17 | * @author Robin
18 | * @since 2015-07-02 16:16:57
19 | */
20 | public class Network {
21 | protected final HttpStack mHttpStack;
22 |
23 | public Network(HttpStack httpStack) {
24 | mHttpStack = httpStack;
25 | }
26 |
27 | /**
28 | * Actually executing a request
29 | *
30 | * @param request
31 | * @return A response not to null
32 | * @throws HttpException
33 | */
34 | public NetworkResponse performRequest(Request> request)
35 | throws HttpException {
36 | while (true) {
37 | HttpResponse httpResponse = null;
38 | byte[] responseContents = null;
39 | Map responseHeaders = new HashMap();
40 | try {
41 | Map headers = new HashMap();
42 | httpResponse = mHttpStack.performRequest(request, headers);
43 |
44 | int statusCode = httpResponse.getResponseCode();
45 | responseHeaders = httpResponse.getHeaders();
46 | if (statusCode == HttpStatus.SC_NOT_MODIFIED) { // 304
47 | return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED,
48 | null,
49 | responseHeaders, true);
50 | }
51 |
52 | if (httpResponse.getContentStream() != null) {
53 | /*if (request instanceof FileRequest) {
54 | responseContents = ((FileRequest) request)
55 | .handleResponse(httpResponse);
56 | } else {*/
57 | responseContents = responseToBytes(request,httpResponse);
58 | // }
59 | } else {
60 | responseContents = new byte[0];
61 | }
62 |
63 | if (statusCode < 200 || statusCode > 299) {
64 | throw new IOException();
65 | }
66 | return new NetworkResponse(statusCode, responseContents,
67 | responseHeaders, false);
68 | } catch (SocketTimeoutException e) {
69 | if (request.getRequestCacheConfig().isRetryWhenRequestFailed()) {
70 | retryOnException( request, new HttpException("socket timeout",HttpError.ERROR_SOCKET_TIMEOUT));
71 | }else {
72 | throw new HttpException("socket timeout",HttpError.ERROR_SOCKET_TIMEOUT);
73 | }
74 | }
75 | /*catch (ConnectTimeoutException e) {
76 | if (request.getCacheConfig().isRetryWhenRequestFailed()) {
77 | retryOnException( request, new HttpException("connect timeout"));
78 | }else {
79 | throw new HttpException(new SocketTimeoutException("connect timeout"));
80 | }
81 | } */
82 | catch (MalformedURLException e) {
83 | throw new RuntimeException("Bad URL " + request.getUrl(), e);
84 | } catch (IOException e) {
85 | int statusCode = 0;
86 | //NetworkResponse networkResponse = null;
87 | if (httpResponse != null) {
88 | statusCode = httpResponse.getResponseCode();
89 | } else {
90 | //throw new HttpException("NoConnection error", e);
91 | throw new HttpException("NoConnection error", HttpError.ERROR_NO_CONNECTION);
92 | //retryOnException( request, new HttpException("NoConnection error",e));
93 | }
94 | CLog.d("Unexpected response code %s for: %s",statusCode,request.getUrl());
95 | if (responseContents != null) {
96 | //networkResponse = new NetworkResponse(statusCode,responseContents, responseHeaders, false);
97 | if (statusCode == HttpStatus.SC_UNAUTHORIZED|| statusCode == HttpStatus.SC_FORBIDDEN) {
98 | if (request.getRequestCacheConfig().isRetryWhenRequestFailed()) {
99 | retryOnException( request, new HttpException("auth error",HttpError.ERROR_UNAUTHORIZED));
100 | } else {
101 | throw new HttpException("auth error",HttpError.ERROR_UNAUTHORIZED);
102 | }
103 | } else if (statusCode == HttpStatus.SC_MOVED_PERMANENTLY || statusCode == HttpStatus.SC_MOVED_TEMPORARILY) {
104 | if (request.getRequestCacheConfig().isRetryWhenRequestFailed()) {
105 | retryOnException( request, new HttpException("redirect error",HttpError.ERROR_REDIRECT));
106 | }else {
107 | throw new HttpException("redirect error",HttpError.ERROR_REDIRECT);
108 | }
109 |
110 | } else {
111 | throw new HttpException("server error, Only throw ServerError for 5xx status codes.",HttpError.ERROR_SERVER);
112 | }
113 | } else {
114 | throw new HttpException("responseContents is null",HttpError.ERROR_RESPONSE_NULL);
115 | }
116 | }
117 | }
118 | }
119 |
120 |
121 | /**
122 | * Convert HttpResponse to byte[]
123 | *
124 | * @param request
125 | * @param response
126 | * @return
127 | * @throws IOException
128 | * @throws HttpException
129 | */
130 | private byte[] responseToBytes(Request> request,HttpResponse response) throws IOException,
131 | HttpException {
132 | PoolingByteArrayOutputStream bytes = new PoolingByteArrayOutputStream(
133 | ByteArrayPool.get(), (int) response.getContentLength());
134 | byte[] buffer = null;
135 | long totalSize = (int) response.getContentLength();
136 | try {
137 | InputStream in =response.getContentStream();
138 | if (in == null) {
139 | throw new HttpException("server error",HttpError.ERROR_SERVER);
140 | }
141 | buffer = ByteArrayPool.get().getBuf(1024);
142 | int count;
143 | int transferredBytesSize = 0;
144 | while ((count = in.read(buffer)) != -1) {
145 | bytes.write(buffer, 0, count);
146 | transferredBytesSize += count;
147 | //request.getRequestQueue().getDelivery().postRequestDownloadProgress(request,transferredBytesSize, totalSize);
148 | request.onRequestDownloadProgress(transferredBytesSize, totalSize);
149 | }
150 | return bytes.toByteArray();
151 | } finally {
152 | try {
153 | response.getContentStream().close();
154 | } catch (IOException e) {
155 | CLog.d("Error occured when calling consumingContent");
156 | }
157 | ByteArrayPool.get().returnBuf(buffer);
158 | bytes.close();
159 | }
160 | }
161 |
162 | /**
163 | * When an exception occurs to try again
164 | * @param request
165 | * @param exception
166 | * @return
167 | * @throws HttpException
168 | */
169 | private static RetryPolicy retryOnException( Request> request,HttpException exception) throws HttpException {
170 | RetryPolicy retryPolicy = request.getRetryPolicy();
171 | try {
172 | retryPolicy.retry(exception);
173 | } catch (HttpException e) {
174 | throw e;
175 | }
176 |
177 | /*Distribution of retry event*/
178 | request.getRequestQueue().getDelivery().postRequestRetry(request, retryPolicy.getCurrentRetryCount() ,exception);
179 |
180 | return retryPolicy;
181 | }
182 | }
183 |
--------------------------------------------------------------------------------
/XDroidRequest/src/com/xdroid/request/ex/ImageRequest.java:
--------------------------------------------------------------------------------
1 | package com.xdroid.request.ex;
2 |
3 | import com.xdroid.request.config.HttpMethod;
4 | import com.xdroid.request.config.Priority;
5 | import com.xdroid.request.config.RequestCacheConfig;
6 | import com.xdroid.request.interfaces.OnRequestListener;
7 | import com.xdroid.request.network.HttpError;
8 | import com.xdroid.request.network.HttpException;
9 | import com.xdroid.request.response.NetworkResponse;
10 | import com.xdroid.request.response.Response;
11 | import com.xdroid.request.retry.DefaultRetryPolicyImpl;
12 | import com.xdroid.request.utils.CLog;
13 |
14 | import android.graphics.Bitmap;
15 | import android.graphics.Bitmap.Config;
16 | import android.graphics.BitmapFactory;
17 | import android.widget.ImageView.ScaleType;
18 |
19 | /**
20 | * Get a bitmap from network
21 | * @author Robin
22 | * @since 2016-01-05 19:18:45
23 | */
24 | public class ImageRequest extends MultipartRequest {
25 | /** Socket timeout in milliseconds for image requests */
26 | private static final int IMAGE_TIMEOUT_MS = 1000;
27 |
28 | /** Default number of retries for image requests */
29 | private static final int IMAGE_MAX_RETRIES = 2;
30 |
31 | /** Default backoff multiplier for image requests */
32 | private static final float IMAGE_BACKOFF_MULT = 2f;
33 |
34 | private final Config mDecodeConfig;
35 | private final int mMaxWidth;
36 | private final int mMaxHeight;
37 | private ScaleType mScaleType;
38 |
39 | /**
40 | * Decoding lock so that we don't decode more than one image at a time (to
41 | * avoid OOM's)
42 | */
43 | private static final Object sDecodeLock = new Object();
44 |
45 | public ImageRequest( String url,OnRequestListener onRequestListener) {
46 | this(RequestCacheConfig.buildImageCacheConfig(), url, url, onRequestListener, 0,0, ScaleType.CENTER_INSIDE, Config.ARGB_8888);
47 | }
48 |
49 | public ImageRequest( String url,String cacheKey,OnRequestListener onRequestListener) {
50 | this(RequestCacheConfig.buildImageCacheConfig(), url, cacheKey, onRequestListener, 0,0, ScaleType.CENTER_INSIDE, Config.ARGB_8888);
51 | }
52 |
53 | public ImageRequest( RequestCacheConfig cacheConfig, String url,String cacheKey,OnRequestListener onRequestListener) {
54 | this(cacheConfig, url, cacheKey, onRequestListener, 0,0, ScaleType.CENTER_INSIDE, Config.ARGB_8888);
55 | }
56 |
57 | public ImageRequest(RequestCacheConfig cacheConfig, String url, String cacheKey,
58 | OnRequestListener onRequestListener,int maxWidth, int maxHeight, ScaleType scaleType, Config decodeConfig) {
59 | super(cacheConfig, url, cacheKey, onRequestListener);
60 | setRetryPolicy(new DefaultRetryPolicyImpl(IMAGE_TIMEOUT_MS, IMAGE_MAX_RETRIES, IMAGE_BACKOFF_MULT));
61 | setPriority(Priority.LOW);
62 | setHttpMethod(HttpMethod.GET);
63 | mDecodeConfig = decodeConfig;
64 | mMaxWidth = maxWidth;
65 | mMaxHeight = maxHeight;
66 | mScaleType = scaleType;
67 | }
68 |
69 |
70 | @Override
71 | public Response parseNetworkResponse(NetworkResponse response) {
72 | // Serialize all decode on a global lock to reduce concurrent heap
73 | // usage.
74 | synchronized (sDecodeLock) {
75 | try {
76 | return doParse(response);
77 | } catch (OutOfMemoryError e) {
78 | CLog.e("Caught OOM for %d byte image, url=%s", response.data.length, getUrl());
79 | return Response.error(new HttpException(e.getMessage(), HttpError.ERROR_PARSE));
80 | }
81 | }
82 | }
83 |
84 | /**
85 | * The real guts of parseNetworkResponse. Broken out for readability.
86 | */
87 | private Response doParse(NetworkResponse response) {
88 | byte[] data = response.data;
89 | BitmapFactory.Options decodeOptions = new BitmapFactory.Options();
90 | Bitmap bitmap = null;
91 | if (mMaxWidth == 0 && mMaxHeight == 0) {
92 | decodeOptions.inPreferredConfig = mDecodeConfig;
93 | bitmap = BitmapFactory.decodeByteArray(data, 0, data.length, decodeOptions);
94 | } else {
95 | // If we have to resize this image, first get the natural bounds.
96 | decodeOptions.inJustDecodeBounds = true;
97 | BitmapFactory.decodeByteArray(data, 0, data.length, decodeOptions);
98 | int actualWidth = decodeOptions.outWidth;
99 | int actualHeight = decodeOptions.outHeight;
100 |
101 | // Then compute the dimensions we would ideally like to decode to.
102 | int desiredWidth = getResizedDimension(mMaxWidth, mMaxHeight, actualWidth, actualHeight, mScaleType);
103 | int desiredHeight = getResizedDimension(mMaxHeight, mMaxWidth, actualHeight, actualWidth, mScaleType);
104 |
105 | // Decode to the nearest power of two scaling factor.
106 | decodeOptions.inJustDecodeBounds = false;
107 | // TODO(ficus): Do we need this or is it okay since API 8 doesn't
108 | // support it?
109 | // decodeOptions.inPreferQualityOverSpeed =
110 | // PREFER_QUALITY_OVER_SPEED;
111 | decodeOptions.inSampleSize = findBestSampleSize(actualWidth, actualHeight, desiredWidth, desiredHeight);
112 | Bitmap tempBitmap = BitmapFactory.decodeByteArray(data, 0, data.length, decodeOptions);
113 |
114 | // If necessary, scale down to the maximal acceptable size.
115 | if (tempBitmap != null
116 | && (tempBitmap.getWidth() > desiredWidth || tempBitmap.getHeight() > desiredHeight)) {
117 | bitmap = Bitmap.createScaledBitmap(tempBitmap, desiredWidth, desiredHeight, true);
118 | tempBitmap.recycle();
119 | } else {
120 | bitmap = tempBitmap;
121 | }
122 | }
123 |
124 | if (bitmap == null) {
125 | return Response.error(new HttpException("bitmap == null", HttpError.ERROR_PARSE));
126 | } else {
127 | super.onParseNetworkResponse(response, bitmap);
128 | return Response.success(bitmap, response.headers);
129 | }
130 | }
131 |
132 | /**
133 | * Scales one side of a rectangle to fit aspect ratio.
134 | *
135 | * @param maxPrimary
136 | * Maximum size of the primary dimension (i.e. width for max
137 | * width), or zero to maintain aspect ratio with secondary
138 | * dimension
139 | * @param maxSecondary
140 | * Maximum size of the secondary dimension, or zero to maintain
141 | * aspect ratio with primary dimension
142 | * @param actualPrimary
143 | * Actual size of the primary dimension
144 | * @param actualSecondary
145 | * Actual size of the secondary dimension
146 | * @param scaleType
147 | * The ScaleType used to calculate the needed image size.
148 | */
149 | private static int getResizedDimension(int maxPrimary, int maxSecondary, int actualPrimary, int actualSecondary,
150 | ScaleType scaleType) {
151 |
152 | // If no dominant value at all, just return the actual.
153 | if ((maxPrimary == 0) && (maxSecondary == 0)) {
154 | return actualPrimary;
155 | }
156 |
157 | // If ScaleType.FIT_XY fill the whole rectangle, ignore ratio.
158 | if (scaleType == ScaleType.FIT_XY) {
159 | if (maxPrimary == 0) {
160 | return actualPrimary;
161 | }
162 | return maxPrimary;
163 | }
164 |
165 | // If primary is unspecified, scale primary to match secondary's scaling
166 | // ratio.
167 | if (maxPrimary == 0) {
168 | double ratio = (double) maxSecondary / (double) actualSecondary;
169 | return (int) (actualPrimary * ratio);
170 | }
171 |
172 | if (maxSecondary == 0) {
173 | return maxPrimary;
174 | }
175 |
176 | double ratio = (double) actualSecondary / (double) actualPrimary;
177 | int resized = maxPrimary;
178 |
179 | // If ScaleType.CENTER_CROP fill the whole rectangle, preserve aspect
180 | // ratio.
181 | if (scaleType == ScaleType.CENTER_CROP) {
182 | if ((resized * ratio) < maxSecondary) {
183 | resized = (int) (maxSecondary / ratio);
184 | }
185 | return resized;
186 | }
187 |
188 | if ((resized * ratio) > maxSecondary) {
189 | resized = (int) (maxSecondary / ratio);
190 | }
191 | return resized;
192 | }
193 |
194 | /**
195 | * Returns the largest power-of-two divisor for use in downscaling a bitmap
196 | * that will not result in the scaling past the desired dimensions.
197 | *
198 | * @param actualWidth
199 | * Actual width of the bitmap
200 | * @param actualHeight
201 | * Actual height of the bitmap
202 | * @param desiredWidth
203 | * Desired width of the bitmap
204 | * @param desiredHeight
205 | * Desired height of the bitmap
206 | */
207 | // Visible for testing.
208 | static int findBestSampleSize(int actualWidth, int actualHeight, int desiredWidth, int desiredHeight) {
209 | double wr = (double) actualWidth / desiredWidth;
210 | double hr = (double) actualHeight / desiredHeight;
211 | double ratio = Math.min(wr, hr);
212 | float n = 1.0f;
213 | while ((n * 2) <= ratio) {
214 | n *= 2;
215 | }
216 |
217 | return (int) n;
218 | }
219 | }
220 |
--------------------------------------------------------------------------------
/XDroidRequest/src/com/xdroid/request/delivered/DeliveryImpl.java:
--------------------------------------------------------------------------------
1 | package com.xdroid.request.delivered;
2 |
3 | import java.io.File;
4 | import java.util.concurrent.Executor;
5 |
6 | import com.xdroid.request.base.Request;
7 | import com.xdroid.request.cache.CacheData;
8 | import com.xdroid.request.cache.Entry;
9 | import com.xdroid.request.network.HttpException;
10 | import com.xdroid.request.response.Response;
11 | import com.xdroid.request.utils.CLog;
12 |
13 | import android.os.Handler;
14 |
15 | /**
16 | * HTTP response of the distributor, here used to distribute the response of the
17 | * asynchronous thread to the UI thread to execute
18 | *
19 | * @author Robin
20 | * @since 2015-07-02 14:53:25
21 | */
22 | public class DeliveryImpl implements IDelivery {
23 |
24 | private final Executor mResponsePoster;
25 |
26 | private RequestUploadProgressRunnable mRequestUploadProgressRunnable;
27 |
28 | private RequestProgressRunnable mRequestProgressRunnable;
29 |
30 | public DeliveryImpl(final Handler handler) {
31 | mResponsePoster = new Executor() {
32 | @Override
33 | public void execute(Runnable command) {
34 | handler.post(command);
35 | }
36 | };
37 | }
38 |
39 | public DeliveryImpl(Executor executor) {
40 | mResponsePoster = executor;
41 | }
42 |
43 | /*
44 | * ========================================================================
45 | * Override Delivery
46 | * ========================================================================
47 | */
48 |
49 | @Override
50 | public void postRequestResponse(Request> request, Response> response) {
51 | // request.markDelivered();
52 | mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, null));
53 | }
54 |
55 | @Override
56 | public void postError(Request> request, HttpException error) {
57 | Response> response = Response.error(error);
58 | mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, null));
59 | }
60 |
61 | @SuppressWarnings("unchecked")
62 | @Override
63 | public void postCacheResponse(Request> request, T cacheData) {
64 | mResponsePoster.execute(new ResponseDeliveryRunnable(request, null, (CacheData>) cacheData));
65 | }
66 |
67 | @Override
68 | public void postRequestPrepare(Request> request) {
69 | mResponsePoster.execute(new RequestPrepareRunnable(request));
70 | }
71 |
72 | @Override
73 | public void postRequestRetry(Request> request, int currentRetryCount, HttpException previousError) {
74 | mResponsePoster.execute(new RequestRetryRunnable(request, currentRetryCount, previousError));
75 | }
76 |
77 | @Override
78 | public void postRequestDownloadProgress(Request> request, long transferredBytesSize, long totalSize) {
79 | if (mRequestProgressRunnable == null) {
80 | mRequestProgressRunnable = new RequestProgressRunnable(request, transferredBytesSize,
81 | totalSize);
82 | }else {
83 | mRequestProgressRunnable.updateParams(request, transferredBytesSize, totalSize);
84 | }
85 | mResponsePoster.execute(mRequestProgressRunnable);
86 | }
87 |
88 | @Override
89 | public void postRequestUploadProgress(Request> request, long transferredBytesSize, long totalSize, int currentFileIndex, File currentFile) {
90 | if (mRequestUploadProgressRunnable == null) {
91 | mRequestUploadProgressRunnable = new RequestUploadProgressRunnable(request, transferredBytesSize,
92 | totalSize, currentFileIndex,currentFile);
93 | }else {
94 | mRequestUploadProgressRunnable.updateParams(request, transferredBytesSize, totalSize, currentFileIndex,currentFile);
95 | }
96 | mResponsePoster.execute(mRequestUploadProgressRunnable);
97 | }
98 |
99 | /*
100 | * ========================================================================
101 | * Runnable task
102 | * ========================================================================
103 | */
104 |
105 | /**
106 | * Runnable task, for the network request response, access to the cache
107 | * results response, failure event, distributed to the UI thread
108 | */
109 | @SuppressWarnings("rawtypes")
110 | private class ResponseDeliveryRunnable implements Runnable {
111 | private final Request mRequest;
112 | private final Response mResponse;
113 | private final CacheData> cacheData;
114 |
115 | public ResponseDeliveryRunnable(Request request, Response response, CacheData> cacheData) {
116 | mRequest = request;
117 | mResponse = response;
118 | this.cacheData = cacheData;
119 | }
120 |
121 | @SuppressWarnings("unchecked")
122 | @Override
123 | public void run() {
124 | if (mRequest.isCanceled()) {
125 | mRequest.finish();
126 | CLog.e("request is cancel when delivered");
127 | return;
128 | }
129 |
130 | if (mResponse != null) {
131 | CLog.i("Hand in main thread");
132 | if (mResponse.isSuccess()) {
133 | mRequest.onRequestFinish(mResponse.headers, mResponse.result);
134 | } else {
135 | mRequest.onRequestFailed(mResponse.error);
136 | }
137 | } else if (cacheData != null) {
138 | // When "isUseCacheDataWhenTimeout" is true, you cannot reset
139 | // the data delivery,
140 | // otherwise it will be delivered to the cached data again after
141 | // the request is completed.
142 | if (!mRequest.getRequestCacheConfig().isUseCacheDataWhenTimeout()) {
143 | mRequest.resetDelivered();
144 | }
145 | mRequest.onCacheDataLoadFinish(cacheData);
146 | }
147 |
148 | // mRequest.requestFinish();
149 | // mRequest.finish();
150 |
151 | }
152 | }
153 |
154 | /**
155 | * Runnable task, which is used to distribute the pre request event to the
156 | * main thread.
157 | */
158 | private class RequestPrepareRunnable implements Runnable {
159 | private Request> mRequest;
160 |
161 | public RequestPrepareRunnable(Request> request) {
162 | mRequest = request;
163 | }
164 |
165 | @Override
166 | public void run() {
167 | if (mRequest.isCanceled()) {
168 | mRequest.finish();
169 | CLog.e("request is cancel when prepare");
170 | return;
171 | }
172 |
173 | mRequest.requestPrepare();
174 | }
175 | }
176 |
177 | /**
178 | * Runnable task, which is used to distribute the pre request event to the
179 | * main thread.
180 | */
181 | private class RequestRetryRunnable implements Runnable {
182 | private Request> mRequest;
183 | private HttpException mPreviousError;
184 | private int mCurrentRetryCount;
185 |
186 | public RequestRetryRunnable(Request> request, int currentRetryCount, HttpException previousError) {
187 | mRequest = request;
188 | this.mCurrentRetryCount = currentRetryCount;
189 | this.mPreviousError = previousError;
190 | }
191 |
192 | @Override
193 | public void run() {
194 | if (mRequest.isCanceled()) {
195 | mRequest.finish();
196 | CLog.e("request is cancel when retry");
197 | return;
198 | }
199 |
200 | mRequest.onRequestRetry(mCurrentRetryCount, mPreviousError);
201 | }
202 | }
203 |
204 | /**
205 | * Runnable task, which is used to delivered request progress.
206 | */
207 | private class RequestProgressRunnable implements Runnable {
208 | private Request> mRequest;
209 | private long mTransferredBytesSize;
210 | private long mTotalSize;
211 |
212 | public RequestProgressRunnable(Request> request, long transferredBytesSize, long totalSize) {
213 | mRequest = request;
214 | this.mTransferredBytesSize = transferredBytesSize;
215 | this.mTotalSize = totalSize;
216 | }
217 |
218 | @Override
219 | public void run() {
220 | if (mRequest.isCanceled()) {
221 | mRequest.finish();
222 | CLog.e("request is cancel when on progress");
223 | return;
224 | }
225 |
226 | mRequest.onRequestDownloadProgress(mTransferredBytesSize, mTotalSize);
227 | }
228 |
229 | public void updateParams(Request> request, long transferredBytesSize, long totalSize) {
230 | this.mRequest = request;
231 | this.mTransferredBytesSize = transferredBytesSize;
232 | this.mTotalSize = totalSize;
233 | }
234 | }
235 |
236 | /**
237 | * Runnable task, which is used to delivered upload progress.
238 | */
239 | private class RequestUploadProgressRunnable implements Runnable {
240 | private Request> mRequest;
241 | private long mTransferredBytesSize;
242 | private long mTotalSize;
243 | private int mCurrentFileIndex;
244 | private File mCurrentFile;
245 |
246 | public RequestUploadProgressRunnable(Request> request, long transferredBytesSize, long totalSize, int currentFileIndex, File currentFile) {
247 | this.mRequest = request;
248 | this.mTransferredBytesSize = transferredBytesSize;
249 | this.mTotalSize = totalSize;
250 | this.mCurrentFileIndex = currentFileIndex;
251 | this.mCurrentFile = currentFile;
252 | }
253 |
254 | @Override
255 | public void run() {
256 | if (mRequest.isCanceled()) {
257 | mRequest.finish();
258 | CLog.e("request is cancel when on upload progress");
259 | return;
260 | }
261 |
262 | mRequest.onRequestUploadProgress(mTransferredBytesSize, mTotalSize, mCurrentFileIndex, mCurrentFile);
263 | }
264 |
265 | public void updateParams(Request> request, long transferredBytesSize, long totalSize, int currentFileIndex, File currentFile) {
266 | this.mRequest = request;
267 | this.mTransferredBytesSize = transferredBytesSize;
268 | this.mTotalSize = totalSize;
269 | this.mCurrentFileIndex = currentFileIndex;
270 | this.mCurrentFile = currentFile;
271 | }
272 | }
273 |
274 | }
275 |
--------------------------------------------------------------------------------
/XDroidRequest/src/com/xdroid/request/XRequest.java:
--------------------------------------------------------------------------------
1 | package com.xdroid.request;
2 |
3 | import java.io.File;
4 |
5 | import com.xdroid.request.base.Request;
6 | import com.xdroid.request.cache.CacheConfig;
7 | import com.xdroid.request.config.HttpMethod;
8 | import com.xdroid.request.config.RequestCacheConfig;
9 | import com.xdroid.request.ex.DownloadRequest;
10 | import com.xdroid.request.ex.MultipartGsonRequest;
11 | import com.xdroid.request.ex.RequestParams;
12 | import com.xdroid.request.interfaces.IXRequest;
13 | import com.xdroid.request.interfaces.OnRequestListener;
14 | import com.xdroid.request.queue.RequestQueue;
15 | import com.xdroid.request.utils.AppUtils;
16 |
17 | import android.content.Context;
18 |
19 | /**
20 | * Encapsulates the request,for the convenience of call
21 | *
22 | * @author Robin
23 | * @since 2015-08-12 17:43:03
24 | *
25 | */
26 | public class XRequest implements IXRequest {
27 |
28 | private static volatile XRequest INSTANCE = null;
29 |
30 | public static XRequest getInstance() {
31 | if (INSTANCE == null) {
32 | synchronized (XRequest.class) {
33 | if (INSTANCE == null) {
34 | INSTANCE = new XRequest();
35 | }
36 | }
37 | }
38 | return INSTANCE;
39 | }
40 |
41 | public static void initXRequest(Context context, long diskCacheMaxSize, File diskCacheDir, int diskCacheAppVersion, int memoryCacheMaxSize) {
42 | RequestContext.init(context);
43 |
44 | CacheConfig.DISK_CACHE_MAX_SIZE = diskCacheMaxSize;
45 |
46 | CacheConfig.DISK_CACHE_DIRECTORY = diskCacheDir;
47 |
48 | CacheConfig.DISK_CACHE_APP_VERSION = diskCacheAppVersion;
49 |
50 | CacheConfig.MEMORY_CACHE_MAX_SIZE = memoryCacheMaxSize;
51 | }
52 |
53 | public static void initXRequest(Context context, long diskCacheMaxSize, File diskCacheDir, int diskCacheAppVersion) {
54 | initXRequest(context, diskCacheMaxSize, diskCacheDir, diskCacheAppVersion, (int) Runtime.getRuntime().maxMemory() / 8);
55 | }
56 |
57 | public static void initXRequest(Context context, long diskCacheMaxSize, File diskCacheDir) {
58 | initXRequest(context, diskCacheMaxSize, diskCacheDir, AppUtils.getAppVersion(context), (int) Runtime.getRuntime().maxMemory() / 8);
59 | }
60 |
61 | public static void initXRequest(Context context, long diskCacheMaxSize) {
62 | initXRequest(context, diskCacheMaxSize, AppUtils.getDiskCacheDir(context, "xrequest"), AppUtils.getAppVersion(context), (int) Runtime.getRuntime().maxMemory() / 8);
63 | }
64 |
65 | public static void initXRequest(Context context) {
66 | RequestContext.init(context);
67 | CacheConfig.DISK_CACHE_MAX_SIZE = CacheConfig.DEFAULT_MAX_SIZE;
68 | CacheConfig.DISK_CACHE_DIRECTORY = AppUtils.getDiskCacheDir(context, "xrequest");
69 | CacheConfig.DISK_CACHE_APP_VERSION = AppUtils.getAppVersion(context);
70 | CacheConfig.MEMORY_CACHE_MAX_SIZE = (int) Runtime.getRuntime().maxMemory() / 8;
71 | }
72 |
73 | private RequestQueue queue;
74 |
75 | /**
76 | * Best during application initialization calls only once
77 | *
78 | * @param threadPoolSize
79 | */
80 | @Override
81 | public void setRequestThreadPoolSize(int threadPoolSize) {
82 | if (queue != null) {
83 | queue.stop();
84 | queue = null;
85 | }
86 | queue = new RequestQueue(threadPoolSize);
87 | queue.start();
88 | }
89 |
90 | /**
91 | * Add a request to queue to execute
92 | *
93 | * @param request
94 | * Target request
95 | */
96 | @Override
97 | public void addToRequestQueue(Request> request) {
98 | if (queue == null) {
99 | queue = new RequestQueue();
100 | queue.start();
101 | }
102 | queue.add(request);
103 | }
104 |
105 | /**
106 | * Create a default cache configuration
107 | *
108 | * @return
109 | */
110 | @Override
111 | public RequestCacheConfig getDefaultCacheConfig() {
112 | return RequestCacheConfig.buildDefaultCacheConfig();
113 | }
114 |
115 | @Override
116 | public RequestCacheConfig getNoCacheConfig() {
117 | return RequestCacheConfig.buildNoCacheConfig();
118 | }
119 |
120 | /**
121 | * To cancel a request that is requesting
122 | *
123 | * @param request
124 | */
125 | @Override
126 | public void cancelRequest(Request> request) {
127 | if (null != request) {
128 | request.cancel();
129 | }
130 | }
131 |
132 | /**
133 | * Cancel all of this request in the request queue , not including is
134 | * requested
135 | *
136 | * @param request
137 | * Current instance of request
138 | * @param tag
139 | * If there is no special Settings, then introduction the
140 | * instance of activity
141 | */
142 | @Override
143 | public void cancelAllRequestInQueueByTag(Object tag) {
144 | if (queue != null) {
145 | queue.cancelAll(tag);
146 | }
147 | }
148 |
149 | /**
150 | * Start the request,start the thread pool
151 | */
152 | @Override
153 | public void start() {
154 | if (queue != null) {
155 | queue.start();
156 | }
157 | }
158 |
159 | /**
160 | * Close the request, quit all threads, release the request queue
161 | */
162 | @Override
163 | public void shutdown() {
164 | if (queue != null) {
165 | queue.stop();
166 | queue = null;
167 | }
168 | }
169 |
170 | /*
171 | * =======================================================================
172 | * GET
173 | * =======================================================================
174 | */
175 |
176 | @Override
177 | public Request> sendGet(Object tag, String url, String cacheKey, RequestParams params, RequestCacheConfig cacheConfig, OnRequestListener onRequestListener) {
178 | url += params.buildQueryParameters();
179 |
180 | MultipartGsonRequest request = new MultipartGsonRequest(cacheConfig, url, cacheKey, onRequestListener);
181 | request.setRequestParams(params);
182 | request.setHttpMethod(HttpMethod.GET);
183 | request.setTag(tag);
184 |
185 | addToRequestQueue(request);
186 |
187 | return request;
188 |
189 | }
190 |
191 | @Override
192 | public Request> sendGet(Object tag, String url, RequestParams params, OnRequestListener onRequestListener) {
193 | String cacheKey = url;
194 | return sendGet(tag, url, cacheKey, params, getDefaultCacheConfig(), onRequestListener);
195 | }
196 |
197 | @Override
198 | public Request> sendGet(Object tag, String url, String cacheKey, RequestParams params, OnRequestListener onRequestListener) {
199 | return sendGet(tag, url, cacheKey, params, getDefaultCacheConfig(), onRequestListener);
200 | }
201 |
202 | @Override
203 | public Request> sendGet(Object tag, String url, OnRequestListener onRequestListener) {
204 | return sendGet(tag, url, new RequestParams(), onRequestListener);
205 | }
206 |
207 | @Override
208 | public Request> sendGet(Object tag, String url, String cacheKey, OnRequestListener onRequestListener) {
209 | return sendGet(tag, url, cacheKey, new RequestParams(), onRequestListener);
210 | }
211 |
212 | @Override
213 | public Request> sendGet(Object tag, String url, RequestParams params, RequestCacheConfig cacheConfig, OnRequestListener onRequestListener) {
214 | return sendGet(tag, url, url, params, cacheConfig, onRequestListener);
215 | }
216 |
217 | /*
218 | * =======================================================================
219 | * POST
220 | * =======================================================================
221 | */
222 |
223 | @Override
224 | public Request> sendPost(Object tag, String url, String cacheKey, RequestParams params, RequestCacheConfig cacheConfig, OnRequestListener onRequestListener) {
225 | MultipartGsonRequest