├── 1.jpg ├── 2.jpg ├── XDroidRequestExample.apk ├── XDroidRequest ├── libs │ └── gson-2.3.jar ├── lint.xml ├── src │ └── com │ │ └── xdroid │ │ └── request │ │ ├── config │ │ ├── DataType.java │ │ ├── Priority.java │ │ ├── HttpMethod.java │ │ ├── TimeController.java │ │ └── RequestCacheConfig.java │ │ ├── interfaces │ │ ├── OnCacheDataListener.java │ │ ├── IResponseDelivery.java │ │ ├── IRequestCacheManager.java │ │ ├── IRequest.java │ │ ├── OnRequestListener.java │ │ ├── IXReqeust.java │ │ └── IXRequest.java │ │ ├── cache │ │ ├── CacheConfig.java │ │ ├── BitmapCache.java │ │ ├── Entry.java │ │ ├── MemoryCacheManager.java │ │ ├── diskcache │ │ │ ├── Util.java │ │ │ └── StrictLineReader.java │ │ ├── CacheData.java │ │ ├── RequestCacheManager.java │ │ └── DiskCacheManager.java │ │ ├── network │ │ ├── HttpError.java │ │ ├── HttpStack.java │ │ ├── HttpStatus.java │ │ ├── HttpResponse.java │ │ ├── PoolingByteArrayOutputStream.java │ │ ├── HTTPSTrustManager.java │ │ ├── HttpException.java │ │ ├── ByteArrayPool.java │ │ ├── HurlStack.java │ │ └── Network.java │ │ ├── retry │ │ ├── RetryPolicy.java │ │ └── DefaultRetryPolicyImpl.java │ │ ├── RequestContext.java │ │ ├── ex │ │ ├── StringRequest.java │ │ ├── DownloadRequest.java │ │ ├── MultipartGsonRequest.java │ │ ├── RequestParams.java │ │ ├── RequestBodyConstants.java │ │ ├── MultipartRequest.java │ │ └── ImageRequest.java │ │ ├── response │ │ ├── NetworkResponse.java │ │ └── Response.java │ │ ├── utils │ │ ├── NetworkUtils.java │ │ ├── AppUtils.java │ │ └── GenericsUtils.java │ │ ├── impl │ │ └── OnRequestListenerAdapter.java │ │ ├── delivered │ │ ├── IDelivery.java │ │ └── DeliveryImpl.java │ │ ├── package-info.java │ │ ├── dispatcher │ │ ├── NetworkDispatcher.java │ │ └── CacheDispatcher.java │ │ ├── XRequest.java │ │ └── queue │ │ └── RequestQueue.java ├── AndroidManifest.xml └── proguard-project.txt ├── XDroidRequestExample ├── lint.xml ├── res │ ├── values │ │ ├── strings.xml │ │ ├── colos.xml │ │ └── styles.xml │ ├── drawable-hdpi │ │ └── ic_launcher.png │ ├── drawable-mdpi │ │ └── ic_launcher.png │ ├── drawable-xhdpi │ │ └── ic_launcher.png │ └── layout │ │ └── log_item.xml ├── libs │ └── android-support-v4.jar ├── src │ └── com │ │ └── xdroid │ │ └── request │ │ └── example │ │ ├── App.java │ │ ├── log │ │ ├── ILogProcessor.aidl │ │ ├── LogFormattedString.java │ │ └── LogProcessor.java │ │ ├── CityRootBean.java │ │ └── RecipeRootBean.java ├── proguard-project.txt └── AndroidManifest.xml └── .gitignore /1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinxdroid/XDroidRequest/HEAD/1.jpg -------------------------------------------------------------------------------- /2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinxdroid/XDroidRequest/HEAD/2.jpg -------------------------------------------------------------------------------- /XDroidRequestExample.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinxdroid/XDroidRequest/HEAD/XDroidRequestExample.apk -------------------------------------------------------------------------------- /XDroidRequest/libs/gson-2.3.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinxdroid/XDroidRequest/HEAD/XDroidRequest/libs/gson-2.3.jar -------------------------------------------------------------------------------- /XDroidRequest/lint.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /XDroidRequestExample/lint.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /XDroidRequestExample/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | XDroidRequestExample 4 | 5 | 6 | -------------------------------------------------------------------------------- /XDroidRequestExample/libs/android-support-v4.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinxdroid/XDroidRequest/HEAD/XDroidRequestExample/libs/android-support-v4.jar -------------------------------------------------------------------------------- /XDroidRequestExample/res/values/colos.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #E86767 4 | 5 | -------------------------------------------------------------------------------- /XDroidRequestExample/res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinxdroid/XDroidRequest/HEAD/XDroidRequestExample/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /XDroidRequestExample/res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinxdroid/XDroidRequest/HEAD/XDroidRequestExample/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /XDroidRequestExample/res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinxdroid/XDroidRequest/HEAD/XDroidRequestExample/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /XDroidRequest/src/com/xdroid/request/config/DataType.java: -------------------------------------------------------------------------------- 1 | package com.xdroid.request.config; 2 | 3 | /** 4 | * The types of data delivery 5 | * @author Robin 6 | * @since 2015-05-08 16:18:07 7 | */ 8 | public enum DataType { 9 | 10 | CACHE_DATA,NETWORK_DATA; 11 | } 12 | -------------------------------------------------------------------------------- /XDroidRequest/src/com/xdroid/request/interfaces/OnCacheDataListener.java: -------------------------------------------------------------------------------- 1 | package com.xdroid.request.interfaces; 2 | 3 | /** 4 | * the operation with cache callback 5 | * @author Robin 6 | * @since 2015-05-08 00:26:40 7 | */ 8 | public interface OnCacheDataListener { 9 | 10 | public void onFinish(ReturnDataType data); 11 | } 12 | -------------------------------------------------------------------------------- /XDroidRequest/src/com/xdroid/request/config/Priority.java: -------------------------------------------------------------------------------- 1 | package com.xdroid.request.config; 2 | 3 | /** 4 | * Priority values. Requests will be processed from higher priorities to lower priorities, in FIFO order. 5 | * @author Robin 6 | * @since 2015-05-10 00:58:01 7 | */ 8 | public enum Priority { 9 | LOW, 10 | NORMAL, 11 | HIGH, 12 | IMMEDIATE 13 | } -------------------------------------------------------------------------------- /XDroidRequest/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 9 | 10 | 12 | 13 | -------------------------------------------------------------------------------- /XDroidRequest/src/com/xdroid/request/config/HttpMethod.java: -------------------------------------------------------------------------------- 1 | package com.xdroid.request.config; 2 | 3 | /** 4 | * For the default request body definition request method 5 | * @author Robin 6 | * @since 2015-05-13 19:31:46 7 | */ 8 | public interface HttpMethod { 9 | int DEPRECATED_GET_OR_POST = -1; 10 | int GET = 0; 11 | int POST = 1; 12 | int PUT = 2; 13 | int DELETE = 3; 14 | int HEAD = 4; 15 | int OPTIONS = 5; 16 | int TRACE = 6; 17 | int PATCH = 7; 18 | } -------------------------------------------------------------------------------- /XDroidRequest/src/com/xdroid/request/cache/CacheConfig.java: -------------------------------------------------------------------------------- 1 | package com.xdroid.request.cache; 2 | 3 | import java.io.File; 4 | 5 | /** 6 | * Disk cache configuration 7 | * @author Robin 8 | * @since 2015-12-28 16:18:00 9 | * 10 | */ 11 | public class CacheConfig { 12 | 13 | public static long DEFAULT_MAX_SIZE=10*1024*1024; 14 | 15 | public static long DISK_CACHE_MAX_SIZE; 16 | public static File DISK_CACHE_DIRECTORY; 17 | public static int DISK_CACHE_APP_VERSION; 18 | 19 | public static int MEMORY_CACHE_MAX_SIZE; 20 | 21 | } 22 | -------------------------------------------------------------------------------- /XDroidRequest/src/com/xdroid/request/network/HttpError.java: -------------------------------------------------------------------------------- 1 | package com.xdroid.request.network; 2 | 3 | /** 4 | * Request error code 5 | * @author Robin 6 | * @since 2015-12-29 14:52:10 7 | */ 8 | public interface HttpError { 9 | 10 | public int ERROR_UNKNOW = 0x01, 11 | ERROR_NOT_NETWORK = 0x02, 12 | ERROR_SERVER = 0x03, 13 | ERROR_SOCKET_TIMEOUT = 0x04, 14 | ERROR_UNAUTHORIZED = 0x05, 15 | ERROR_REDIRECT = 0x06, 16 | ERROR_RESPONSE_NULL = 0x07, 17 | ERROR_PARSE = 0x08, 18 | ERROR_NO_CONNECTION = 0x09; 19 | } 20 | -------------------------------------------------------------------------------- /XDroidRequest/src/com/xdroid/request/interfaces/IResponseDelivery.java: -------------------------------------------------------------------------------- 1 | package com.xdroid.request.interfaces; 2 | 3 | import java.util.Map; 4 | 5 | import com.xdroid.request.base.Request; 6 | import com.xdroid.request.config.DataType; 7 | 8 | /** 9 | * Used to cache thread or request thread after the completion of the delivery data 10 | * @author Robin 11 | * @since 2015-05-08 18:04:42 12 | * @param 13 | */ 14 | public interface IResponseDelivery { 15 | /** 16 | * Parses a response from the network or cache and delivers it. 17 | */ 18 | public void deliveryResponse(Request request,Map headers ,T result, DataType dataType); 19 | 20 | } 21 | -------------------------------------------------------------------------------- /XDroidRequest/src/com/xdroid/request/cache/BitmapCache.java: -------------------------------------------------------------------------------- 1 | package com.xdroid.request.cache; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * Used to cache bitmap 7 | * @author Robin 8 | * @since 2016-01-19 15:12:40 9 | * 10 | */ 11 | public class BitmapCache implements Serializable { 12 | private static final long serialVersionUID = 1L; 13 | 14 | private byte[] bitmapBytes = null; 15 | private String name = null; 16 | 17 | public BitmapCache(byte[] bitmapBytes, String name) { 18 | this.bitmapBytes = bitmapBytes; 19 | this.name = name; 20 | } 21 | 22 | public byte[] getBitmapBytes() { 23 | return this.bitmapBytes; 24 | } 25 | 26 | public String getName() { 27 | return this.name; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /XDroidRequest/src/com/xdroid/request/network/HttpStack.java: -------------------------------------------------------------------------------- 1 | package com.xdroid.request.network; 2 | 3 | import java.io.IOException; 4 | import java.util.Map; 5 | 6 | import com.xdroid.request.base.Request; 7 | 8 | /** 9 | * Http request terminal, known to achieve class: 10 | * @author Robin 11 | * @since 2015-07-02 16:13:43 12 | * 13 | */ 14 | public interface HttpStack { 15 | /** 16 | * Let the Http request for a Request 17 | * 18 | * @param request 19 | * @param additionalHeaders Attached Http request header 20 | * @return A Http response 21 | */ 22 | public HttpResponse performRequest(Request request, 23 | Map additionalHeaders) throws IOException; 24 | 25 | } 26 | -------------------------------------------------------------------------------- /XDroidRequestExample/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 14 | 15 | 16 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | #*.apk 3 | *.ap_ 4 | 5 | # Files for the Dalvik VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # Generated files 12 | bin/ 13 | gen/ 14 | 15 | # Gradle files 16 | .gradle/ 17 | build/ 18 | /*/build/ 19 | 20 | # Local configuration file (sdk path, etc) 21 | local.properties 22 | 23 | # Proguard folder generated by Eclipse 24 | proguard/ 25 | 26 | # Log Files 27 | *.log 28 | /XDroidRequest/bin/* 29 | /XDroidRequest/gen/* 30 | /XDroidRequest/.classpath 31 | /XDroidRequest/.project 32 | /XDroidRequest/project.properties 33 | /XDroidRequest/.settings/ 34 | /XDroidRequestExample/bin/* 35 | /XDroidRequestExample/gen/* 36 | /XDroidRequestExample/.classpath 37 | /XDroidRequestExample/.project 38 | /XDroidRequestExample/project.properties 39 | /XDroidRequestExample/.settings/ 40 | -------------------------------------------------------------------------------- /XDroidRequestExample/src/com/xdroid/request/example/App.java: -------------------------------------------------------------------------------- 1 | package com.xdroid.request.example; 2 | 3 | import java.io.File; 4 | 5 | import com.xdroid.request.XRequest; 6 | 7 | import android.annotation.SuppressLint; 8 | import android.app.Application; 9 | 10 | public class App extends Application { 11 | 12 | @Override 13 | public void onCreate() { 14 | super.onCreate(); 15 | 16 | configXReqeustCache(); 17 | 18 | } 19 | 20 | @SuppressLint("SdCardPath") 21 | private void configXReqeustCache() { 22 | //磁盘缓存路径 23 | File DISK_CACHE_DIR_PATH = new File("/sdcard/xrequest/diskcache"); 24 | //磁盘缓存最大值 25 | int DISK_CACHE_MAX_SIZE = 30*1024*1024; 26 | 27 | //XRequest.initXRequest(getApplicationContext()); 28 | 29 | XRequest.initXRequest(getApplicationContext(), DISK_CACHE_MAX_SIZE, DISK_CACHE_DIR_PATH); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /XDroidRequest/src/com/xdroid/request/config/TimeController.java: -------------------------------------------------------------------------------- 1 | package com.xdroid.request.config; 2 | 3 | /** 4 | * control the expiration time and timeout 5 | * 6 | * @author Robin 7 | * @since 2015-05-07 20:17:47 8 | */ 9 | public class TimeController { 10 | 11 | private long expirationTime; 12 | 13 | private long timeout; 14 | 15 | public long getExpirationTime() { 16 | return expirationTime; 17 | } 18 | 19 | public void setExpirationTime(long expirationTime) { 20 | this.expirationTime = expirationTime; 21 | } 22 | 23 | public long getTimeout() { 24 | return timeout; 25 | } 26 | 27 | public void setTimeout(long timeout) { 28 | this.timeout = timeout; 29 | } 30 | 31 | @Override 32 | public String toString() { 33 | return "TimeController [expirationTime=" + expirationTime + ", timeout=" + timeout + "]"; 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /XDroidRequest/src/com/xdroid/request/retry/RetryPolicy.java: -------------------------------------------------------------------------------- 1 | package com.xdroid.request.retry; 2 | 3 | import com.xdroid.request.network.HttpException; 4 | 5 | /** 6 | * Retry policy for a request. 7 | * @author Robin 8 | * @since 2015-08-19 10:00:59 9 | */ 10 | public interface RetryPolicy { 11 | 12 | /** 13 | * Returns the current timeout 14 | */ 15 | public int getCurrentTimeout(); 16 | 17 | /** 18 | * Currently retry count 19 | * @return 20 | */ 21 | public int getCurrentRetryCount(); 22 | 23 | /** 24 | * Prepares for the next retry by applying a backoff to the timeout. 25 | * @param error The error code of the last attempt. 26 | * @throws HttpException In the event that the retry could not be performed 27 | */ 28 | public void retry(HttpException error) throws HttpException; 29 | } 30 | -------------------------------------------------------------------------------- /XDroidRequest/proguard-project.txt: -------------------------------------------------------------------------------- 1 | # To enable ProGuard in your project, edit project.properties 2 | # to define the proguard.config property as described in that file. 3 | # 4 | # Add project specific ProGuard rules here. 5 | # By default, the flags in this file are appended to flags specified 6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt 7 | # You can edit the include path and order by changing the ProGuard 8 | # include property in project.properties. 9 | # 10 | # For more details, see 11 | # http://developer.android.com/guide/developing/tools/proguard.html 12 | 13 | # Add any project specific keep options here: 14 | 15 | # If your project uses WebView with JS, uncomment the following 16 | # and specify the fully qualified class name to the JavaScript interface 17 | # class: 18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 19 | # public *; 20 | #} 21 | -------------------------------------------------------------------------------- /XDroidRequestExample/proguard-project.txt: -------------------------------------------------------------------------------- 1 | # To enable ProGuard in your project, edit project.properties 2 | # to define the proguard.config property as described in that file. 3 | # 4 | # Add project specific ProGuard rules here. 5 | # By default, the flags in this file are appended to flags specified 6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt 7 | # You can edit the include path and order by changing the ProGuard 8 | # include property in project.properties. 9 | # 10 | # For more details, see 11 | # http://developer.android.com/guide/developing/tools/proguard.html 12 | 13 | # Add any project specific keep options here: 14 | 15 | # If your project uses WebView with JS, uncomment the following 16 | # and specify the fully qualified class name to the JavaScript interface 17 | # class: 18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 19 | # public *; 20 | #} 21 | -------------------------------------------------------------------------------- /XDroidRequest/src/com/xdroid/request/RequestContext.java: -------------------------------------------------------------------------------- 1 | package com.xdroid.request; 2 | 3 | import com.xdroid.request.utils.AppUtils; 4 | 5 | import android.content.Context; 6 | import android.content.ContextWrapper; 7 | 8 | /** 9 | * Request context 10 | * 11 | * @author Robin 12 | * @since 2015-12-31 10:59:05 13 | * 14 | */ 15 | public class RequestContext extends ContextWrapper { 16 | 17 | private static RequestContext sContext; 18 | 19 | public RequestContext(Context base) { 20 | super(base); 21 | } 22 | 23 | public static void init(Context context) { 24 | String processName = AppUtils.getCurProcessName(context); 25 | String mainProcessName = context.getPackageName(); 26 | 27 | if (!mainProcessName.equals(processName)) { 28 | return; 29 | } 30 | if (sContext == null) { 31 | sContext = new RequestContext(context); 32 | } 33 | } 34 | 35 | public static RequestContext getInstance() { 36 | return sContext; 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /XDroidRequest/src/com/xdroid/request/ex/StringRequest.java: -------------------------------------------------------------------------------- 1 | package com.xdroid.request.ex; 2 | 3 | import com.xdroid.request.config.RequestCacheConfig; 4 | import com.xdroid.request.interfaces.OnRequestListener; 5 | import com.xdroid.request.response.NetworkResponse; 6 | import com.xdroid.request.response.Response; 7 | 8 | /** 9 | * Get char sequence from network 10 | * @author Robin 11 | * @since 2016-01-05 19:15:06 12 | * 13 | */ 14 | public class StringRequest extends MultipartRequest { 15 | 16 | public StringRequest() { 17 | super(); 18 | } 19 | 20 | public StringRequest(RequestCacheConfig cacheConfig, String url, String cacheKey, 21 | OnRequestListener onRequestListener) { 22 | super(cacheConfig, url, cacheKey, onRequestListener); 23 | } 24 | 25 | @Override 26 | public Response parseNetworkResponse(NetworkResponse response) { 27 | return Response.success(new String(response.data), response.headers); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /XDroidRequestExample/src/com/xdroid/request/example/log/ILogProcessor.aidl: -------------------------------------------------------------------------------- 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 | interface ILogProcessor { 21 | 22 | void reset(String buffer); 23 | void run(int type); 24 | void restart(int type); 25 | void stop(); 26 | void write(String file, String tag); 27 | } 28 | -------------------------------------------------------------------------------- /XDroidRequest/src/com/xdroid/request/cache/Entry.java: -------------------------------------------------------------------------------- 1 | package com.xdroid.request.cache; 2 | 3 | import java.io.Serializable; 4 | import java.util.Collections; 5 | import java.util.Map; 6 | 7 | /** 8 | * The cached data entity, including the request header and the request content 9 | * @author Robin 10 | * @since 2015-06-24 11:21:41 11 | */ 12 | @SuppressWarnings("serial") 13 | public class Entry implements Serializable{ 14 | 15 | /** Request's content for cache*/ 16 | public T result; 17 | /** Request's headers for cache */ 18 | public Map responseHeaders = Collections.emptyMap(); 19 | 20 | public Entry(T result, Map responseHeaders) { 21 | super(); 22 | this.result = result; 23 | this.responseHeaders = responseHeaders; 24 | } 25 | 26 | public T getResult() { 27 | return result; 28 | } 29 | 30 | public void setResult(T result) { 31 | this.result = result; 32 | } 33 | 34 | public Map getResponseHeaders() { 35 | return responseHeaders; 36 | } 37 | 38 | public void setResponseHeaders(Map responseHeaders) { 39 | this.responseHeaders = responseHeaders; 40 | } 41 | 42 | 43 | 44 | } 45 | -------------------------------------------------------------------------------- /XDroidRequest/src/com/xdroid/request/response/NetworkResponse.java: -------------------------------------------------------------------------------- 1 | package com.xdroid.request.response; 2 | 3 | import java.util.Collections; 4 | import java.util.Map; 5 | 6 | import com.xdroid.request.network.HttpStatus; 7 | 8 | /** 9 | * The Http response returned from the NetWork, 10 | * contains the response that is successful or failed, the request header, the response content, the HTTP status code 11 | * @author Robin 12 | * @since 2015-07-02 15:05:31 13 | */ 14 | public class NetworkResponse { 15 | 16 | public NetworkResponse(int statusCode, byte[] data, 17 | Map headers, boolean notModified) { 18 | this.statusCode = statusCode; 19 | this.data = data; 20 | this.headers = headers; 21 | this.notModified = notModified; 22 | } 23 | 24 | public NetworkResponse(byte[] data) { 25 | this(HttpStatus.SC_OK, data, Collections. emptyMap(), 26 | false); 27 | } 28 | 29 | public NetworkResponse(byte[] data, Map headers) { 30 | this(HttpStatus.SC_OK, data, headers, false); 31 | } 32 | 33 | public final int statusCode; 34 | 35 | public final byte[] data; 36 | 37 | public final Map headers; 38 | 39 | public final boolean notModified; // If the server returns 304 ( Not Modified ), the true 40 | } -------------------------------------------------------------------------------- /XDroidRequest/src/com/xdroid/request/utils/NetworkUtils.java: -------------------------------------------------------------------------------- 1 | package com.xdroid.request.utils; 2 | 3 | import android.content.Context; 4 | import android.net.ConnectivityManager; 5 | import android.net.NetworkInfo; 6 | 7 | /** 8 | * Provide some help about the network function 9 | * @author Robin 10 | * @since 2015/5/28 11:23. 11 | */ 12 | public class NetworkUtils { 13 | 14 | public static boolean checkNet(Context context) { 15 | ConnectivityManager cm = (ConnectivityManager) context 16 | .getSystemService(Context.CONNECTIVITY_SERVICE); 17 | NetworkInfo info = cm.getActiveNetworkInfo(); 18 | return info != null; 19 | } 20 | 21 | /*private static String getHeader(HttpResponse response, String key) { 22 | return response.getHeaders().get(key); 23 | } 24 | 25 | public static boolean isSupportRange(HttpResponse response) { 26 | if (TextUtils.equals(getHeader(response, "Accept-Ranges"), "bytes")) { 27 | return true; 28 | } 29 | String value = getHeader(response, "Content-Range"); 30 | return value != null && value.startsWith("bytes"); 31 | } 32 | 33 | public static boolean isGzipContent(HttpResponse response) { 34 | return TextUtils 35 | .equals(getHeader(response, "Content-Encoding"), "gzip"); 36 | }*/ 37 | } 38 | -------------------------------------------------------------------------------- /XDroidRequestExample/res/layout/log_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 21 | 26 | 27 | 31 | 32 | -------------------------------------------------------------------------------- /XDroidRequest/src/com/xdroid/request/interfaces/IRequestCacheManager.java: -------------------------------------------------------------------------------- 1 | package com.xdroid.request.interfaces; 2 | 3 | import java.io.File; 4 | 5 | import com.xdroid.request.base.Request; 6 | 7 | /** 8 | * Request cache manager interface 9 | * 10 | * @author Robin 11 | * @since 2015-12-30 20:34:42 12 | * 13 | */ 14 | public interface IRequestCacheManager { 15 | 16 | // ----------------------------------------Disk------------------------------------------- 17 | 18 | public File getDiskCacheDirectory(); 19 | 20 | public long getDiskCacheMaxSize(); 21 | 22 | public void setDiskCacheMaxSize(long maxSize); 23 | 24 | public long getAllDiskCacheSize(); 25 | 26 | public void deleteAllDiskCacheData(); 27 | 28 | public Boolean deleteOneDiskCacheData(String originalKey); 29 | 30 | public Boolean deleteOneDiskCacheData(Request request); 31 | 32 | public Boolean deleteOneDiskCacheData(Request request, String originalKey); 33 | 34 | public T getDataFromDiskCache(String originalKey); 35 | 36 | // ----------------------------------------Memory------------------------------------------- 37 | 38 | public void deleteOneMemoryCacheData(String key); 39 | 40 | public void deleteOneMemoryCacheData(Request request); 41 | 42 | public void deleteOneMemoryCacheData(Request request, String key); 43 | 44 | public void deleteAllMemoryCacheData(); 45 | 46 | public T getDataFromMemoryCache(String key); 47 | 48 | } 49 | -------------------------------------------------------------------------------- /XDroidRequestExample/src/com/xdroid/request/example/CityRootBean.java: -------------------------------------------------------------------------------- 1 | package com.xdroid.request.example; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * 测试用 城市实体类 7 | * @author Robin 8 | * @since 2015-11-11 14:26:36 9 | * 10 | */ 11 | public class CityRootBean implements Serializable{ 12 | private static final long serialVersionUID = 1L; 13 | 14 | private String errNum; 15 | private String retMsg; 16 | private T retData; 17 | 18 | public static class CityBean implements Serializable{ 19 | private static final long serialVersionUID = 1L; 20 | private String citylist; 21 | 22 | public String getCitylist() { 23 | return citylist; 24 | } 25 | 26 | public void setCitylist(String citylist) { 27 | this.citylist = citylist; 28 | } 29 | 30 | @Override 31 | public String toString() { 32 | return "CityBean [citylist=" + citylist + "]"; 33 | } 34 | 35 | } 36 | 37 | public String getErrNum() { 38 | return errNum; 39 | } 40 | 41 | public void setErrNum(String errNum) { 42 | this.errNum = errNum; 43 | } 44 | 45 | public String getRetMsg() { 46 | return retMsg; 47 | } 48 | 49 | public void setRetMsg(String retMsg) { 50 | this.retMsg = retMsg; 51 | } 52 | 53 | public T getRetData() { 54 | return retData; 55 | } 56 | 57 | public void setRetData(T retData) { 58 | this.retData = retData; 59 | } 60 | 61 | @Override 62 | public String toString() { 63 | return "CityRootBean [errNum=" + errNum + ", retMsg=" + retMsg + ", retData=" + retData + "]"; 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /XDroidRequest/src/com/xdroid/request/response/Response.java: -------------------------------------------------------------------------------- 1 | package com.xdroid.request.response; 2 | 3 | import java.util.Map; 4 | 5 | import com.xdroid.request.network.HttpException; 6 | 7 | /** 8 | * Http request response package type, containing the request header, request 9 | * content, error content of the request response 10 | * 11 | * @author Robin 12 | * @since 2015-07-02 15:07:13 13 | */ 14 | public class Response { 15 | /** 16 | * Http type of response 17 | */ 18 | public final T result; 19 | 20 | public final HttpException error; 21 | 22 | public final Map headers; 23 | 24 | public boolean isSuccess() { 25 | return error == null; 26 | } 27 | 28 | private Response(T result, Map headers) { 29 | this.result = result; 30 | this.headers = headers; 31 | this.error = null; 32 | } 33 | 34 | private Response(HttpException error) { 35 | this.result = null; 36 | this.headers = null; 37 | this.error = error; 38 | } 39 | 40 | /** 41 | * To return a successful HttpRespond 42 | * 43 | * @param result 44 | * Http type of response 45 | * @param headers 46 | * Request header information 47 | */ 48 | public static Response success(T result, Map headers) { 49 | return new Response(result, headers); 50 | } 51 | 52 | /** 53 | * To return a failed HttpRespond 54 | * 55 | * @param error 56 | */ 57 | public static Response error(HttpException error) { 58 | return new Response(error); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /XDroidRequestExample/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 20 | 23 | 24 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /XDroidRequest/src/com/xdroid/request/cache/MemoryCacheManager.java: -------------------------------------------------------------------------------- 1 | package com.xdroid.request.cache; 2 | 3 | import com.xdroid.request.cache.memorycache.LruCache; 4 | 5 | /** 6 | * Manage memory cache 7 | * @author Robin 8 | * @since 2015-05-07 23:18:22 9 | * @param 10 | * @param 11 | */ 12 | public class MemoryCacheManager { 13 | 14 | public static MemoryCacheManager mMemoryCacheManager; 15 | 16 | private LruCache mMemoryCache; 17 | 18 | public MemoryCacheManager(){ 19 | if (mMemoryCache==null) { 20 | mMemoryCache=new LruCache(CacheConfig.MEMORY_CACHE_MAX_SIZE){ 21 | @Override 22 | protected int sizeOf(KeyType key, ValueType value) { 23 | return super.sizeOf(key, value); 24 | } 25 | }; 26 | } 27 | } 28 | 29 | 30 | public static MemoryCacheManager getInstance() { 31 | if (mMemoryCacheManager == null) { 32 | mMemoryCacheManager = new MemoryCacheManager(); 33 | } 34 | return mMemoryCacheManager; 35 | } 36 | 37 | 38 | /** 39 | * set the data to cache 40 | * @param key 41 | * @param value 42 | */ 43 | public void setDataToMemoryCache(KeyType key,ValueType value){ 44 | if (getDataFromMemoryCache(key)==null) { 45 | mMemoryCache.put(key, value); 46 | } 47 | } 48 | 49 | /** 50 | * read the data from cache 51 | * @param key 52 | * @return 53 | */ 54 | public ValueType getDataFromMemoryCache(KeyType key){ 55 | return mMemoryCache.get(key); 56 | } 57 | 58 | public void deleteAllMemoryCacheData(){ 59 | mMemoryCache.evictAll(); 60 | } 61 | 62 | public void deleteOneMemoryCacheData(KeyType key){ 63 | mMemoryCache.remove(key); 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /XDroidRequest/src/com/xdroid/request/impl/OnRequestListenerAdapter.java: -------------------------------------------------------------------------------- 1 | package com.xdroid.request.impl; 2 | 3 | import java.io.File; 4 | import java.util.Map; 5 | 6 | import com.xdroid.request.base.Request; 7 | import com.xdroid.request.config.DataType; 8 | import com.xdroid.request.interfaces.OnRequestListener; 9 | import com.xdroid.request.network.HttpException; 10 | import com.xdroid.request.response.NetworkResponse; 11 | 12 | /** 13 | * implements "OnRequestListener" interface, if you need to rewrite a callback function, can realize this 14 | * @author Robin 15 | * @since 2015/5/27 18:55. 16 | */ 17 | public abstract class OnRequestListenerAdapter implements OnRequestListener { 18 | 19 | @Override 20 | public void onRequestPrepare(Request request) { 21 | } 22 | 23 | @Override 24 | public void onRequestFailed(Request request, HttpException httpException) { 25 | } 26 | 27 | @Override 28 | public void onRequestRetry(Request request, int currentRetryCount, HttpException previousError) { 29 | } 30 | 31 | @Override 32 | public void onRequestDownloadProgress(Request request, long transferredBytesSize, long totalSize) { 33 | } 34 | 35 | @Override 36 | public void onRequestUploadProgress(Request request, long transferredBytesSize, long totalSize, int currentFileIndex,File currentFile) { 37 | } 38 | 39 | @Override 40 | public void onRequestFinish(Request request, Map headers, T result) { 41 | } 42 | 43 | @Override 44 | public void onCacheDataLoadFinish(Request request, Map headers, T result) { 45 | } 46 | 47 | @Override 48 | public boolean onParseNetworkResponse(Request request, NetworkResponse networkResponse, T result) { 49 | return true; 50 | } 51 | 52 | @Override 53 | public void onDone(Request request, Map headers, T result, DataType dataType) { 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /XDroidRequestExample/src/com/xdroid/request/example/log/LogFormattedString.java: -------------------------------------------------------------------------------- 1 | package com.xdroid.request.example.log; 2 | 3 | import java.util.HashMap; 4 | 5 | import android.graphics.Typeface; 6 | import android.text.SpannableString; 7 | import android.text.style.ForegroundColorSpan; 8 | import android.text.style.StyleSpan; 9 | 10 | public class LogFormattedString extends SpannableString { 11 | public static final HashMap LABEL_COLOR_MAP; 12 | 13 | public LogFormattedString(String line) { 14 | super(line); 15 | 16 | try { 17 | if (line.length() < 4) { 18 | throw new RuntimeException(); 19 | } 20 | 21 | if (line.charAt(1) != '/') { 22 | throw new RuntimeException(); 23 | } 24 | 25 | Integer labelColor = LABEL_COLOR_MAP.get(line.charAt(0)); 26 | 27 | if (labelColor == null) { 28 | labelColor = LABEL_COLOR_MAP.get('E'); 29 | } 30 | 31 | setSpan(new ForegroundColorSpan(labelColor), 0, 1, 0); 32 | setSpan(new StyleSpan(Typeface.BOLD), 0, 1, 0); 33 | 34 | int leftIdx; 35 | 36 | if ((leftIdx = line.indexOf(':', 2)) >= 0) { 37 | setSpan(new ForegroundColorSpan(labelColor), 2, leftIdx, 0); 38 | setSpan(new StyleSpan(Typeface.ITALIC), 2, leftIdx, 0); 39 | } 40 | } catch (Exception e) { 41 | setSpan(new ForegroundColorSpan(0xffddaacc), 0, length(), 0); 42 | } 43 | } 44 | 45 | static { 46 | LABEL_COLOR_MAP = new HashMap(); 47 | LABEL_COLOR_MAP.put('D', 0xff9999ff); 48 | LABEL_COLOR_MAP.put('V', 0xffcccccc); 49 | LABEL_COLOR_MAP.put('I', 0xffeeeeee); 50 | LABEL_COLOR_MAP.put('E', 0xffff9999); 51 | LABEL_COLOR_MAP.put('W', 0xffffff99); 52 | } 53 | } -------------------------------------------------------------------------------- /XDroidRequest/src/com/xdroid/request/interfaces/IRequest.java: -------------------------------------------------------------------------------- 1 | package com.xdroid.request.interfaces; 2 | 3 | import java.io.File; 4 | import java.util.Map; 5 | 6 | import com.xdroid.request.cache.CacheData; 7 | import com.xdroid.request.cache.Entry; 8 | import com.xdroid.request.network.HttpException; 9 | import com.xdroid.request.response.NetworkResponse; 10 | 11 | /** 12 | * {@link com.xdroid.request.base.Request} 13 | * @author Robin 14 | * @since 2015-05-07 14:06:41 15 | */ 16 | public interface IRequest{ 17 | 18 | /** Do something before the request */ 19 | public void requestPrepare(); 20 | 21 | /** When request finished */ 22 | public void onRequestFinish(Map headers,T data); 23 | 24 | /** When request failed */ 25 | public void onRequestFailed(HttpException httpException); 26 | 27 | /** When request retry */ 28 | public void onRequestRetry(int currentRetryCount, HttpException previousError); 29 | 30 | /** Call this method to delivered current progress for request */ 31 | public void onRequestDownloadProgress(long transferredBytesSize, long totalSize); 32 | 33 | /** Call this method to delivered upload progress for request */ 34 | public void onRequestUploadProgress(long transferredBytesSize, long totalSize, int currentFileIndex, File currentFile); 35 | 36 | /** When cache data load finished */ 37 | public void onCacheDataLoadFinish(CacheData> cacheData); 38 | 39 | /** Get the current request's cache data */ 40 | public CacheData> getCache(String key); 41 | 42 | /** Parse the network response to an object */ 43 | public void onParseNetworkResponse(NetworkResponse networkResponse,T result); 44 | 45 | /** Get the request's cookie */ 46 | public String getCookie(); 47 | 48 | /** Manual call this method when the request finished , to release the same request in the "mWaitingRequests" map */ 49 | public void finish() ; 50 | 51 | } 52 | -------------------------------------------------------------------------------- /XDroidRequest/src/com/xdroid/request/interfaces/OnRequestListener.java: -------------------------------------------------------------------------------- 1 | package com.xdroid.request.interfaces; 2 | 3 | import java.io.File; 4 | import java.util.Map; 5 | 6 | import com.xdroid.request.base.Request; 7 | import com.xdroid.request.config.DataType; 8 | import com.xdroid.request.network.HttpException; 9 | import com.xdroid.request.response.NetworkResponse; 10 | 11 | /** 12 | * when data processed finish 13 | * 14 | * @author Robin 15 | * @since 2015-05-07 21:27:07 16 | */ 17 | public interface OnRequestListener { 18 | 19 | /** The preparation for the request */ 20 | public void onRequestPrepare(Request request); 21 | 22 | /** Call this method when request failed */ 23 | public void onRequestFailed(Request request, HttpException httpException); 24 | 25 | /** Call this method when request retry */ 26 | public void onRequestRetry(Request request, int currentRetryCount, HttpException previousError); 27 | 28 | /** Call this method to delivered current progress for request */ 29 | public void onRequestDownloadProgress(Request request, long transferredBytesSize, long totalSize); 30 | 31 | /** Call this method to delivered upload progress for request */ 32 | public void onRequestUploadProgress(Request request, long transferredBytesSize, long totalSize, int currentFileIndex, File currentFile); 33 | 34 | /** Call this method when request finished */ 35 | public void onRequestFinish(Request request, Map headers, T result); 36 | 37 | /** Call this method when cache data load finished */ 38 | public void onCacheDataLoadFinish(Request request, Map headers, T result); 39 | 40 | /** Parse the network response to an object */ 41 | public boolean onParseNetworkResponse(Request request, NetworkResponse networkResponse,T result); 42 | 43 | /** 44 | * When the request is completed or the cache data loaded ,call this method 45 | * , called only once, the final data delivery function 46 | */ 47 | public void onDone(Request request, Map headers, T result, DataType dataType); 48 | 49 | } 50 | -------------------------------------------------------------------------------- /XDroidRequest/src/com/xdroid/request/utils/AppUtils.java: -------------------------------------------------------------------------------- 1 | package com.xdroid.request.utils; 2 | 3 | import java.io.File; 4 | 5 | import android.app.ActivityManager; 6 | import android.content.Context; 7 | import android.content.pm.PackageInfo; 8 | import android.content.pm.PackageManager.NameNotFoundException; 9 | import android.os.Environment; 10 | import android.os.Process;; 11 | /** 12 | * APP helper 13 | * 14 | * @author Robin 15 | * @since 2015-12-31 10:03:05 16 | * 17 | */ 18 | public class AppUtils { 19 | 20 | public static int getAppVersion(Context context) { 21 | try { 22 | PackageInfo info = context.getPackageManager().getPackageInfo(context.getPackageName(), 0); 23 | return info.versionCode; 24 | } catch (NameNotFoundException e) { 25 | e.printStackTrace(); 26 | } 27 | return 1; 28 | } 29 | /** 30 | * According to the incoming a unique name for the path of the hard disk cache address. 31 | */ 32 | public static File getDiskCacheDir(Context context, String uniqueName) { 33 | String cachePath; 34 | if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) 35 | || !Environment.isExternalStorageRemovable()) { 36 | File cacheDir=context.getExternalCacheDir(); 37 | if (cacheDir!=null) { 38 | cachePath = cacheDir .getPath(); // /sdcard/Android/data//cache 39 | }else { 40 | cachePath = context.getCacheDir().getPath(); // /data/data//cache 41 | } 42 | 43 | } else { 44 | cachePath = context.getCacheDir().getPath(); // /data/data//cache 45 | } 46 | return new File(cachePath + File.separator + uniqueName); 47 | } 48 | 49 | public static String getCurProcessName(Context context) { 50 | int pid = Process.myPid(); 51 | ActivityManager mActivityManager = (ActivityManager) context.getSystemService("activity"); 52 | 53 | for (ActivityManager.RunningAppProcessInfo appProcess : mActivityManager.getRunningAppProcesses()) { 54 | if (appProcess.pid == pid) { 55 | return appProcess.processName; 56 | } 57 | } 58 | return null; 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /XDroidRequest/src/com/xdroid/request/network/HttpStatus.java: -------------------------------------------------------------------------------- 1 | package com.xdroid.request.network; 2 | 3 | /** 4 | * HTTP Status 5 | * 6 | * @author Robin 7 | * @since 2015-11-07 18:34:57 8 | * 9 | */ 10 | public interface HttpStatus { 11 | public int SC_ACCEPTED = 202; 12 | public int SC_BAD_GATEWAY = 502; 13 | public int SC_BAD_REQUEST = 400; 14 | public int SC_CONFLICT = 409; 15 | public int SC_CONTINUE = 100; 16 | public int SC_CREATED = 201; 17 | public int SC_EXPECTATION_FAILED = 417; 18 | public int SC_FAILED_DEPENDENCY = 424; 19 | public int SC_FORBIDDEN = 403; 20 | public int SC_GATEWAY_TIMEOUT = 504; 21 | public int SC_GONE = 410; 22 | public int SC_HTTP_VERSION_NOT_SUPPORTED = 505; 23 | public int SC_INSUFFICIENT_SPACE_ON_RESOURCE = 419; 24 | public int SC_INSUFFICIENT_STORAGE = 507; 25 | public int SC_INTERNAL_SERVER_ERROR = 500; 26 | public int SC_LENGTH_REQUIRED = 411; 27 | public int SC_LOCKED = 423; 28 | public int SC_METHOD_FAILURE = 420; 29 | public int SC_METHOD_NOT_ALLOWED = 405; 30 | public int SC_MOVED_PERMANENTLY = 301; 31 | public int SC_MOVED_TEMPORARILY = 302; 32 | public int SC_MULTIPLE_CHOICES = 300; 33 | public int SC_MULTI_STATUS = 207; 34 | public int SC_NON_AUTHORITATIVE_INFORMATION = 203; 35 | public int SC_NOT_ACCEPTABLE = 406; 36 | public int SC_NOT_FOUND = 404; 37 | public int SC_NOT_IMPLEMENTED = 501; 38 | public int SC_NOT_MODIFIED = 304; 39 | public int SC_NO_CONTENT = 204; 40 | public int SC_OK = 200; 41 | public int SC_PARTIAL_CONTENT = 206; 42 | public int SC_PAYMENT_REQUIRED = 402; 43 | public int SC_PRECONDITION_FAILED = 412; 44 | public int SC_PROCESSING = 102; 45 | public int SC_PROXY_AUTHENTICATION_REQUIRED = 407; 46 | public int SC_REQUESTED_RANGE_NOT_SATISFIABLE = 416; 47 | public int SC_REQUEST_TIMEOUT = 408; 48 | public int SC_REQUEST_TOO_LONG = 413; 49 | public int SC_REQUEST_URI_TOO_LONG = 414; 50 | public int SC_RESET_CONTENT = 205; 51 | public int SC_SEE_OTHER = 303; 52 | public int SC_SERVICE_UNAVAILABLE = 503; 53 | public int SC_SWITCHING_PROTOCOLS = 101; 54 | public int SC_TEMPORARY_REDIRECT = 307; 55 | public int SC_UNAUTHORIZED = 401; 56 | public int SC_UNPROCESSABLE_ENTITY = 422; 57 | public int SC_UNSUPPORTED_MEDIA_TYPE = 415; 58 | public int SC_USE_PROXY = 305; 59 | } 60 | -------------------------------------------------------------------------------- /XDroidRequest/src/com/xdroid/request/network/HttpResponse.java: -------------------------------------------------------------------------------- 1 | package com.xdroid.request.network; 2 | 3 | import java.io.InputStream; 4 | import java.io.Serializable; 5 | import java.util.Map; 6 | 7 | /** 8 | * Compatible with 6.0, is used to replace "org.apache.http.HttpResponse" 9 | * @author Robin 10 | * @since 2016-1-14 18:55:51 11 | * 12 | */ 13 | public class HttpResponse implements Serializable { 14 | 15 | private static final long serialVersionUID = 1L; 16 | 17 | private Map headers; 18 | 19 | private int responseCode; 20 | 21 | private String responseMessage; 22 | 23 | private InputStream contentStream; 24 | 25 | private String contentEncoding; 26 | 27 | private String contentType; 28 | 29 | private long contentLength; 30 | 31 | public Map getHeaders() { 32 | return headers; 33 | } 34 | 35 | public void setHeaders(Map headers) { 36 | this.headers = headers; 37 | } 38 | 39 | public int getResponseCode() { 40 | return responseCode; 41 | } 42 | 43 | public void setResponseCode(int responseCode) { 44 | this.responseCode = responseCode; 45 | } 46 | 47 | public String getResponseMessage() { 48 | return responseMessage; 49 | } 50 | 51 | public void setResponseMessage(String responseMessage) { 52 | this.responseMessage = responseMessage; 53 | } 54 | 55 | public InputStream getContentStream() { 56 | return contentStream; 57 | } 58 | 59 | public void setContentStream(InputStream contentStream) { 60 | this.contentStream = contentStream; 61 | } 62 | 63 | public String getContentEncoding() { 64 | return contentEncoding; 65 | } 66 | 67 | public void setContentEncoding(String contentEncoding) { 68 | this.contentEncoding = contentEncoding; 69 | } 70 | 71 | public String getContentType() { 72 | return contentType; 73 | } 74 | 75 | public void setContentType(String contentType) { 76 | this.contentType = contentType; 77 | } 78 | 79 | public long getContentLength() { 80 | return contentLength; 81 | } 82 | 83 | public void setContentLength(long contentLength) { 84 | this.contentLength = contentLength; 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /XDroidRequest/src/com/xdroid/request/delivered/IDelivery.java: -------------------------------------------------------------------------------- 1 | package com.xdroid.request.delivered; 2 | 3 | import java.io.File; 4 | 5 | import com.xdroid.request.base.Request; 6 | import com.xdroid.request.network.HttpException; 7 | import com.xdroid.request.response.Response; 8 | 9 | /** 10 | * The distributor, the result of the asynchronous thread to the UI thread 11 | * 12 | * @author Robin 13 | * @since 2015-07-02 14:49:51 14 | * 15 | */ 16 | public interface IDelivery { 17 | /** 18 | * Distribution request response result 19 | * 20 | * @param request 21 | * @param response 22 | */ 23 | public void postRequestResponse(Request request, Response response); 24 | 25 | /** 26 | * Distribute Failure events 27 | * 28 | * @param request 29 | * @param error 30 | */ 31 | public void postError(Request request, HttpException error); 32 | 33 | /** 34 | * Distribution to read the cached results response 35 | * @param request 36 | * @param cacheData 37 | */ 38 | public void postCacheResponse(Request request,T cacheData); 39 | 40 | /** 41 | * Prepare events at the start of the request 42 | * @param request 43 | */ 44 | public void postRequestPrepare(Request request); 45 | 46 | /** 47 | * Distribution to retry event 48 | * @param request 49 | * @param previousError An exception before 50 | */ 51 | public void postRequestRetry(Request request, int currentRetryCount, HttpException previousError); 52 | 53 | /** 54 | * Delivered current progress for request 55 | * @param request 56 | * @param transferredBytesSize 57 | * @param totalSize 58 | */ 59 | public void postRequestDownloadProgress(Request request, long transferredBytesSize, long totalSize); 60 | 61 | /** 62 | * Delivered upload progress for request 63 | * @param request 64 | * @param transferredBytesSize 65 | * @param totalSize 66 | * @param currentFileIndex The subscript is currently being uploaded file 67 | * @param currentFile Is currently being uploaded files 68 | */ 69 | public void postRequestUploadProgress(Request request, long transferredBytesSize, long totalSize, int currentFileIndex, File currentFile); 70 | 71 | } 72 | -------------------------------------------------------------------------------- /XDroidRequest/src/com/xdroid/request/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * usage 3 | * @author Robin 4 | * @since 2015-05-22 14:16:49 5 | * 6 | */ 7 | package com.xdroid.request; 8 | /* 9 | 10 | **XDroidRequest** 是一款网络请求框架,它的功能也许会适合你。这是本项目的第三版了,前两版由于扩展性问题一直不满意,思考来思考去还是觉得Google的Volley的扩展性最强,所以有了这个第三版 11 | 12 | ### Provide ### 13 | 14 | - 适配 Android6.0 ,不再使用HttpClient相关API 15 | - 一行代码发送请求,提供多种回调函数供选择, 16 | - 支持8种网络请求方式 GET,POST,PUT,DELETE,HEAD,OPTIONS,TRACE,PATCH 17 | - 支持请求的优先级设置,优先级高的将先于优先级低的发送请求 18 | - 支持取消请求,可以取消当前发送请求的“请求”(可自定义取消请求的依据条件),也可以取消请求队列中还未发送的请求 19 | - 支持多请求并发,多个请求同时发送,底层使用固定数量线程池,可设置线程池的大小 20 | - 支持重复请求的判断,当有重复的请求将挂起,等待第一个请求完成后,挂起的请求使用已经请求完毕的缓存,如果未开启缓存,则会继续请求网络 21 | - 支持请求失败重试,默认重试2次,重试超时时间会递增,递增速率可设置,默认为1倍递增 22 | - 支持多文件与大文件上传,可以与参数一起发送至服务器,提供上传进度回调 23 | - 支持大文件下载,提供下载进度回调 24 | - 支持发送JSON数据 25 | - 自动网络判定,可设置此时是否显示缓存数据 26 | - 请求结果自动解析,可泛型任何Java bean,默认实现了GSON解析,可自定义 27 | - 多种错误类型判定 28 | - 扩展性强,可自定义发送请求方式与解析请求结果 29 | - 支持强大的缓存控制 30 | - 支持缓存配置,可配置磁盘缓存路径,磁盘缓存最大值,磁盘缓存当前占有大小,磁盘缓存清理 31 | 内存缓存最大值大小,内存缓存清理 32 | - 支持缓存管理与控制,包括本地请求缓存一系列信息查询以及对缓存的手动操作 33 | 34 | ### About cache ### 35 | - XDroidRequest使用了二级缓存,内存缓存与磁盘缓存,内存缓存使用LruCache,磁盘缓存使用DiskLruCache 36 | - setShouldCache(true) ,一个开关控制是否使用缓存的功能 37 | - setUseCacheDataAnyway(false), 是否总是使用缓存,这个开关开启后,将每次首先从内存和本地查找缓存,有的话直接使用缓存, 38 | 请求会在后台执行,完成后会更新缓存。如果没有缓存将直接进行网络请求获取,完成后会更新缓存. 39 | - setUseCacheDataWhenRequestFailed(true) ,是否在请求失败后使用缓存数据,无网络属于请求失败,可以保证即使没有网络,或者 40 | 请求也有数据展示. 41 | - setUseCacheDataWhenTimeout(true) ,是否在请求超时后直接使用缓存,这里的超时时间并不是网络请求的超时时间,而是我们 42 | 设定一个时间,超过这个时间后,不管请求有没有完成都直接使用缓存,后台的请求完成后会自动更新缓存 43 | - setUseCacheDataWhenUnexpired(true),是否使用缓存当缓存未过期的时候,这个开关也是经常开启的开关,每个缓存都会对应一个过期时间,先从内存查找缓存,没有的话再从磁盘查找,有缓存且过期的话,将直接使用缓存数据,当过期之后会进行网络请求,请求完成后会更新内存缓存与磁盘。没有缓存将直接进行网络请求,请求完成后会更新内存与磁盘缓存 44 | - setRetryWhenRequestFailed(true) ,是否进行重试,当请求失败的时候,默认开启,重试2次,不需要重试功能的话可关闭 45 | - setNeverExpired(false); 设置缓存是否永不过期 46 | 47 | 48 | 多文件上传PHP代码: 49 | $v) 51 | { 52 | $uploadfile = './upload/'. basename($_FILES['file']['name'][$k]); 53 | if (move_uploaded_file($_FILES['file']['tmp_name'][$k], $uploadfile)) 54 | { 55 | echo "File : ", $_FILES['file']['name'][$k] ," is valid, and was successfully uploaded.\n"; 56 | } 57 | 58 | else 59 | { 60 | echo "Possible file : ", $_FILES['file']['name'][$k], " upload attack!\n"; 61 | } 62 | 63 | } 64 | 65 | echo "成功接收附加字段:". $_POST['file_name']; 66 | 67 | ?> 68 | 69 | 70 | */ -------------------------------------------------------------------------------- /XDroidRequest/src/com/xdroid/request/cache/diskcache/Util.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 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.Closeable; 20 | import java.io.File; 21 | import java.io.IOException; 22 | import java.io.Reader; 23 | import java.io.StringWriter; 24 | import java.nio.charset.Charset; 25 | 26 | /** Junk drawer of utility methods. */ 27 | final class Util { 28 | static final Charset US_ASCII = Charset.forName("US-ASCII"); 29 | static final Charset UTF_8 = Charset.forName("UTF-8"); 30 | 31 | private Util() { 32 | } 33 | 34 | static String readFully(Reader reader) throws IOException { 35 | try { 36 | StringWriter writer = new StringWriter(); 37 | char[] buffer = new char[1024]; 38 | int count; 39 | while ((count = reader.read(buffer)) != -1) { 40 | writer.write(buffer, 0, count); 41 | } 42 | return writer.toString(); 43 | } finally { 44 | reader.close(); 45 | } 46 | } 47 | 48 | /** 49 | * Deletes the contents of {@code dir}. Throws an IOException if any file 50 | * could not be deleted, or if {@code dir} is not a readable directory. 51 | */ 52 | static void deleteContents(File dir) throws IOException { 53 | File[] files = dir.listFiles(); 54 | if (files == null) { 55 | throw new IOException("not a readable directory: " + dir); 56 | } 57 | for (File file : files) { 58 | if (file.isDirectory()) { 59 | deleteContents(file); 60 | } 61 | if (!file.delete()) { 62 | throw new IOException("failed to delete file: " + file); 63 | } 64 | } 65 | } 66 | 67 | static void closeQuietly(/*Auto*/Closeable closeable) { 68 | if (closeable != null) { 69 | try { 70 | closeable.close(); 71 | } catch (RuntimeException rethrown) { 72 | throw rethrown; 73 | } catch (Exception ignored) { 74 | } 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /XDroidRequest/src/com/xdroid/request/ex/DownloadRequest.java: -------------------------------------------------------------------------------- 1 | package com.xdroid.request.ex; 2 | 3 | import java.io.File; 4 | import java.io.FileNotFoundException; 5 | import java.io.FileOutputStream; 6 | import java.io.IOException; 7 | 8 | import com.xdroid.request.config.HttpMethod; 9 | import com.xdroid.request.config.Priority; 10 | import com.xdroid.request.config.RequestCacheConfig; 11 | import com.xdroid.request.interfaces.OnRequestListener; 12 | import com.xdroid.request.response.NetworkResponse; 13 | import com.xdroid.request.response.Response; 14 | import com.xdroid.request.utils.CLog; 15 | 16 | import android.text.TextUtils; 17 | 18 | /** 19 | * Download request 20 | * @author Robin 21 | * @since 2016-1-14 18:53:03 22 | * 23 | */ 24 | public class DownloadRequest extends MultipartRequest { 25 | 26 | private String mDownloadPath; 27 | private String mFileName; 28 | 29 | public DownloadRequest(String downloadPath,String fileName) { 30 | super(); 31 | this.mDownloadPath = downloadPath; 32 | this.mFileName = fileName; 33 | 34 | setPriority(Priority.NORMAL); 35 | setHttpMethod(HttpMethod.GET); 36 | } 37 | 38 | public DownloadRequest(RequestCacheConfig cacheConfig, String url, String cacheKey, String downloadPath,String fileName, 39 | OnRequestListener onRequestListener) { 40 | super(cacheConfig, url, cacheKey, onRequestListener); 41 | 42 | setPriority(Priority.NORMAL); 43 | setHttpMethod(HttpMethod.GET); 44 | setRequestParams(new RequestParams()); 45 | 46 | this.mDownloadPath = downloadPath; 47 | this.mFileName = fileName; 48 | } 49 | 50 | @Override 51 | public Response parseNetworkResponse(NetworkResponse response) { 52 | File downloadFile = null; 53 | try { 54 | byte[] data = response.data; 55 | //convert array of bytes into file 56 | File directory = new File(mDownloadPath); 57 | if (!directory.exists()) { 58 | directory.mkdir(); 59 | } 60 | 61 | String path = mDownloadPath; 62 | if (!TextUtils.isEmpty(mFileName)) { 63 | path = mDownloadPath+File.separator+mFileName; 64 | } 65 | FileOutputStream fileOuputStream = new FileOutputStream(path); 66 | fileOuputStream.write(data); 67 | fileOuputStream.close(); 68 | downloadFile = new File(path); 69 | } catch (FileNotFoundException e) { 70 | e.printStackTrace(); 71 | CLog.e("Download directory %s is not exsit",mDownloadPath); 72 | } catch (IOException e) { 73 | e.printStackTrace(); 74 | } 75 | 76 | return Response.success(downloadFile, response.headers); 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /XDroidRequest/src/com/xdroid/request/network/PoolingByteArrayOutputStream.java: -------------------------------------------------------------------------------- 1 | package com.xdroid.request.network; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.IOException; 5 | 6 | /** 7 | * Cache write stream 8 | */ 9 | public class PoolingByteArrayOutputStream extends ByteArrayOutputStream { 10 | /** 11 | * If the {@link #PoolingByteArrayOutputStream(ByteArrayPool)} constructor 12 | * is called, this is the default size to which the underlying byte array is 13 | * initialized. 14 | */ 15 | private static final int DEFAULT_SIZE = 256; 16 | 17 | private final ByteArrayPool mPool; 18 | 19 | /** 20 | * Constructs a new PoolingByteArrayOutputStream with a default size. If 21 | * more bytes are written to this instance, the underlying byte array will 22 | * expand. 23 | */ 24 | public PoolingByteArrayOutputStream(ByteArrayPool pool) { 25 | this(pool, DEFAULT_SIZE); 26 | } 27 | 28 | /** 29 | * Constructs a new {@code ByteArrayOutputStream} with a default size of 30 | * {@code size} bytes. If more than {@code size} bytes are written to this 31 | * instance, the underlying byte array will expand. 32 | * 33 | * @param size 34 | * initial size for the underlying byte array. The value will be 35 | * pinned to a default minimum size. 36 | */ 37 | public PoolingByteArrayOutputStream(ByteArrayPool pool, int size) { 38 | mPool = pool; 39 | buf = mPool.getBuf(Math.max(size, DEFAULT_SIZE)); 40 | } 41 | 42 | @Override 43 | public void close() throws IOException { 44 | mPool.returnBuf(buf); 45 | buf = null; 46 | super.close(); 47 | } 48 | 49 | @Override 50 | public void finalize() { 51 | mPool.returnBuf(buf); 52 | } 53 | 54 | /** 55 | * Ensures there is enough space in the buffer for the given number of 56 | * additional bytes. 57 | */ 58 | private void expand(int i) { 59 | /* Can the buffer handle @i more bytes, if not expand it */ 60 | if (count + i <= buf.length) { 61 | return; 62 | } 63 | byte[] newbuf = mPool.getBuf((count + i) * 2); 64 | System.arraycopy(buf, 0, newbuf, 0, count); 65 | mPool.returnBuf(buf); 66 | buf = newbuf; 67 | } 68 | 69 | @Override 70 | public synchronized void write(byte[] buffer, int offset, int len) { 71 | expand(len); 72 | super.write(buffer, offset, len); 73 | } 74 | 75 | @Override 76 | public synchronized void write(int oneByte) { 77 | expand(1); 78 | super.write(oneByte); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /XDroidRequest/src/com/xdroid/request/retry/DefaultRetryPolicyImpl.java: -------------------------------------------------------------------------------- 1 | package com.xdroid.request.retry; 2 | 3 | import com.xdroid.request.network.HttpException; 4 | import com.xdroid.request.utils.CLog; 5 | 6 | /** 7 | * Default retry policy for request. 8 | * @author Robin 9 | * @since 2015-08-19 10:08:59 10 | * 11 | */ 12 | public class DefaultRetryPolicyImpl implements RetryPolicy { 13 | private int mCurrentTimeoutMs; 14 | 15 | private int mCurrentRetryCount; 16 | 17 | private final int mMaxNumRetries; 18 | 19 | private final float mBackoffMultiplier; 20 | 21 | public static final int DEFAULT_TIMEOUT_MS = 2500; 22 | 23 | public static final int DEFAULT_MAX_RETRIES = 2; 24 | 25 | public static final float DEFAULT_BACKOFF_MULT = 1f; 26 | 27 | /*================================================================== 28 | * Constructor 29 | *================================================================== 30 | */ 31 | 32 | public DefaultRetryPolicyImpl() { 33 | this(DEFAULT_TIMEOUT_MS, DEFAULT_MAX_RETRIES, DEFAULT_BACKOFF_MULT); 34 | } 35 | 36 | public DefaultRetryPolicyImpl(int initialTimeoutMs, int maxNumRetries, float backoffMultiplier) { 37 | mCurrentTimeoutMs = initialTimeoutMs; 38 | mMaxNumRetries = maxNumRetries; 39 | mBackoffMultiplier = backoffMultiplier; 40 | } 41 | 42 | /*================================================================== 43 | * Override RetryPolicy 44 | *================================================================== 45 | */ 46 | 47 | @Override 48 | public void retry(HttpException error) throws HttpException { 49 | mCurrentRetryCount++; 50 | mCurrentTimeoutMs += (mCurrentTimeoutMs * mBackoffMultiplier); 51 | if (!canContinueToTry()) { 52 | throw error; 53 | } 54 | 55 | CLog.w("request failed , is to try the request again,current retry count = %s , current timeout = %s", mCurrentRetryCount,mCurrentTimeoutMs ); 56 | 57 | } 58 | 59 | protected boolean canContinueToTry () { 60 | return mCurrentRetryCount <= mMaxNumRetries; 61 | } 62 | 63 | 64 | public float getBackoffMultiplier() { 65 | return mBackoffMultiplier; 66 | } 67 | 68 | /*================================================================== 69 | * Getter and Setter 70 | *================================================================== 71 | */ 72 | 73 | @Override 74 | public int getCurrentTimeout() { 75 | return mCurrentTimeoutMs; 76 | } 77 | 78 | @Override 79 | public int getCurrentRetryCount() { 80 | return mCurrentRetryCount; 81 | } 82 | 83 | 84 | } 85 | -------------------------------------------------------------------------------- /XDroidRequest/src/com/xdroid/request/network/HTTPSTrustManager.java: -------------------------------------------------------------------------------- 1 | package com.xdroid.request.network; 2 | 3 | import java.security.KeyManagementException; 4 | import java.security.NoSuchAlgorithmException; 5 | import java.security.SecureRandom; 6 | import java.security.cert.X509Certificate; 7 | 8 | import javax.net.ssl.HostnameVerifier; 9 | import javax.net.ssl.HttpsURLConnection; 10 | import javax.net.ssl.SSLContext; 11 | import javax.net.ssl.SSLSession; 12 | import javax.net.ssl.TrustManager; 13 | import javax.net.ssl.X509TrustManager; 14 | 15 | /** 16 | * HTTPS Kit 17 | */ 18 | public class HTTPSTrustManager implements X509TrustManager { 19 | 20 | private static TrustManager[] trustManagers; 21 | private static final X509Certificate[] _AcceptedIssuers = new X509Certificate[]{}; 22 | 23 | @Override 24 | public void checkClientTrusted( 25 | java.security.cert.X509Certificate[] x509Certificates, String s) 26 | throws java.security.cert.CertificateException { 27 | // To change body of implemented methods use File | Settings | File 28 | // Templates. 29 | } 30 | 31 | @Override 32 | public void checkServerTrusted( 33 | java.security.cert.X509Certificate[] x509Certificates, String s) 34 | throws java.security.cert.CertificateException { 35 | // To change body of implemented methods use File | Settings | File 36 | // Templates. 37 | } 38 | 39 | public boolean isClientTrusted(X509Certificate[] chain) { 40 | return true; 41 | } 42 | 43 | public boolean isServerTrusted(X509Certificate[] chain) { 44 | return true; 45 | } 46 | 47 | @Override 48 | public X509Certificate[] getAcceptedIssuers() { 49 | return _AcceptedIssuers; 50 | } 51 | 52 | public static void allowAllSSL() { 53 | HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() { 54 | @Override 55 | public boolean verify(String arg0, SSLSession arg1) { 56 | return true; 57 | } 58 | }); 59 | 60 | SSLContext context = null; 61 | if (trustManagers == null) { 62 | trustManagers = new TrustManager[]{new HTTPSTrustManager()}; 63 | } 64 | 65 | try { 66 | context = SSLContext.getInstance("TLS"); 67 | context.init(null, trustManagers, new SecureRandom()); 68 | } catch (NoSuchAlgorithmException e) { 69 | e.printStackTrace(); 70 | } catch (KeyManagementException e) { 71 | e.printStackTrace(); 72 | } 73 | HttpsURLConnection.setDefaultSSLSocketFactory(context 74 | .getSocketFactory()); 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /XDroidRequest/src/com/xdroid/request/network/HttpException.java: -------------------------------------------------------------------------------- 1 | package com.xdroid.request.network; 2 | 3 | /** 4 | * HTTP request exception 5 | * 6 | * @author Robin 7 | * @since 2015-07-02 15:10:49 8 | */ 9 | @SuppressWarnings("serial") 10 | public class HttpException extends Exception { 11 | 12 | /** Http request error code */ 13 | private int mHttpErrorCode = HttpError.ERROR_UNKNOW; 14 | 15 | /** Http request error text */ 16 | private String mHttpErrorText; 17 | 18 | public HttpException() { 19 | } 20 | 21 | public HttpException(String exceptionMessage,int httpErrorCode) { 22 | super(exceptionMessage); 23 | this.mHttpErrorCode = httpErrorCode; 24 | this.mHttpErrorText = exceptionMessage; 25 | } 26 | 27 | public HttpException(String exceptionMessage, Throwable reason) { 28 | super(exceptionMessage, reason); 29 | this.mHttpErrorText = exceptionMessage; 30 | } 31 | 32 | public HttpException(String exceptionMessage) { 33 | super(exceptionMessage); 34 | this.mHttpErrorText = exceptionMessage; 35 | } 36 | 37 | /*public HttpException(Throwable cause) { 38 | super(cause); 39 | }*/ 40 | 41 | public int getHttpErrorCode() { 42 | return mHttpErrorCode; 43 | } 44 | 45 | public void setHttpErrorCode(int httpErrorCode) { 46 | this.mHttpErrorCode = httpErrorCode; 47 | } 48 | 49 | 50 | public String getHttpErrorText() { 51 | return mHttpErrorText; 52 | } 53 | 54 | public void setHttpErrorText(String httpErrorText) { 55 | this.mHttpErrorText = httpErrorText; 56 | } 57 | 58 | @Override 59 | public String toString() { 60 | String errorCodeText = ""; 61 | switch (mHttpErrorCode) { 62 | case HttpError.ERROR_NOT_NETWORK: 63 | errorCodeText = "ERROR_NOT_NETWORK"; 64 | break; 65 | case HttpError.ERROR_REDIRECT: 66 | errorCodeText = "ERROR_REDIRECT"; 67 | break; 68 | case HttpError.ERROR_RESPONSE_NULL: 69 | errorCodeText = "ERROR_RESPONSE_NULL"; 70 | break; 71 | case HttpError.ERROR_SERVER: 72 | errorCodeText = "ERROR_SERVER"; 73 | break; 74 | case HttpError.ERROR_SOCKET_TIMEOUT: 75 | errorCodeText = "ERROR_SOCKET_TIMEOUT"; 76 | break; 77 | case HttpError.ERROR_UNAUTHORIZED: 78 | errorCodeText = "ERROR_UNAUTHORIZED"; 79 | break; 80 | case HttpError.ERROR_UNKNOW: 81 | errorCodeText = "ERROR_UNKNOW"; 82 | break; 83 | case HttpError.ERROR_NO_CONNECTION: 84 | errorCodeText = "ERROR_NO_CONNECTION"; 85 | break; 86 | case HttpError.ERROR_PARSE: 87 | errorCodeText = "ERROR_PARSE"; 88 | break; 89 | default: 90 | errorCodeText = "ERROR_UNKNOW"; 91 | break; 92 | } 93 | return "HttpException [HttpErrorCode = " + mHttpErrorCode +", HttpErrorCodeText = "+errorCodeText+ ", HttpErrorText = "+getHttpErrorText()+"]"; 94 | } 95 | 96 | 97 | 98 | } 99 | -------------------------------------------------------------------------------- /XDroidRequest/src/com/xdroid/request/cache/CacheData.java: -------------------------------------------------------------------------------- 1 | package com.xdroid.request.cache; 2 | 3 | import java.io.Serializable; 4 | import java.text.SimpleDateFormat; 5 | 6 | import com.xdroid.request.utils.CLog; 7 | 8 | import android.annotation.SuppressLint; 9 | 10 | /** 11 | * define the cache data entity 12 | * 13 | * @author Robin 14 | * @since 2015-05-08 10:06:46 15 | */ 16 | @SuppressWarnings("serial") 17 | public class CacheData implements Serializable { 18 | 19 | /** 20 | * will storage's data 21 | */ 22 | private CacheDataType entry; 23 | 24 | /** 25 | * the data expired time 26 | */ 27 | private long expirationTime; 28 | 29 | /** 30 | * the data write to cache time 31 | */ 32 | private long writeTime; 33 | 34 | /** 35 | * Whether never expired 36 | */ 37 | private boolean isNeverExpiry; 38 | 39 | public CacheData(CacheDataType entry, long expirationTime, long writeTime) { 40 | super(); 41 | this.entry = entry; 42 | this.expirationTime = expirationTime; 43 | this.writeTime = writeTime; 44 | } 45 | 46 | public CacheData(CacheDataType data, long expirationTime, long writeTime, boolean isNeverExpiry) { 47 | super(); 48 | this.entry = data; 49 | this.expirationTime = expirationTime; 50 | this.writeTime = writeTime; 51 | this.isNeverExpiry = isNeverExpiry; 52 | } 53 | 54 | public CacheDataType getEntry() { 55 | return entry; 56 | } 57 | 58 | public void setEntry(CacheDataType data) { 59 | this.entry = data; 60 | } 61 | 62 | public long getExpirationTime() { 63 | return expirationTime; 64 | } 65 | 66 | public void setExpirationTime(long expirationTime) { 67 | this.expirationTime = expirationTime; 68 | } 69 | 70 | public long getWriteTime() { 71 | return writeTime; 72 | } 73 | 74 | public void setWriteTime(long writeTime) { 75 | this.writeTime = writeTime; 76 | } 77 | 78 | public boolean isNeverExpiry() { 79 | return isNeverExpiry; 80 | } 81 | 82 | public void setNeverExpiry(boolean isNeverExpiry) { 83 | this.isNeverExpiry = isNeverExpiry; 84 | } 85 | 86 | /** 87 | * check out the data is or not expired 88 | * 89 | * @return 90 | */ 91 | public Boolean isExpired() { 92 | if (isNeverExpiry) { 93 | return false; 94 | } 95 | 96 | if (writeTime <= 0) { 97 | return true; 98 | } 99 | if (expirationTime <= 0) { 100 | return true; 101 | } 102 | long intervalTime = System.currentTimeMillis() - writeTime; 103 | String format = "yyyy-MM-dd HH:mm"; 104 | String currentTimeStr = getStringByFormat(System.currentTimeMillis(), format); 105 | String writeTimeStr = getStringByFormat(writeTime, format); 106 | CLog.d("currentTime:%s,writeTime:%s,interval:%s s", (Object)currentTimeStr, writeTimeStr , intervalTime/1000); 107 | 108 | if (intervalTime < expirationTime) { 109 | return false; 110 | } else { 111 | // expired 112 | return true; 113 | } 114 | } 115 | 116 | @SuppressLint("SimpleDateFormat") 117 | private static String getStringByFormat(long milliseconds,String format) { 118 | String thisDateTime = null; 119 | try { 120 | SimpleDateFormat mSimpleDateFormat = new SimpleDateFormat(format); 121 | thisDateTime = mSimpleDateFormat.format(milliseconds); 122 | } catch (Exception e) { 123 | e.printStackTrace(); 124 | } 125 | return thisDateTime; 126 | } 127 | 128 | } 129 | -------------------------------------------------------------------------------- /XDroidRequest/src/com/xdroid/request/ex/MultipartGsonRequest.java: -------------------------------------------------------------------------------- 1 | package com.xdroid.request.ex; 2 | 3 | import java.lang.reflect.Type; 4 | import java.util.ArrayList; 5 | import java.util.regex.Matcher; 6 | import java.util.regex.Pattern; 7 | 8 | import com.google.gson.Gson; 9 | import com.google.gson.JsonArray; 10 | import com.google.gson.JsonElement; 11 | import com.google.gson.JsonParser; 12 | import com.xdroid.request.config.RequestCacheConfig; 13 | import com.xdroid.request.interfaces.OnRequestListener; 14 | import com.xdroid.request.response.NetworkResponse; 15 | import com.xdroid.request.response.Response; 16 | import com.xdroid.request.utils.CLog; 17 | import com.xdroid.request.utils.GenericsUtils; 18 | 19 | import android.text.TextUtils; 20 | 21 | /** 22 | * Parse the result by "GSON" 23 | * 24 | * @author Robin 25 | * @since 2016-01-07 19:55:16 26 | * 27 | * @param 28 | */ 29 | public class MultipartGsonRequest extends MultipartRequest { 30 | 31 | private Type mBeanType; 32 | 33 | public MultipartGsonRequest() { 34 | super(); 35 | } 36 | 37 | public MultipartGsonRequest(RequestCacheConfig cacheConfig, String url, String cacheKey, OnRequestListener onRequestListener) { 38 | super(cacheConfig, url, cacheKey, onRequestListener); 39 | mBeanType = GenericsUtils.getBeanType(onRequestListener); 40 | } 41 | 42 | @SuppressWarnings("unchecked") 43 | @Override 44 | public Response parseNetworkResponse(NetworkResponse response) { 45 | String result = new String(response.data); 46 | 47 | CLog.d("[Original String Data]:%s", result); 48 | 49 | //Because Android Studio cannot print string contains special characters, so here to filter out the special characters 50 | if (!TextUtils.isEmpty(result)) { 51 | Pattern CRLF = Pattern.compile("(\r\n|\r|\n|\n\r|\t)"); 52 | Matcher matcher = CRLF.matcher(result); 53 | result = matcher.replaceAll(""); 54 | CLog.d("[Filter the special characters of the original character data]:%s", result); 55 | } 56 | 57 | if (mBeanType.equals(String.class)) { 58 | T parseResult = (T) result; 59 | CLog.d("parse network response complete"); 60 | super.onParseNetworkResponse(response, parseResult); 61 | 62 | return Response.success(parseResult, response.headers); 63 | } 64 | 65 | if (result.startsWith("[") && result.endsWith("]")) { 66 | T parseResult = (T) fromJsonList(result, mBeanType); 67 | CLog.d("parse network response complete"); 68 | super.onParseNetworkResponse(response, parseResult); 69 | 70 | return Response.success(parseResult, response.headers); 71 | } 72 | if (result.startsWith("{") && result.endsWith("}")) { 73 | T parseResult = (T) fromJsonObject(result, mBeanType); 74 | CLog.d("parse network response complete"); 75 | super.onParseNetworkResponse(response, parseResult); 76 | 77 | return Response.success(parseResult, response.headers); 78 | } 79 | return null; 80 | } 81 | 82 | public X fromJsonObject(String json, Type cls) { 83 | Gson gson = new Gson(); 84 | X bean = gson.fromJson(json, cls); 85 | return bean; 86 | } 87 | 88 | @SuppressWarnings("unchecked") 89 | public ArrayList fromJsonList(String json, Type cls) { 90 | Gson gson = new Gson(); 91 | ArrayList mList = new ArrayList(); 92 | JsonArray array = new JsonParser().parse(json).getAsJsonArray(); 93 | for (final JsonElement elem : array) { 94 | mList.add((X) gson.fromJson(elem, cls)); 95 | } 96 | return mList; 97 | } 98 | } -------------------------------------------------------------------------------- /XDroidRequestExample/src/com/xdroid/request/example/RecipeRootBean.java: -------------------------------------------------------------------------------- 1 | package com.xdroid.request.example; 2 | 3 | import java.io.Serializable; 4 | /** 5 | * 测试用 食谱实体类 6 | * @author Robin 7 | * @since 2015-11-27 11:45:55 8 | * 9 | */ 10 | import java.util.List; 11 | public class RecipeRootBean implements Serializable { 12 | private static final long serialVersionUID = 1L; 13 | 14 | private String status; 15 | private List tngou; 16 | 17 | public static class RecipeBean implements Serializable{ 18 | private static final long serialVersionUID = 1L; 19 | 20 | private String count; 21 | private String description; 22 | private String fcount; 23 | private String food; 24 | private String id; 25 | private String images; 26 | private String img; 27 | private String keywords; 28 | private String message; 29 | private String name; 30 | private String rcount; 31 | 32 | public String getCount() { 33 | return count; 34 | } 35 | 36 | public void setCount(String count) { 37 | this.count = count; 38 | } 39 | 40 | public String getDescription() { 41 | return description; 42 | } 43 | 44 | public void setDescription(String description) { 45 | this.description = description; 46 | } 47 | 48 | public String getFcount() { 49 | return fcount; 50 | } 51 | 52 | public void setFcount(String fcount) { 53 | this.fcount = fcount; 54 | } 55 | 56 | public String getFood() { 57 | return food; 58 | } 59 | 60 | public void setFood(String food) { 61 | this.food = food; 62 | } 63 | 64 | public String getId() { 65 | return id; 66 | } 67 | 68 | public void setId(String id) { 69 | this.id = id; 70 | } 71 | 72 | public String getImages() { 73 | return images; 74 | } 75 | 76 | public void setImages(String images) { 77 | this.images = images; 78 | } 79 | 80 | public String getImg() { 81 | return img; 82 | } 83 | 84 | public void setImg(String img) { 85 | this.img = img; 86 | } 87 | 88 | public String getKeywords() { 89 | return keywords; 90 | } 91 | 92 | public void setKeywords(String keywords) { 93 | this.keywords = keywords; 94 | } 95 | 96 | public String getMessage() { 97 | return message; 98 | } 99 | 100 | public void setMessage(String message) { 101 | this.message = message; 102 | } 103 | 104 | public String getName() { 105 | return name; 106 | } 107 | 108 | public void setName(String name) { 109 | this.name = name; 110 | } 111 | 112 | public String getRcount() { 113 | return rcount; 114 | } 115 | 116 | public void setRcount(String rcount) { 117 | this.rcount = rcount; 118 | } 119 | 120 | @Override 121 | public String toString() { 122 | return "CategoryRootBean [count=" + count + ", description=" + description + ", fcount=" + fcount + ", food=" 123 | + food + ", id=" + id + ", images=" + images + ", img=" + img + ", keywords=" + keywords + ", message=" 124 | + message + ", name=" + name + ", rcount=" + rcount + "]"; 125 | } 126 | } 127 | 128 | public String getStatus() { 129 | return status; 130 | } 131 | 132 | public void setStatus(String status) { 133 | this.status = status; 134 | } 135 | 136 | public List getTngou() { 137 | return tngou; 138 | } 139 | 140 | public void setTngou(List tngou) { 141 | this.tngou = tngou; 142 | } 143 | 144 | @Override 145 | public String toString() { 146 | return "RecipeRootBean [status=" + status + ", tngou=" + tngou + "]"; 147 | } 148 | 149 | 150 | } 151 | -------------------------------------------------------------------------------- /XDroidRequest/src/com/xdroid/request/interfaces/IXReqeust.java: -------------------------------------------------------------------------------- 1 | package com.xdroid.request.interfaces; 2 | 3 | import java.io.File; 4 | 5 | import com.xdroid.request.base.Request; 6 | import com.xdroid.request.config.RequestCacheConfig; 7 | import com.xdroid.request.ex.RequestParams; 8 | 9 | /** 10 | * Provider method for "XRequest" 11 | * 12 | * @author Robin 13 | * @since 2015-08-13 16:53:31 14 | * @param 15 | * Listen callback type 16 | * 17 | */ 18 | public interface IXReqeust { 19 | 20 | /** 21 | * Best during application initialization calls only once 22 | * 23 | * @param threadPoolSize 24 | */ 25 | public void setRequestThreadPoolSize(int threadPoolSize); 26 | 27 | /** 28 | * Add a request to queue to execute 29 | * 30 | * @param request 31 | * Target request 32 | */ 33 | public void addToRequestQueue(Request request); 34 | 35 | /** 36 | * Create a default cache configuration 37 | * 38 | * @return 39 | */ 40 | public RequestCacheConfig getDefaultCacheConfig(); 41 | 42 | /** 43 | * Create a no cache configuration 44 | * 45 | * @return 46 | */ 47 | public RequestCacheConfig getNoCacheConfig(); 48 | 49 | /** 50 | * To cancel a request that is requesting 51 | * 52 | * @param request 53 | */ 54 | public void cancelRequest(Request request); 55 | 56 | /** 57 | * Cancel all of this request in the request queue , not including is 58 | * requested 59 | * 60 | * @param request 61 | * Current instance of request 62 | * @param tag 63 | * If there is no special Settings, then introduction the 64 | * instance of activity 65 | */ 66 | public void cancelAllRequestInQueueByTag(Object tag); 67 | 68 | /** 69 | * Start the request,start the thread pool 70 | */ 71 | public void start(); 72 | 73 | /** 74 | * Close the request, quit all threads, release the request queue 75 | */ 76 | public void shutdown(); 77 | 78 | /* 79 | * ======================================================================= 80 | * GET 81 | * ======================================================================= 82 | */ 83 | 84 | public Request sendGet(Object tag, String url, String cacheKey, RequestParams params, RequestCacheConfig cacheConfig, OnRequestListener onRequestListener); 85 | 86 | public Request sendGet(Object tag, String url, RequestParams params, RequestCacheConfig cacheConfig, OnRequestListener onRequestListener); 87 | 88 | public Request sendGet(Object tag, String url, String cacheKey, RequestParams params, OnRequestListener onRequestListener); 89 | 90 | public Request sendGet(Object tag, String url, RequestParams params, OnRequestListener onRequestListener); 91 | 92 | public Request sendGet(Object tag, String url, String cacheKey, OnRequestListener onRequestListener); 93 | 94 | public Request sendGet(Object tag, String url, OnRequestListener onRequestListener); 95 | 96 | /* 97 | * ======================================================================= 98 | * POST 99 | * ======================================================================= 100 | */ 101 | 102 | public Request sendPost(Object tag, String url, String cacheKey, RequestParams params, RequestCacheConfig cacheConfig, OnRequestListener onRequestListener); 103 | 104 | public Request sendPost(Object tag, String url, RequestParams params, RequestCacheConfig cacheConfig, OnRequestListener onRequestListener); 105 | 106 | public Request sendPost(Object tag, String url, String cacheKey, RequestParams params, OnRequestListener onRequestListener); 107 | 108 | public Request sendPost(Object tag, String url, RequestParams params, OnRequestListener onRequestListener); 109 | 110 | /* 111 | * ======================================================================= 112 | * Download 113 | * ======================================================================= 114 | */ 115 | 116 | public Request upload(Object tag, String url, String cacheKey, RequestParams params, RequestCacheConfig cacheConfig, OnRequestListener onRequestListener); 117 | 118 | public Request upload(Object tag, String url, RequestParams params, OnRequestListener onRequestListener); 119 | 120 | public Request upload(Object tag, String url, String cacheKey, RequestParams params, OnRequestListener onRequestListener); 121 | 122 | /* 123 | * ======================================================================= 124 | * Download 125 | * ======================================================================= 126 | */ 127 | 128 | public Request download(Object tag, String url, String cacheKey, String downloadPath, String fileName, RequestCacheConfig cacheConfig, OnRequestListener onRequestListener); 129 | 130 | public Request download(Object tag, String url, String downloadPath, String fileName, OnRequestListener onRequestListener); 131 | } 132 | -------------------------------------------------------------------------------- /XDroidRequest/src/com/xdroid/request/interfaces/IXRequest.java: -------------------------------------------------------------------------------- 1 | package com.xdroid.request.interfaces; 2 | 3 | import java.io.File; 4 | 5 | import com.xdroid.request.base.Request; 6 | import com.xdroid.request.config.RequestCacheConfig; 7 | import com.xdroid.request.ex.RequestParams; 8 | 9 | /** 10 | * Provider method for "XRequest" 11 | * 12 | * @author Robin 13 | * @since 2015-08-13 16:53:31 14 | * @param 15 | * Listen callback type 16 | * 17 | */ 18 | public interface IXRequest { 19 | 20 | /** 21 | * Best during application initialization calls only once 22 | * 23 | * @param threadPoolSize 24 | */ 25 | public void setRequestThreadPoolSize(int threadPoolSize); 26 | 27 | /** 28 | * Add a request to queue to execute 29 | * 30 | * @param request 31 | * Target request 32 | */ 33 | public void addToRequestQueue(Request request); 34 | 35 | /** 36 | * Create a default cache configuration 37 | * 38 | * @return 39 | */ 40 | public RequestCacheConfig getDefaultCacheConfig(); 41 | 42 | /** 43 | * Create a no cache configuration 44 | * 45 | * @return 46 | */ 47 | public RequestCacheConfig getNoCacheConfig(); 48 | 49 | /** 50 | * To cancel a request that is requesting 51 | * 52 | * @param request 53 | */ 54 | public void cancelRequest(Request request); 55 | 56 | /** 57 | * Cancel all of this request in the request queue , not including is 58 | * requested 59 | * 60 | * @param request 61 | * Current instance of request 62 | * @param tag 63 | * If there is no special Settings, then introduction the 64 | * instance of activity 65 | */ 66 | public void cancelAllRequestInQueueByTag(Object tag); 67 | 68 | /** 69 | * Start the request,start the thread pool 70 | */ 71 | public void start(); 72 | 73 | /** 74 | * Close the request, quit all threads, release the request queue 75 | */ 76 | public void shutdown(); 77 | 78 | /* 79 | * ======================================================================= 80 | * GET 81 | * ======================================================================= 82 | */ 83 | 84 | public Request sendGet(Object tag, String url, String cacheKey, RequestParams params, RequestCacheConfig cacheConfig, OnRequestListener onRequestListener); 85 | 86 | public Request sendGet(Object tag, String url, RequestParams params, RequestCacheConfig cacheConfig, OnRequestListener onRequestListener); 87 | 88 | public Request sendGet(Object tag, String url, String cacheKey, RequestParams params, OnRequestListener onRequestListener); 89 | 90 | public Request sendGet(Object tag, String url, RequestParams params, OnRequestListener onRequestListener); 91 | 92 | public Request sendGet(Object tag, String url, String cacheKey, OnRequestListener onRequestListener); 93 | 94 | public Request sendGet(Object tag, String url, OnRequestListener onRequestListener); 95 | 96 | /* 97 | * ======================================================================= 98 | * POST 99 | * ======================================================================= 100 | */ 101 | 102 | public Request sendPost(Object tag, String url, String cacheKey, RequestParams params, RequestCacheConfig cacheConfig, OnRequestListener onRequestListener); 103 | 104 | public Request sendPost(Object tag, String url, RequestParams params, RequestCacheConfig cacheConfig, OnRequestListener onRequestListener); 105 | 106 | public Request sendPost(Object tag, String url, String cacheKey, RequestParams params, OnRequestListener onRequestListener); 107 | 108 | public Request sendPost(Object tag, String url, RequestParams params, OnRequestListener onRequestListener); 109 | 110 | /* 111 | * ======================================================================= 112 | * Download 113 | * ======================================================================= 114 | */ 115 | 116 | public Request upload(Object tag, String url, String cacheKey, RequestParams params, RequestCacheConfig cacheConfig, OnRequestListener onRequestListener); 117 | 118 | public Request upload(Object tag, String url, RequestParams params, OnRequestListener onRequestListener); 119 | 120 | public Request upload(Object tag, String url, String cacheKey, RequestParams params, OnRequestListener onRequestListener); 121 | 122 | /* 123 | * ======================================================================= 124 | * Download 125 | * ======================================================================= 126 | */ 127 | 128 | public Request download(Object tag, String url, String cacheKey, String downloadPath, String fileName, RequestCacheConfig cacheConfig, OnRequestListener onRequestListener); 129 | 130 | public Request download(Object tag, String url, String downloadPath, String fileName, OnRequestListener onRequestListener); 131 | } 132 | -------------------------------------------------------------------------------- /XDroidRequest/src/com/xdroid/request/utils/GenericsUtils.java: -------------------------------------------------------------------------------- 1 | package com.xdroid.request.utils; 2 | 3 | import java.lang.reflect.ParameterizedType; 4 | import java.lang.reflect.Type; 5 | 6 | /** 7 | * Parse helper 8 | * @author Robin 9 | * @since 2015-11-10 14:50:21 10 | * 11 | */ 12 | public class GenericsUtils { 13 | 14 | /** 15 | * Parsing the generic type 16 | * @param cls 17 | * @return 18 | */ 19 | public static Type parseGenericityType(T obj){ 20 | Type mySuperClass = obj.getClass().getGenericSuperclass(); 21 | Type type = ((ParameterizedType) mySuperClass).getActualTypeArguments()[0]; 22 | return type; 23 | } 24 | 25 | /** 26 | * 通过反射,获得定义Class时声明的父类的范型参数的类型. 27 | * 如public BookManager extends GenricManager 28 | * 29 | * @param clazz The class to introspect 30 | * @return the first generic declaration, or Object.class if cannot be determined 31 | */ 32 | public static Class getSuperClassGenricType(Class clazz) { 33 | return getSuperClassGenricType(clazz, 0); 34 | } 35 | 36 | /** 37 | * 通过反射,获得定义Class时声明的父类的范型参数的类型. 38 | * 如public BookManager extends GenricManager 39 | * 40 | * @param clazz clazz The class to introspect 41 | * @param index the Index of the generic ddeclaration,start from 0. 42 | */ 43 | public static Class getSuperClassGenricType(Class clazz, int index) throws IndexOutOfBoundsException { 44 | 45 | Type genType = clazz.getGenericSuperclass(); 46 | 47 | if (!(genType instanceof ParameterizedType)) { 48 | return Object.class; 49 | } 50 | 51 | Type[] params = ((ParameterizedType) genType).getActualTypeArguments(); 52 | 53 | if (index >= params.length || index < 0) { 54 | return Object.class; 55 | } 56 | if (!(params[index] instanceof Class)) { 57 | return Object.class; 58 | } 59 | return (Class) params[index]; 60 | } 61 | 62 | @SuppressWarnings("unchecked") 63 | public static Class getViewClass(Class klass) { 64 | Type type = klass.getGenericSuperclass(); 65 | if(type == null || !(type instanceof ParameterizedType)) return null; 66 | ParameterizedType parameterizedType = (ParameterizedType) type; 67 | Type[] types = parameterizedType.getActualTypeArguments(); 68 | if(types == null || types.length == 0) return null; 69 | return (Class) types[0]; 70 | } 71 | 72 | public static Type getBeanType(T listener) { 73 | Type type; 74 | try { 75 | Type[] typs = GenericsUtils.getGenericInterfaces(listener.getClass()); 76 | if (typs != null) { 77 | type = typs[0]; 78 | } else { 79 | type = GenericsUtils.getGenericSuperclass(listener.getClass())[0]; 80 | } 81 | } catch (Exception e) { 82 | throw new RuntimeException("unknow type"); 83 | } 84 | return type; 85 | } 86 | 87 | /** 88 | * Take the parent class generic 89 | * @param clazz 90 | * @return 91 | */ 92 | public static Type[] getGenericSuperclass(Class clazz) { 93 | try { 94 | Type typeGeneric = clazz.getGenericSuperclass(); 95 | if (typeGeneric != null) { 96 | if (typeGeneric instanceof ParameterizedType) { 97 | return getGeneric((ParameterizedType) typeGeneric); 98 | } 99 | } 100 | } catch (Exception e) { 101 | CLog.e("ClassUtils", e); 102 | } 103 | return null; 104 | } 105 | /** 106 | * Take the parent interface generic 107 | * @param clazz 108 | * @return 109 | */ 110 | public static Type[] getGenericInterfaces(Class clazz) { 111 | try { 112 | Type typeGeneric = clazz.getGenericInterfaces()[0]; 113 | if (typeGeneric != null) { 114 | if (typeGeneric instanceof ParameterizedType) { 115 | return getGeneric((ParameterizedType) typeGeneric); 116 | } 117 | } 118 | } catch (Exception e) { 119 | } 120 | return null; 121 | } 122 | /** 123 | * Take a generic 124 | * @param type 125 | * @return 126 | */ 127 | public static Type[] getGeneric(ParameterizedType type) { 128 | try { 129 | if (type != null) { 130 | Type[] typeArgs = type.getActualTypeArguments(); 131 | if (typeArgs != null && typeArgs.length > 0) { 132 | Type[] args = new Type[typeArgs.length]; 133 | for (int i=0; i>> diskCacheManager = (DiskCacheManager>>) DiskCacheManager.getInstance(); 36 | return diskCacheManager.getDiskCacheDirectory(); 37 | } 38 | 39 | @Override 40 | public long getDiskCacheMaxSize() { 41 | @SuppressWarnings("unchecked") 42 | DiskCacheManager>> diskCacheManager = (DiskCacheManager>>) DiskCacheManager.getInstance(); 43 | return diskCacheManager.getDiskCacheMaxSize(); 44 | } 45 | 46 | @Override 47 | public void setDiskCacheMaxSize(long maxSize) { 48 | @SuppressWarnings("unchecked") 49 | DiskCacheManager>> diskCacheManager = (DiskCacheManager>>) DiskCacheManager.getInstance(); 50 | diskCacheManager.setDiskCacheMaxSize(maxSize); 51 | } 52 | 53 | @Override 54 | public long getAllDiskCacheSize() { 55 | @SuppressWarnings("unchecked") 56 | DiskCacheManager>> diskCacheManager = (DiskCacheManager>>) DiskCacheManager.getInstance(); 57 | return diskCacheManager.getAllDiskCacheSize(); 58 | } 59 | 60 | @Override 61 | public void deleteAllDiskCacheData() { 62 | @SuppressWarnings("unchecked") 63 | DiskCacheManager>> diskCacheManager = (DiskCacheManager>>) DiskCacheManager.getInstance(); 64 | diskCacheManager.deleteAllDiskCacheData(); 65 | } 66 | 67 | @Override 68 | public Boolean deleteOneDiskCacheData(String originalKey) { 69 | @SuppressWarnings("unchecked") 70 | DiskCacheManager>> diskCacheManager = (DiskCacheManager>>) DiskCacheManager.getInstance(); 71 | return diskCacheManager.deleteOneDiskCacheData(originalKey); 72 | } 73 | 74 | @Override 75 | public Boolean deleteOneDiskCacheData(Request request) { 76 | request.getCacheManager().deleteOneMemoryCacheData(request.getCacheKey()); 77 | Boolean deleteSuccess = request.getDiskCacheManager().deleteOneDiskCacheData(request.getCacheKey()); 78 | return deleteSuccess; 79 | } 80 | 81 | @Override 82 | public Boolean deleteOneDiskCacheData(Request request, String originalKey) { 83 | request.getCacheManager().deleteOneMemoryCacheData(originalKey); 84 | Boolean deleteSuccess = request.getDiskCacheManager().deleteOneDiskCacheData(originalKey); 85 | return deleteSuccess; 86 | } 87 | 88 | @SuppressWarnings("unchecked") 89 | @Override 90 | public T getDataFromDiskCache(String originalKey) { 91 | DiskCacheManager>> diskCacheManager = (DiskCacheManager>>) DiskCacheManager.getInstance(); 92 | CacheData> cacheData = diskCacheManager.getDataFromDiskCache(originalKey); 93 | if (cacheData != null && cacheData.getEntry() != null && cacheData.getEntry().result != null) { 94 | return (T) cacheData.getEntry().result; 95 | } 96 | return null; 97 | } 98 | 99 | // ----------------------------------------Memory------------------------------------------- 100 | 101 | @Override 102 | public void deleteOneMemoryCacheData(String key) { 103 | @SuppressWarnings("unchecked") 104 | MemoryCacheManager>> memoryCacheManager = (MemoryCacheManager>>) MemoryCacheManager.getInstance(); 105 | memoryCacheManager.deleteOneMemoryCacheData(key); 106 | } 107 | 108 | @Override 109 | public void deleteOneMemoryCacheData(Request request) { 110 | request.getCacheManager().deleteOneMemoryCacheData(request.getCacheKey()); 111 | } 112 | 113 | @Override 114 | public void deleteOneMemoryCacheData(Request request, String key) { 115 | request.getCacheManager().deleteOneMemoryCacheData(key); 116 | } 117 | 118 | @Override 119 | public void deleteAllMemoryCacheData() { 120 | @SuppressWarnings("unchecked") 121 | MemoryCacheManager>> memoryCacheManager = (MemoryCacheManager>>) MemoryCacheManager.getInstance(); 122 | memoryCacheManager.deleteAllMemoryCacheData(); 123 | } 124 | 125 | @SuppressWarnings("unchecked") 126 | @Override 127 | public T getDataFromMemoryCache(String key) { 128 | MemoryCacheManager>> memoryCacheManager = (MemoryCacheManager>>) MemoryCacheManager.getInstance(); 129 | CacheData> 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 request = new MultipartGsonRequest(cacheConfig, url, cacheKey, onRequestListener); 226 | request.setRequestParams(params); 227 | request.setHttpMethod(HttpMethod.POST); 228 | request.setTag(tag); 229 | 230 | addToRequestQueue(request); 231 | 232 | return request; 233 | } 234 | 235 | @Override 236 | public Request sendPost(Object tag, String url, RequestParams params, RequestCacheConfig cacheConfig, OnRequestListener onRequestListener) { 237 | return sendPost(tag, url, url, params, cacheConfig, onRequestListener); 238 | } 239 | 240 | @Override 241 | public Request sendPost(Object tag, String url, RequestParams params, OnRequestListener onRequestListener) { 242 | String cacheKey = url; 243 | return sendPost(tag, url, cacheKey, params, getDefaultCacheConfig(), onRequestListener); 244 | } 245 | 246 | @Override 247 | public Request sendPost(Object tag, String url, String cacheKey, RequestParams params, OnRequestListener onRequestListener) { 248 | return sendPost(tag, url, cacheKey, params, getDefaultCacheConfig(), onRequestListener); 249 | } 250 | 251 | /* 252 | * ======================================================================= 253 | * Upload 254 | * ======================================================================= 255 | */ 256 | 257 | @Override 258 | public Request upload(Object tag, String url, String cacheKey, RequestParams params, RequestCacheConfig cacheConfig, OnRequestListener onRequestListener) { 259 | return sendPost(tag, url, cacheKey, params, cacheConfig, onRequestListener); 260 | } 261 | 262 | @Override 263 | public Request upload(Object tag, String url, RequestParams params, OnRequestListener onRequestListener) { 264 | String cacheKey = url; 265 | return sendPost(tag, url, cacheKey, params, getNoCacheConfig(), onRequestListener); 266 | } 267 | 268 | @Override 269 | public Request upload(Object tag, String url, String cacheKey, RequestParams params, OnRequestListener onRequestListener) { 270 | return sendPost(tag, url, cacheKey, params, getNoCacheConfig(), onRequestListener); 271 | } 272 | 273 | /* 274 | * ======================================================================= 275 | * Download 276 | * ======================================================================= 277 | */ 278 | @Override 279 | public Request download(Object tag, String url, String cacheKey, String downloadPath, String fileName, RequestCacheConfig cacheConfig, OnRequestListener onRequestListener) { 280 | DownloadRequest request = new DownloadRequest(cacheConfig, url, cacheKey, downloadPath, fileName, onRequestListener); 281 | request.setTag(tag); 282 | 283 | addToRequestQueue(request); 284 | 285 | return request; 286 | } 287 | 288 | @Override 289 | public Request download(Object tag, String url, String downloadPath, String fileName, OnRequestListener onRequestListener) { 290 | return download(tag, url, url, downloadPath, fileName, getNoCacheConfig(), onRequestListener); 291 | } 292 | 293 | } 294 | -------------------------------------------------------------------------------- /XDroidRequest/src/com/xdroid/request/queue/RequestQueue.java: -------------------------------------------------------------------------------- 1 | package com.xdroid.request.queue; 2 | 3 | import java.util.HashMap; 4 | import java.util.HashSet; 5 | import java.util.LinkedList; 6 | import java.util.Map; 7 | import java.util.Queue; 8 | import java.util.Set; 9 | import java.util.concurrent.Executors; 10 | import java.util.concurrent.PriorityBlockingQueue; 11 | import java.util.concurrent.ThreadPoolExecutor; 12 | import java.util.concurrent.atomic.AtomicInteger; 13 | 14 | import com.xdroid.request.base.Request; 15 | import com.xdroid.request.delivered.DeliveryImpl; 16 | import com.xdroid.request.delivered.IDelivery; 17 | import com.xdroid.request.dispatcher.CacheDispatcher; 18 | import com.xdroid.request.dispatcher.NetworkDispatcher; 19 | import com.xdroid.request.network.HttpStack; 20 | import com.xdroid.request.network.HurlStack; 21 | import com.xdroid.request.network.Network; 22 | import com.xdroid.request.utils.CLog; 23 | 24 | import android.os.Handler; 25 | import android.os.Looper; 26 | 27 | /** 28 | * A request dispatch queue with a thread pool of dispatchers. 29 | *@author Robin 30 | *@since 2015-05-08 13:35:10 31 | */ 32 | public class RequestQueue { 33 | 34 | /** Used for generating monotonically-increasing sequence numbers for requests. */ 35 | private AtomicInteger mSequenceGenerator = new AtomicInteger(); 36 | 37 | /** 38 | * Staging area for requests that already have a duplicate request in flight. 39 | * 40 | *

    41 | *
  • containsKey(cacheKey) indicates that there is a request in flight for the given cache 42 | * key.
  • 43 | *
  • get(cacheKey) returns waiting requests for the given cache key. The in flight request 44 | * is not contained in that list. Is null if no requests are staged.
  • 45 | *
46 | */ 47 | private final Map>> mWaitingRequests = 48 | new HashMap>>(); 49 | 50 | /** 51 | * The set of all requests currently being processed by this RequestQueue. A Request 52 | * will be in this set if it is waiting in any queue or currently being processed by 53 | * any dispatcher. 54 | */ 55 | private final Set> mCurrentRequests = new HashSet>(); 56 | 57 | /** The cache triage queue. */ 58 | private final PriorityBlockingQueue> mCacheQueue = 59 | new PriorityBlockingQueue>(); 60 | 61 | /** The queue of requests that are actually going out to the network. */ 62 | private final PriorityBlockingQueue> mNetworkQueue = 63 | new PriorityBlockingQueue>(); 64 | 65 | /** Number of network request dispatcher threads to start. */ 66 | private static final int DEFAULT_NETWORK_THREAD_POOL_SIZE = 4; 67 | 68 | 69 | /** The network dispatchers. */ 70 | private NetworkDispatcher[] mDispatchers; 71 | 72 | /** The cache dispatcher. */ 73 | private CacheDispatcher mCacheDispatcher; 74 | 75 | /** Network request actuator **/ 76 | public Network mNetwork; 77 | 78 | /** Http request results and the cache results for the response of the distributor **/ 79 | public IDelivery mDelivery; 80 | 81 | /** HTTP request body builder, the use of HttpUrlConnection, when SDK is larger than 11, when less than 11, the use of HttpClient */ 82 | public HttpStack httpStackFactory() { 83 | return new HurlStack(); 84 | } 85 | 86 | /** 87 | * Creates the worker pool. Processing will not begin until {@link #start()} is called. 88 | */ 89 | public RequestQueue() { 90 | this(DEFAULT_NETWORK_THREAD_POOL_SIZE); 91 | } 92 | 93 | /** 94 | * Creates the worker pool. Processing will not begin until {@link #start()} is called. 95 | * 96 | * @param threadPoolSize Number of network dispatcher threads to create 97 | */ 98 | public RequestQueue(int threadPoolSize) { 99 | mDispatchers = new NetworkDispatcher[threadPoolSize]; 100 | mNetwork = new Network(httpStackFactory()); 101 | mDelivery= new DeliveryImpl(new Handler(Looper.getMainLooper())); 102 | } 103 | 104 | /** 105 | * Starts the dispatchers in this queue. 106 | */ 107 | public void start() { 108 | stop(); // Make sure any currently running dispatchers are stopped. 109 | // Create the cache dispatcher and start it. 110 | mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue,mDelivery); 111 | mCacheDispatcher.start(); 112 | 113 | // Create network dispatchers (and corresponding threads) up to the pool size. 114 | //Use thread array, thread death not rebuild and test the upload and download at the same time, poor performance, often with no connection 115 | /*for (int i = 0; i < mDispatchers.length; i++) { 116 | NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue,mNetwork,mDelivery); 117 | mDispatchers[i] = networkDispatcher; 118 | networkDispatcher.start(); 119 | }*/ 120 | 121 | // Create network dispatchers (and corresponding threads) up to the pool size. 122 | //Use fixed number of thread pool, performance is superior to the thread array, test and upload and download, found no big problem 123 | ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) Executors.newFixedThreadPool(mDispatchers.length); 124 | for (int i = 0; i < mDispatchers.length; i++) { 125 | NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork,mDelivery); 126 | mDispatchers[i] = networkDispatcher; 127 | threadPoolExecutor.submit(networkDispatcher); 128 | } 129 | 130 | } 131 | 132 | /** 133 | * Stops the cache and network dispatchers. 134 | */ 135 | public void stop() { 136 | if (mCacheDispatcher != null) { 137 | mCacheDispatcher.quit(); 138 | } 139 | for (int i = 0; i < mDispatchers.length; i++) { 140 | if (mDispatchers[i] != null) { 141 | mDispatchers[i].quit(); 142 | } 143 | } 144 | } 145 | 146 | /** 147 | * Gets a sequence number. 148 | */ 149 | public int getSequenceNumber() { 150 | return mSequenceGenerator.incrementAndGet(); 151 | } 152 | 153 | /** 154 | * A simple predicate or filter interface for Requests, for use by 155 | * {@link com.xdroid.request.queue.RequestQueue#cancelAll(com.xdroid.request.queue.RequestQueue.RequestFilter)}. 156 | */ 157 | public interface RequestFilter { 158 | public boolean apply(Request request); 159 | } 160 | 161 | /** 162 | * Cancels all requests in this queue for which the given filter applies. 163 | * @param filter The filtering function to use 164 | */ 165 | public void cancelAll(RequestFilter filter) { 166 | synchronized (mCurrentRequests) { 167 | for (Request request : mCurrentRequests) { 168 | if (filter.apply(request)) { 169 | request.cancel(); 170 | } 171 | } 172 | } 173 | } 174 | 175 | /** 176 | * Cancels all requests in this queue with the given tag. Tag must be non-null 177 | * and equality is by identity. 178 | */ 179 | public void cancelAll(final Object tag) { 180 | if (tag == null) { 181 | throw new IllegalArgumentException("Cannot cancelAll with a null tag"); 182 | } 183 | cancelAll(new RequestFilter() { 184 | @Override 185 | public boolean apply(Request request) { 186 | return request.getTag() == tag; 187 | } 188 | }); 189 | } 190 | 191 | /** 192 | * Adds a Request to the dispatch queue. 193 | * @param request The request to service 194 | * @return The passed-in request 195 | */ 196 | public Request add(Request request) { 197 | // Tag the request as belonging to this queue and add it to the set of current requests. 198 | request.setRequestQueue(this); 199 | synchronized (mCurrentRequests) { 200 | mCurrentRequests.add(request); 201 | } 202 | 203 | // Process requests in the order they are added. 204 | request.setSequence(getSequenceNumber()); 205 | CLog.v("add-to-queue"); 206 | 207 | // If the request is uncacheable, skip the cache queue and go straight to the network. 208 | if (!request.getRequestCacheConfig().isShouldCache()) { 209 | mNetworkQueue.add(request); 210 | return request; 211 | } 212 | 213 | // Insert request into stage if there's already a request with the same cache key in flight. 214 | synchronized (mWaitingRequests) { 215 | String cacheKey = request.getCacheKey(); 216 | if (mWaitingRequests.containsKey(cacheKey)) { 217 | // There is already a request in flight. Queue up. 218 | Queue> stagedRequests = mWaitingRequests.get(cacheKey); 219 | if (stagedRequests == null) { 220 | stagedRequests = new LinkedList>(); 221 | } 222 | stagedRequests.add(request); 223 | mWaitingRequests.put(cacheKey, stagedRequests); 224 | CLog.i("Request for cacheKey="+cacheKey+" is in flight, putting on hold."); 225 | } else { 226 | // Insert 'null' queue for this cacheKey, indicating there is now a request in 227 | // flight. 228 | mWaitingRequests.put(cacheKey, null); 229 | mCacheQueue.add(request); 230 | } 231 | return request; 232 | } 233 | } 234 | 235 | /** 236 | * Called from {@link Request#finish()}, indicating that processing of the given request 237 | * has finished. 238 | * 239 | *

Releases waiting requests for request.getCacheKey() if 240 | * request.shouldCache().

241 | */ 242 | public void finish(Request request) { 243 | // Remove from the set of requests currently being processed. 244 | synchronized (mCurrentRequests) { 245 | mCurrentRequests.remove(request); 246 | } 247 | 248 | if (request.getRequestCacheConfig().isShouldCache()) { 249 | synchronized (mWaitingRequests) { 250 | String cacheKey = request.getCacheKey(); 251 | Queue> waitingRequests = mWaitingRequests.remove(cacheKey); 252 | if (waitingRequests != null) { 253 | CLog.i("Releasing "+waitingRequests.size()+" waiting requests for cacheKey="+cacheKey); 254 | // Process all queued up requests. They won't be considered as in flight, but 255 | // that's not a problem as the cache has been primed by 'request'. 256 | mCacheQueue.addAll(waitingRequests); 257 | } 258 | } 259 | } 260 | } 261 | 262 | public IDelivery getDelivery() { 263 | return mDelivery; 264 | } 265 | 266 | 267 | } 268 | -------------------------------------------------------------------------------- /XDroidRequest/src/com/xdroid/request/cache/DiskCacheManager.java: -------------------------------------------------------------------------------- 1 | package com.xdroid.request.cache; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.File; 5 | import java.io.FileNotFoundException; 6 | import java.io.IOException; 7 | import java.io.InputStream; 8 | import java.io.ObjectInputStream; 9 | import java.io.ObjectOutputStream; 10 | import java.io.OutputStream; 11 | import java.security.MessageDigest; 12 | import java.security.NoSuchAlgorithmException; 13 | 14 | import com.xdroid.request.cache.diskcache.DiskLruCache; 15 | import com.xdroid.request.interfaces.OnCacheDataListener; 16 | 17 | import android.graphics.Bitmap; 18 | import android.graphics.Bitmap.CompressFormat; 19 | import android.graphics.BitmapFactory; 20 | import android.os.AsyncTask; 21 | 22 | /** 23 | * manage the disk cache 24 | * @author Robin 25 | * @since 2015-05-07 23:31:23 26 | */ 27 | public class DiskCacheManager { 28 | 29 | private static DiskCacheManager mCacheManager; 30 | 31 | private DiskLruCache mDiskLruCache; 32 | 33 | private static final int DEFAULT_VALUE_COUNT=1; 34 | 35 | public DiskCacheManager () { 36 | init(); 37 | } 38 | 39 | /*private static volatile DiskCacheManager>> INSTANCE = null; 40 | 41 | public static DiskCacheManager>> getInstance() { 42 | if (INSTANCE == null) { 43 | synchronized (DiskCacheManager.class) { 44 | if (INSTANCE == null) { 45 | INSTANCE = new DiskCacheManager>>(); 46 | } 47 | } 48 | } 49 | return INSTANCE; 50 | }*/ 51 | 52 | public static DiskCacheManager getInstance(){ 53 | if (mCacheManager == null) { 54 | mCacheManager=new DiskCacheManager(); 55 | } 56 | return mCacheManager; 57 | } 58 | 59 | private void init() { 60 | if (mDiskLruCache==null) { 61 | open(); 62 | } 63 | 64 | } 65 | 66 | public void open(){ 67 | File cacheDir = CacheConfig.DISK_CACHE_DIRECTORY; 68 | if (!cacheDir.exists()) { 69 | cacheDir.mkdirs(); 70 | } 71 | try { 72 | mDiskLruCache=DiskLruCache.open(cacheDir, CacheConfig.DISK_CACHE_APP_VERSION, DEFAULT_VALUE_COUNT, CacheConfig.DISK_CACHE_MAX_SIZE); 73 | } catch (IOException e) { 74 | if (e instanceof FileNotFoundException) { 75 | throw new RuntimeException("Maybe you forgot to add storage permissions to the AndroidMenifest file."); 76 | } 77 | e.printStackTrace(); 78 | } 79 | } 80 | 81 | /** 82 | * set the data to disk cache 83 | * @param originalKey 84 | */ 85 | public void setDataToDiskCache(String originalKey,ValueType value){ 86 | if (mDiskLruCache == null || mDiskLruCache.isClosed()) { 87 | open(); 88 | } 89 | try { 90 | String key = hashKeyForDisk(originalKey); 91 | DiskLruCache.Editor editor = mDiskLruCache.edit(key); 92 | if (editor != null) { 93 | OutputStream outputStream = editor.newOutputStream(0); 94 | ObjectOutputStream oos=new ObjectOutputStream(outputStream); 95 | if (value!=null) { 96 | 97 | if (value instanceof CacheData) { 98 | @SuppressWarnings("unchecked") 99 | CacheData> cacheData = (CacheData>) value; 100 | if (cacheData.getEntry().result instanceof Bitmap) { 101 | Bitmap bitmap = (Bitmap) cacheData.getEntry().result; 102 | ByteArrayOutputStream baops = new ByteArrayOutputStream(); 103 | bitmap.compress(CompressFormat.PNG, 0, baops); 104 | BitmapCache bitmapCache = new BitmapCache(baops.toByteArray(), "bitmap_cache.png"); 105 | 106 | Entry entry = new Entry(bitmapCache, cacheData.getEntry().responseHeaders); 107 | CacheData> bitmapCacheData = new CacheData>(entry, cacheData.getExpirationTime(), cacheData.getWriteTime(), cacheData.isNeverExpiry()); 108 | oos.writeObject(bitmapCacheData); 109 | }else { 110 | oos.writeObject(value); 111 | } 112 | }else { 113 | oos.writeObject(value); 114 | } 115 | 116 | } 117 | /*if (oos!=null) { 118 | oos.close(); 119 | }*/ 120 | 121 | if (getDataFromDiskCache(originalKey)==null) { 122 | editor.commit(); 123 | } else { 124 | editor.abort(); 125 | } 126 | } 127 | mDiskLruCache.flush(); 128 | } catch (IOException e) { 129 | e.printStackTrace(); 130 | } 131 | 132 | } 133 | 134 | /** 135 | * set the data to disk cache by async 136 | * @param originalKey 137 | * @param value 138 | * @param onCacheDataListener 139 | */ 140 | public void setDataToDiskCacheAsync(final String originalKey,final ValueType value,final OnCacheDataListener onCacheDataListener){ 141 | if (mDiskLruCache == null || mDiskLruCache.isClosed()) { 142 | open(); 143 | } 144 | new AsyncTask() { 145 | 146 | @Override 147 | protected ValueType doInBackground(Void... params) { 148 | setDataToDiskCache(originalKey, value); 149 | return value; 150 | } 151 | 152 | @Override 153 | protected void onPostExecute(ValueType result) { 154 | super.onPostExecute(result); 155 | onCacheDataListener.onFinish(result); 156 | } 157 | }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); 158 | } 159 | 160 | /** 161 | * read the data from disk cache 162 | * @return 163 | */ 164 | @SuppressWarnings("unchecked") 165 | public ValueType getDataFromDiskCache(String originalKey){ 166 | if (mDiskLruCache == null || mDiskLruCache.isClosed()) { 167 | open(); 168 | } 169 | try { 170 | String key = hashKeyForDisk(originalKey); 171 | DiskLruCache.Snapshot snapShot = mDiskLruCache.get(key); 172 | if (snapShot != null) { 173 | InputStream is = snapShot.getInputStream(0); 174 | ObjectInputStream ois=new ObjectInputStream(is); 175 | try { 176 | ValueType value=(ValueType) ois.readObject(); 177 | 178 | if (value instanceof CacheData) { 179 | CacheData> cacheData = (CacheData>) value; 180 | if (cacheData.getEntry().result instanceof BitmapCache) { 181 | BitmapCache bitmapCache = (BitmapCache) cacheData.getEntry().result; 182 | byte[] data = bitmapCache.getBitmapBytes(); 183 | Bitmap resultBitmap = BitmapFactory.decodeByteArray(data, 0, data.length); 184 | 185 | Entry entry = new Entry(resultBitmap, cacheData.getEntry().responseHeaders); 186 | CacheData> bitmapCacheData = new CacheData>(entry, cacheData.getExpirationTime(), cacheData.getWriteTime(), cacheData.isNeverExpiry()); 187 | 188 | return (ValueType) bitmapCacheData; 189 | } 190 | } 191 | 192 | return value; 193 | } catch (Exception e) { 194 | e.printStackTrace(); 195 | return null; 196 | } 197 | } 198 | } catch (IOException e) { 199 | e.printStackTrace(); 200 | return null; 201 | } 202 | return null; 203 | 204 | } 205 | 206 | /** 207 | * read the data from disk cache by Async 208 | */ 209 | public void getDataFromDiskCacheAsync(final String originalKey,final OnCacheDataListener onCacheDataListener){ 210 | if (mDiskLruCache == null || mDiskLruCache.isClosed()) { 211 | open(); 212 | } 213 | new AsyncTask() { 214 | 215 | @Override 216 | protected ValueType doInBackground(Void... params) { 217 | return getDataFromDiskCache(originalKey); 218 | } 219 | 220 | @Override 221 | protected void onPostExecute(ValueType result) { 222 | super.onPostExecute(result); 223 | onCacheDataListener.onFinish(result); 224 | } 225 | }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); 226 | } 227 | 228 | /** 229 | * delete one data 230 | * @param originalKey 231 | * @return 232 | */ 233 | public Boolean deleteOneDiskCacheData(String originalKey){ 234 | if (mDiskLruCache == null || mDiskLruCache.isClosed()) { 235 | open(); 236 | } 237 | try { 238 | String key = hashKeyForDisk(originalKey); 239 | return mDiskLruCache.remove(key); 240 | } catch (IOException e) { 241 | e.printStackTrace(); 242 | return false; 243 | } 244 | } 245 | 246 | public void deleteAllDiskCacheData(){ 247 | if (mDiskLruCache == null || mDiskLruCache.isClosed()) { 248 | open(); 249 | } 250 | if (mDiskLruCache != null) { 251 | try { 252 | mDiskLruCache.delete(); 253 | } catch (IOException e) { 254 | e.printStackTrace(); 255 | } 256 | } 257 | } 258 | 259 | public long getAllDiskCacheSize(){ 260 | if (mDiskLruCache == null || mDiskLruCache.isClosed()) { 261 | open(); 262 | } 263 | if (mDiskLruCache != null) { 264 | return mDiskLruCache.size(); 265 | } 266 | return 0; 267 | } 268 | 269 | public void setDiskCacheMaxSize(long maxSize){ 270 | if (mDiskLruCache == null || mDiskLruCache.isClosed()) { 271 | open(); 272 | } 273 | if (mDiskLruCache != null) { 274 | mDiskLruCache.setMaxSize(maxSize); 275 | CacheConfig.DISK_CACHE_MAX_SIZE = maxSize; 276 | } 277 | } 278 | 279 | public long getDiskCacheMaxSize(){ 280 | if (mDiskLruCache == null || mDiskLruCache.isClosed()) { 281 | open(); 282 | } 283 | if (mDiskLruCache != null) { 284 | return mDiskLruCache.getMaxSize(); 285 | } 286 | return 0; 287 | } 288 | 289 | public File getDiskCacheDirectory(){ 290 | if (mDiskLruCache == null || mDiskLruCache.isClosed()) { 291 | open(); 292 | } 293 | if (mDiskLruCache != null) { 294 | return mDiskLruCache.getDirectory(); 295 | } 296 | return null; 297 | } 298 | 299 | public static String InputStreamToString(InputStream is) throws Exception{ 300 | int BUFFER_SIZE = 4096; 301 | ByteArrayOutputStream outStream = new ByteArrayOutputStream(); 302 | byte[] data = new byte[BUFFER_SIZE]; 303 | int count = -1; 304 | while((count = is.read(data,0,BUFFER_SIZE)) != -1) 305 | outStream.write(data, 0, count); 306 | 307 | data = null; 308 | return new String(outStream.toByteArray(),"ISO-8859-1"); 309 | } 310 | 311 | 312 | /** 313 | * Using the MD5 algorithm to encrypt the key of the incoming and return. 314 | */ 315 | public String hashKeyForDisk(String key) { 316 | String cacheKey; 317 | try { 318 | final MessageDigest mDigest = MessageDigest.getInstance("MD5"); 319 | mDigest.update(key.getBytes()); 320 | cacheKey = bytesToHexString(mDigest.digest()); 321 | } catch (NoSuchAlgorithmException e) { 322 | cacheKey = String.valueOf(key.hashCode()); 323 | } 324 | return cacheKey; 325 | } 326 | 327 | private String bytesToHexString(byte[] bytes) { 328 | StringBuilder sb = new StringBuilder(); 329 | for (int i = 0; i < bytes.length; i++) { 330 | String hex = Integer.toHexString(0xFF & bytes[i]); 331 | if (hex.length() == 1) { 332 | sb.append('0'); 333 | } 334 | sb.append(hex); 335 | } 336 | return sb.toString(); 337 | } 338 | 339 | 340 | /** 341 | * Record cache synchronization to the journal file. 342 | */ 343 | public void fluchCache() { 344 | if (mDiskLruCache != null) { 345 | try { 346 | mDiskLruCache.flush(); 347 | } catch (IOException e) { 348 | e.printStackTrace(); 349 | } 350 | } 351 | } 352 | 353 | } 354 | --------------------------------------------------------------------------------