认为博文实用,请点赞,请评论,请关注。谢谢!
~
老规矩,先上GIF动态图。看个效果,假设符合你的项目或者确定你要了解的内容,再往下看吧:
完整项目下载地址:http://download.csdn.net/detail/iwanghang/9792768
贴代码:
1.PHP:
<?php namespace app\index\controller; class Uploadimg2
{
public function index()
{ $param = file_get_contents("php://input"); // 1
// base64
// 过来的字符串是“photo:xxxxx”,xxxxx就是base64的图片,以下这一行去掉了“photo:”
$param1 = substr($param, 6);
// 这里是转码 Unicode转Native
$param2 = str_replace(" ","+",$param1);
$param2 = str_replace("%2F","/",$param2);
$param2 = str_replace("%2B","+",$param2);
$param2 = str_replace("%0A","",$param2);
// 这里是 base64_decode
$image_content = base64_decode($param2);
// 保存图片
file_put_contents(ROOT_PATH . 'public' . DS . 'uploads/0/1.jpg', $image_content);
//file_put_contents(ROOT_PATH . 'public' . DS . 'uploads/0/1.txt', $param); // 2
// 16进制
$binary_string = pack("H*" , $param1);
file_put_contents(ROOT_PATH . 'public' . DS . 'uploads/0/2.jpg', $binary_string);
//file_put_contents(ROOT_PATH . 'public' . DS . 'uploads/0/2.txt', $binary_string); // 3
// 2进制
file_put_contents(ROOT_PATH . 'public' . DS . 'uploads/0/3.jpg', $param);
//file_put_contents(ROOT_PATH . 'public' . DS . 'uploads/0/3.txt', $param); return 111;
}
}
2.Android:
uploadimg:
package com.jerry.uploadimg; import java.io.ByteArrayOutputStream;
import java.io.File; import org.apache.http.Header; import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.util.Base64;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast; import com.loopj.android.http.AsyncHttpClient;
import com.loopj.android.http.AsyncHttpResponseHandler;
import com.loopj.android.http.RequestParams; public class MainActivity extends Activity { private static final int PHOTO_REQUEST_CAMERA = 1;// 拍照
private static final int PHOTO_REQUEST_GALLERY = 2;// 从相冊中选择
private static final int PHOTO_REQUEST_CUT = 3;// 结果 private ImageView mFace;
private Bitmap bitmap;
private TextView tvv;
//private String url = "http://192.168.1.106:80/index.php/index/Upload";
private String url = "http://192.168.1.111/index.php/index/Uploadimg2";
// private String url = "http://192.168.1.113/tugua/api/";
// private String url = "http://192.168.1.126/tx_api/Test/index";
// private String url = "192.168.1.103/mibileup/iosphp.php"; private char[] slslsl; /* 头像名称 */
private static final String PHOTO_FILE_NAME = "temp_photo.jpg";
private File tempFile; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
this.mFace = (ImageView) this.findViewById(R.id.iv_image);
this.tvv = (TextView) findViewById(R.id.tv); tvv.setText(url);
} /*
* 上传图片
*/
public void upload(View view) {
try {
ByteArrayOutputStream out = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out);
out.flush();
out.close();
byte[] buffer = out.toByteArray(); // 1
// 转换为Base64。然后没转换为字符串
byte[] encode = Base64.encode(buffer, Base64.DEFAULT);
String photo = new String(encode); // 2
// 转换为16进制。然后没转换为字符串
char[] ssssss = Hex.encodeHex(buffer);
photo = new String(ssssss); // 3
// byte[] 直接转为字符串
// String photo = new String(buffer); RequestParams params = new RequestParams();
params.put("photo", photo);
//String url = "http://192.168.1.106:80/index.php/index/Uploadimg2";
//tvv.setText(url); AsyncHttpClient client = new AsyncHttpClient();
client.post(url, params, new AsyncHttpResponseHandler() {
@Override
public void onSuccess(int statusCode, Header[] headers,
byte[] responseBody) {
try {
if (statusCode == 200) { Toast.makeText(MainActivity.this, "头像上传成功!", 0)
.show();
} else {
Toast.makeText(MainActivity.this,
"网络訪问异常,错误码:" + statusCode, 0).show(); }
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} @Override
public void onFailure(int statusCode, Header[] headers,
byte[] responseBody, Throwable error) {
Toast.makeText(MainActivity.this,
"网络訪问异常,错误码 > " + statusCode, 0).show(); }
}); } catch (Exception e) {
e.printStackTrace();
}
} /*
* 从相冊获取
*/
public void gallery(View view) {
// 激活系统图库。选择一张图片
Intent intent = new Intent(Intent.ACTION_PICK);
intent.setType("image/*");
startActivityForResult(intent, PHOTO_REQUEST_GALLERY);
} /*
* 从相机获取
*/
public void camera(View view) {
Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
// 推断存储卡能否够用。可用进行存储
if (hasSdcard()) {
intent.putExtra(MediaStore.EXTRA_OUTPUT,
Uri.fromFile(new File(Environment
.getExternalStorageDirectory(), PHOTO_FILE_NAME)));
}
startActivityForResult(intent, PHOTO_REQUEST_CAMERA);
} @Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == PHOTO_REQUEST_GALLERY) {
if (data != null) {
// 得到图片的全路径
Uri uri = data.getData();
crop(uri);
} } else if (requestCode == PHOTO_REQUEST_CAMERA) {
if (hasSdcard()) {
tempFile = new File(Environment.getExternalStorageDirectory(),
PHOTO_FILE_NAME);
crop(Uri.fromFile(tempFile));
} else {
Toast.makeText(MainActivity.this, "未找到存储卡。无法存储照片!", 0).show();
} } else if (requestCode == PHOTO_REQUEST_CUT) {
try {
bitmap = data.getParcelableExtra("data");
this.mFace.setImageBitmap(bitmap);
boolean delete = tempFile.delete();
System.out.println("delete = " + delete); } catch (Exception e) {
e.printStackTrace();
} } super.onActivityResult(requestCode, resultCode, data);
} /**
* 剪切图片
*
* @function:
* @author:Jerry
* @date:2013-12-30
* @param uri
*/
private void crop(Uri uri) {
// 裁剪图片意图
Intent intent = new Intent("com.android.camera.action.CROP");
intent.setDataAndType(uri, "image/*");
intent.putExtra("crop", "true");
// 裁剪框的比例,1:1
intent.putExtra("aspectX", 1);
intent.putExtra("aspectY", 1);
// 裁剪后输出图片的尺寸大小
intent.putExtra("outputX", 250);
intent.putExtra("outputY", 250);
// 图片格式
intent.putExtra("outputFormat", "JPEG");
intent.putExtra("noFaceDetection", true);// 取消人脸识别
intent.putExtra("return-data", true);// true:不返回uri,false:返回uri
startActivityForResult(intent, PHOTO_REQUEST_CUT);
} private boolean hasSdcard() {
if (Environment.getExternalStorageState().equals(
Environment.MEDIA_MOUNTED)) {
return true;
} else {
return false;
}
}
}
\uploadimg\Hex.java
package com.jerry.uploadimg; /**
* reference apache commons <a
* href="http://commons.apache.org/codec/">http://commons.apache.org/codec/</a>
*
* @author Aub
*
*/
public class Hex { /**
* 用于建立十六进制字符的输出的小写字符数组
*/
private static final char[] DIGITS_LOWER = { '0', '1', '2', '3', '4', '5',
'6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; /**
* 用于建立十六进制字符的输出的大写字符数组
*/
private static final char[] DIGITS_UPPER = { '0', '1', '2', '3', '4', '5',
'6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; /**
* 将字节数组转换为十六进制字符数组
*
* @param data
* byte[]
* @return 十六进制char[]
*/
public static char[] encodeHex(byte[] data) {
return encodeHex(data, true);
} /**
* 将字节数组转换为十六进制字符数组
*
* @param data
* byte[]
* @param toLowerCase
* <code>true</code> 传换成小写格式 , <code>false</code> 传换成大写格式
* @return 十六进制char[]
*/
public static char[] encodeHex(byte[] data, boolean toLowerCase) {
return encodeHex(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER);
} /**
* 将字节数组转换为十六进制字符数组
*
* @param data
* byte[]
* @param toDigits
* 用于控制输出的char[]
* @return 十六进制char[]
*/
protected static char[] encodeHex(byte[] data, char[] toDigits) {
int l = data.length;
char[] out = new char[l << 1];
// two characters form the hex value.
for (int i = 0, j = 0; i < l; i++) {
out[j++] = toDigits[(0xF0 & data[i]) >>> 4];
out[j++] = toDigits[0x0F & data[i]];
}
return out;
} /**
* 将字节数组转换为十六进制字符串
*
* @param data
* byte[]
* @return 十六进制String
*/
public static String encodeHexStr(byte[] data) {
return encodeHexStr(data, true);
} /**
* 将字节数组转换为十六进制字符串
*
* @param data
* byte[]
* @param toLowerCase
* <code>true</code> 传换成小写格式 , <code>false</code> 传换成大写格式
* @return 十六进制String
*/
public static String encodeHexStr(byte[] data, boolean toLowerCase) {
return encodeHexStr(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER);
} /**
* 将字节数组转换为十六进制字符串
*
* @param data
* byte[]
* @param toDigits
* 用于控制输出的char[]
* @return 十六进制String
*/
protected static String encodeHexStr(byte[] data, char[] toDigits) {
return new String(encodeHex(data, toDigits));
} /**
* 将十六进制字符数组转换为字节数组
*
* @param data
* 十六进制char[]
* @return byte[]
* @throws RuntimeException
* 假设源十六进制字符数组是一个奇怪的长度。将抛出执行时异常
*/
public static byte[] decodeHex(char[] data) { int len = data.length; if ((len & 0x01) != 0) {
throw new RuntimeException("Odd number of characters.");
} byte[] out = new byte[len >> 1]; // two characters form the hex value.
for (int i = 0, j = 0; j < len; i++) {
int f = toDigit(data[j], j) << 4;
j++;
f = f | toDigit(data[j], j);
j++;
out[i] = (byte) (f & 0xFF);
} return out;
} /**
* 将十六进制字符转换成一个整数
*
* @param ch
* 十六进制char
* @param index
* 十六进制字符在字符数组中的位置
* @return 一个整数
* @throws RuntimeException
* 当ch不是一个合法的十六进制字符时,抛出执行时异常
*/
protected static int toDigit(char ch, int index) {
int digit = Character.digit(ch, 16);
if (digit == -1) {
throw new RuntimeException("Illegal hexadecimal character " + ch
+ " at index " + index);
}
return digit;
} public static void main(String[] args) {
String srcStr = "待转换字符串";
String encodeStr = encodeHexStr(srcStr.getBytes());
String decodeStr = new String(decodeHex(encodeStr.toCharArray()));
System.out.println("转换前:" + srcStr);
System.out.println("转换后:" + encodeStr);
System.out.println("还原后:" + decodeStr);
} }
activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity" > <Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="gallery"
android:text="获取图库图片" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="camera"
android:text="拍照获取图片" /> <ImageView
android:id="@+id/iv_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content" /> <Button
android:onClick="upload"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="上传" /> <TextView
android:id="@+id/tv"
android:text="URL"
android:layout_width="match_parent"
android:layout_height="match_parent" /> </LinearLayout>
loopj\android\http
loopj\android\http\AsyncHttpClient.java
/*
Android Asynchronous Http Client
Copyright (c) 2011 James Smith <james@loopj.com>
http://loopj.com Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/ package com.loopj.android.http; import android.content.Context;
import android.util.Log; import org.apache.http.Header;
import org.apache.http.HeaderElement;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.HttpRequestInterceptor;
import org.apache.http.HttpResponse;
import org.apache.http.HttpResponseInterceptor;
import org.apache.http.HttpVersion;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CookieStore;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpHead;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.protocol.ClientContext;
import org.apache.http.conn.params.ConnManagerParams;
import org.apache.http.conn.params.ConnPerRouteBean;
import org.apache.http.conn.params.ConnRoutePNames;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.entity.HttpEntityWrapper;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.client.DefaultRedirectHandler;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;
import org.apache.http.protocol.SyncBasicHttpContext; import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.zip.GZIPInputStream; /**
* The AsyncHttpClient can be used to make asynchronous GET, POST, PUT and
* DELETE HTTP requests in your Android applications. Requests can be made
* with additional parameters by passing a {@link RequestParams} instance,
* and responses can be handled by passing an anonymously overridden
* {@link AsyncHttpResponseHandler} instance.
* <p> </p>
* For example:
* <p> </p>
* <pre>
* AsyncHttpClient client = new AsyncHttpClient();
* client.get("http://www.google.com", new AsyncHttpResponseHandler() {
* @Override
* public void onSuccess(String response) {
* System.out.println(response);
* }
* });
* </pre>
*/
public class AsyncHttpClient {
private static final String VERSION = "1.4.4"; private static final int DEFAULT_MAX_CONNECTIONS = 10;
private static final int DEFAULT_SOCKET_TIMEOUT = 10 * 1000;
private static final int DEFAULT_MAX_RETRIES = 5;
private static final int DEFAULT_RETRY_SLEEP_TIME_MILLIS = 1500;
private static final int DEFAULT_SOCKET_BUFFER_SIZE = 8192;
private static final String HEADER_ACCEPT_ENCODING = "Accept-Encoding";
private static final String ENCODING_GZIP = "gzip";
private static final String LOG_TAG = "AsyncHttpClient"; private int maxConnections = DEFAULT_MAX_CONNECTIONS;
private int timeout = DEFAULT_SOCKET_TIMEOUT; private final DefaultHttpClient httpClient;
private final HttpContext httpContext;
private ThreadPoolExecutor threadPool;
private final Map<Context, List<WeakReference<Future<?>>>> requestMap;
private final Map<String, String> clientHeaderMap;
private boolean isUrlEncodingEnabled = true; /**
* Creates a new AsyncHttpClient with default constructor arguments values
*/
public AsyncHttpClient() {
this(false, 80, 443);
} /**
* Creates a new AsyncHttpClient.
*
* @param httpPort non-standard HTTP-only port
*/
public AsyncHttpClient(int httpPort) {
this(false, httpPort, 443);
} /**
* Creates a new AsyncHttpClient.
*
* @param httpPort non-standard HTTP-only port
* @param httpsPort non-standard HTTPS-only port
*/
public AsyncHttpClient(int httpPort, int httpsPort) {
this(false, httpPort, httpsPort);
} /**
* Creates new AsyncHttpClient using given params
*
* @param fixNoHttpResponseException Whether to fix or not issue, by ommiting SSL verification
* @param httpPort HTTP port to be used, must be greater than 0
* @param httpsPort HTTPS port to be used, must be greater than 0
*/
public AsyncHttpClient(boolean fixNoHttpResponseException, int httpPort, int httpsPort) {
this(getDefaultSchemeRegistry(fixNoHttpResponseException, httpPort, httpsPort));
} /**
* Returns default instance of SchemeRegistry
*
* @param fixNoHttpResponseException Whether to fix or not issue, by ommiting SSL verification
* @param httpPort HTTP port to be used, must be greater than 0
* @param httpsPort HTTPS port to be used, must be greater than 0
*/
private static SchemeRegistry getDefaultSchemeRegistry(boolean fixNoHttpResponseException, int httpPort, int httpsPort) {
if (fixNoHttpResponseException) {
Log.d(LOG_TAG, "Beware! Using the fix is insecure, as it doesn't verify SSL certificates.");
} if (httpPort < 1) {
httpPort = 80;
Log.d(LOG_TAG, "Invalid HTTP port number specified, defaulting to 80");
} if (httpsPort < 1) {
httpsPort = 443;
Log.d(LOG_TAG, "Invalid HTTPS port number specified, defaulting to 443");
} // Fix to SSL flaw in API < ICS
// See https://code.google.com/p/android/issues/detail?id=13117
SSLSocketFactory sslSocketFactory;
if (fixNoHttpResponseException)
sslSocketFactory = MySSLSocketFactory.getFixedSocketFactory();
else
sslSocketFactory = SSLSocketFactory.getSocketFactory(); SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), httpPort));
schemeRegistry.register(new Scheme("https", sslSocketFactory, httpsPort)); return schemeRegistry;
} /**
* Creates a new AsyncHttpClient.
*
* @param schemeRegistry SchemeRegistry to be used
*/
public AsyncHttpClient(SchemeRegistry schemeRegistry) { BasicHttpParams httpParams = new BasicHttpParams(); ConnManagerParams.setTimeout(httpParams, timeout);
ConnManagerParams.setMaxConnectionsPerRoute(httpParams, new ConnPerRouteBean(maxConnections));
ConnManagerParams.setMaxTotalConnections(httpParams, DEFAULT_MAX_CONNECTIONS); HttpConnectionParams.setSoTimeout(httpParams, timeout);
HttpConnectionParams.setConnectionTimeout(httpParams, timeout);
HttpConnectionParams.setTcpNoDelay(httpParams, true);
HttpConnectionParams.setSocketBufferSize(httpParams, DEFAULT_SOCKET_BUFFER_SIZE); HttpProtocolParams.setVersion(httpParams, HttpVersion.HTTP_1_1);
HttpProtocolParams.setUserAgent(httpParams, String.format("android-async-http/%s (http://loopj.com/android-async-http)", VERSION)); ThreadSafeClientConnManager cm = new ThreadSafeClientConnManager(httpParams, schemeRegistry); threadPool = (ThreadPoolExecutor) Executors.newCachedThreadPool();
requestMap = new WeakHashMap<Context, List<WeakReference<Future<?>>>>();
clientHeaderMap = new HashMap<String, String>(); httpContext = new SyncBasicHttpContext(new BasicHttpContext());
httpClient = new DefaultHttpClient(cm, httpParams);
httpClient.addRequestInterceptor(new HttpRequestInterceptor() {
@Override
public void process(HttpRequest request, HttpContext context) {
if (!request.containsHeader(HEADER_ACCEPT_ENCODING)) {
request.addHeader(HEADER_ACCEPT_ENCODING, ENCODING_GZIP);
}
for (String header : clientHeaderMap.keySet()) {
request.addHeader(header, clientHeaderMap.get(header));
}
}
}); httpClient.addResponseInterceptor(new HttpResponseInterceptor() {
@Override
public void process(HttpResponse response, HttpContext context) {
final HttpEntity entity = response.getEntity();
if (entity == null) {
return;
}
final Header encoding = entity.getContentEncoding();
if (encoding != null) {
for (HeaderElement element : encoding.getElements()) {
if (element.getName().equalsIgnoreCase(ENCODING_GZIP)) {
response.setEntity(new InflatingEntity(entity));
break;
}
}
}
}
}); httpClient.setHttpRequestRetryHandler(new RetryHandler(DEFAULT_MAX_RETRIES, DEFAULT_RETRY_SLEEP_TIME_MILLIS));
} /**
* Get the underlying HttpClient instance. This is useful for setting
* additional fine-grained settings for requests by accessing the
* client's ConnectionManager, HttpParams and SchemeRegistry.
*
* @return underlying HttpClient instance
*/
public HttpClient getHttpClient() {
return this.httpClient;
} /**
* Get the underlying HttpContext instance. This is useful for getting
* and setting fine-grained settings for requests by accessing the
* context's attributes such as the CookieStore.
*
* @return underlying HttpContext instance
*/
public HttpContext getHttpContext() {
return this.httpContext;
} /**
* Sets an optional CookieStore to use when making requests
*
* @param cookieStore The CookieStore implementation to use, usually an instance of {@link PersistentCookieStore}
*/
public void setCookieStore(CookieStore cookieStore) {
httpContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore);
} /**
* Overrides the threadpool implementation used when queuing/pooling
* requests. By default, Executors.newCachedThreadPool() is used.
*
* @param threadPool an instance of {@link ThreadPoolExecutor} to use for queuing/pooling requests.
*/
public void setThreadPool(ThreadPoolExecutor threadPool) {
this.threadPool = threadPool;
} /**
* Simple interface method, to enable or disable redirects.
* If you set manually RedirectHandler on underlying HttpClient, effects of this method will be canceled.
*
* @param enableRedirects boolean
*/
public void setEnableRedirects(final boolean enableRedirects) {
httpClient.setRedirectHandler(new DefaultRedirectHandler() {
@Override
public boolean isRedirectRequested(HttpResponse response, HttpContext context) {
return enableRedirects;
}
});
} /**
* Sets the User-Agent header to be sent with each request. By default,
* "Android Asynchronous Http Client/VERSION (http://loopj.com/android-async-http/)" is used.
*
* @param userAgent the string to use in the User-Agent header.
*/
public void setUserAgent(String userAgent) {
HttpProtocolParams.setUserAgent(this.httpClient.getParams(), userAgent);
} /**
* Returns current limit of parallel connections
*
* @return maximum limit of parallel connections, default is 10
*/
public int getMaxConnections() {
return maxConnections;
} /**
* Sets maximum limit of parallel connections
*
* @param maxConnections maximum parallel connections, must be at least 1
*/
public void setMaxConnections(int maxConnections) {
if (maxConnections < 1)
maxConnections = DEFAULT_MAX_CONNECTIONS;
this.maxConnections = maxConnections;
final HttpParams httpParams = this.httpClient.getParams();
ConnManagerParams.setMaxConnectionsPerRoute(httpParams, new ConnPerRouteBean(this.maxConnections));
} /**
* Returns current socket timeout limit (milliseconds), default is 10000 (10sec)
*
* @return Socket Timeout limit in milliseconds
*/
public int getTimeout() {
return timeout;
} /**
* Set the connection and socket timeout. By default, 10 seconds.
*
* @param timeout the connect/socket timeout in milliseconds, at least 1 second
*/
public void setTimeout(int timeout) {
if (timeout < 1000)
timeout = DEFAULT_SOCKET_TIMEOUT;
this.timeout = timeout;
final HttpParams httpParams = this.httpClient.getParams();
ConnManagerParams.setTimeout(httpParams, this.timeout);
HttpConnectionParams.setSoTimeout(httpParams, this.timeout);
HttpConnectionParams.setConnectionTimeout(httpParams, this.timeout);
} /**
* Sets the Proxy by it's hostname and port
*
* @param hostname the hostname (IP or DNS name)
* @param port the port number. -1 indicates the scheme default port.
*/
public void setProxy(String hostname, int port) {
final HttpHost proxy = new HttpHost(hostname, port);
final HttpParams httpParams = this.httpClient.getParams();
httpParams.setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy);
} /**
* Sets the Proxy by it's hostname,port,username and password
*
* @param hostname the hostname (IP or DNS name)
* @param port the port number. -1 indicates the scheme default port.
* @param username the username
* @param password the password
*/
public void setProxy(String hostname, int port, String username, String password) {
httpClient.getCredentialsProvider().setCredentials(
new AuthScope(hostname, port),
new UsernamePasswordCredentials(username, password));
final HttpHost proxy = new HttpHost(hostname, port);
final HttpParams httpParams = this.httpClient.getParams();
httpParams.setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy);
} /**
* Sets the SSLSocketFactory to user when making requests. By default,
* a new, default SSLSocketFactory is used.
*
* @param sslSocketFactory the socket factory to use for https requests.
*/
public void setSSLSocketFactory(SSLSocketFactory sslSocketFactory) {
this.httpClient.getConnectionManager().getSchemeRegistry().register(new Scheme("https", sslSocketFactory, 443));
} /**
* Sets the maximum number of retries and timeout for a particular Request.
*
* @param retries maximum number of retries per request
*/
public void setMaxRetriesAndTimeout(int retries, int timeout) {
this.httpClient.setHttpRequestRetryHandler(new RetryHandler(retries, timeout));
} /**
* Sets headers that will be added to all requests this client makes (before sending).
*
* @param header the name of the header
* @param value the contents of the header
*/
public void addHeader(String header, String value) {
clientHeaderMap.put(header, value);
} /**
* Remove header from all requests this client makes (before sending).
*
* @param header the name of the header
*/
public void removeHeader(String header) {
clientHeaderMap.remove(header);
} /**
* Sets basic authentication for the request. Uses AuthScope.ANY. This is the same as
* setBasicAuth('username','password',AuthScope.ANY)
*
* @param username Basic Auth username
* @param password Basic Auth password
*/
public void setBasicAuth(String username, String password) {
AuthScope scope = AuthScope.ANY;
setBasicAuth(username, password, scope);
} /**
* Sets basic authentication for the request. You should pass in your AuthScope for security. It should be like this
* setBasicAuth("username","password", new AuthScope("host",port,AuthScope.ANY_REALM))
*
* @param username Basic Auth username
* @param password Basic Auth password
* @param scope - an AuthScope object
*/
public void setBasicAuth(String username, String password, AuthScope scope) {
UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(username, password);
this.httpClient.getCredentialsProvider().setCredentials(scope, credentials);
} /**
* Removes set basic auth credentials
*/
public void clearBasicAuth() {
this.httpClient.getCredentialsProvider().clear();
} /**
* Cancels any pending (or potentially active) requests associated with the
* passed Context.
* <p> </p>
* <b>Note:</b> This will only affect requests which were created with a non-null
* android Context. This method is intended to be used in the onDestroy
* method of your android activities to destroy all requests which are no
* longer required.
*
* @param context the android Context instance associated to the request.
* @param mayInterruptIfRunning specifies if active requests should be cancelled along with pending requests.
*/
public void cancelRequests(Context context, boolean mayInterruptIfRunning) {
List<WeakReference<Future<?>>> requestList = requestMap.get(context);
if (requestList != null) {
for (WeakReference<Future<? >> requestRef : requestList) {
Future<?> request = requestRef.get();
if (request != null) {
request.cancel(mayInterruptIfRunning);
}
}
}
requestMap.remove(context);
} //
// HTTP HEAD Requests
// /**
* Perform a HTTP HEAD request, without any parameters.
*
* @param url the URL to send the request to.
* @param responseHandler the response handler instance that should handle the response.
*/
public RequestHandle head(String url, AsyncHttpResponseHandler responseHandler) {
return head(null, url, null, responseHandler);
} /**
* Perform a HTTP HEAD request with parameters.
*
* @param url the URL to send the request to.
* @param params additional HEAD parameters to send with the request.
* @param responseHandler the response handler instance that should handle the response.
*/
public RequestHandle head(String url, RequestParams params, AsyncHttpResponseHandler responseHandler) {
return head(null, url, params, responseHandler);
} /**
* Perform a HTTP HEAD request without any parameters and track the Android Context which initiated the request.
*
* @param context the Android Context which initiated the request.
* @param url the URL to send the request to.
* @param responseHandler the response handler instance that should handle the response.
*/
public RequestHandle head(Context context, String url, AsyncHttpResponseHandler responseHandler) {
return head(context, url, null, responseHandler);
} /**
* Perform a HTTP HEAD request and track the Android Context which initiated the request.
*
* @param context the Android Context which initiated the request.
* @param url the URL to send the request to.
* @param params additional HEAD parameters to send with the request.
* @param responseHandler the response handler instance that should handle the response.
*/
public RequestHandle head(Context context, String url, RequestParams params, AsyncHttpResponseHandler responseHandler) {
return sendRequest(httpClient, httpContext, new HttpHead(getUrlWithQueryString(isUrlEncodingEnabled, url, params)), null, responseHandler, context);
} /**
* Perform a HTTP HEAD request and track the Android Context which initiated
* the request with customized headers
*
* @param context Context to execute request against
* @param url the URL to send the request to.
* @param headers set headers only for this request
* @param params additional HEAD parameters to send with the request.
* @param responseHandler the response handler instance that should handle
* the response.
*/
public RequestHandle head(Context context, String url, Header[] headers, RequestParams params, AsyncHttpResponseHandler responseHandler) {
HttpUriRequest request = new HttpHead(getUrlWithQueryString(isUrlEncodingEnabled, url, params));
if (headers != null) request.setHeaders(headers);
return sendRequest(httpClient, httpContext, request, null, responseHandler,
context);
} //
// HTTP GET Requests
// /**
* Perform a HTTP GET request, without any parameters.
*
* @param url the URL to send the request to.
* @param responseHandler the response handler instance that should handle the response.
*/
public RequestHandle get(String url, AsyncHttpResponseHandler responseHandler) {
return get(null, url, null, responseHandler);
} /**
* Perform a HTTP GET request with parameters.
*
* @param url the URL to send the request to.
* @param params additional GET parameters to send with the request.
* @param responseHandler the response handler instance that should handle the response.
*/
public RequestHandle get(String url, RequestParams params, AsyncHttpResponseHandler responseHandler) {
return get(null, url, params, responseHandler);
} /**
* Perform a HTTP GET request without any parameters and track the Android Context which initiated the request.
*
* @param context the Android Context which initiated the request.
* @param url the URL to send the request to.
* @param responseHandler the response handler instance that should handle the response.
*/
public RequestHandle get(Context context, String url, AsyncHttpResponseHandler responseHandler) {
return get(context, url, null, responseHandler);
} /**
* Perform a HTTP GET request and track the Android Context which initiated the request.
*
* @param context the Android Context which initiated the request.
* @param url the URL to send the request to.
* @param params additional GET parameters to send with the request.
* @param responseHandler the response handler instance that should handle the response.
*/
public RequestHandle get(Context context, String url, RequestParams params, AsyncHttpResponseHandler responseHandler) {
return sendRequest(httpClient, httpContext, new HttpGet(getUrlWithQueryString(isUrlEncodingEnabled, url, params)), null, responseHandler, context);
} /**
* Perform a HTTP GET request and track the Android Context which initiated
* the request with customized headers
*
* @param context Context to execute request against
* @param url the URL to send the request to.
* @param headers set headers only for this request
* @param params additional GET parameters to send with the request.
* @param responseHandler the response handler instance that should handle
* the response.
*/
public RequestHandle get(Context context, String url, Header[] headers, RequestParams params, AsyncHttpResponseHandler responseHandler) {
HttpUriRequest request = new HttpGet(getUrlWithQueryString(isUrlEncodingEnabled, url, params));
if (headers != null) request.setHeaders(headers);
return sendRequest(httpClient, httpContext, request, null, responseHandler,
context);
} //
// HTTP POST Requests
// /**
* Perform a HTTP POST request, without any parameters.
*
* @param url the URL to send the request to.
* @param responseHandler the response handler instance that should handle the response.
*/
public RequestHandle post(String url, AsyncHttpResponseHandler responseHandler) {
return post(null, url, null, responseHandler);
} /**
* Perform a HTTP POST request with parameters.
*
* @param url the URL to send the request to.
* @param params additional POST parameters or files to send with the request.
* @param responseHandler the response handler instance that should handle the response.
*/
public RequestHandle post(String url, RequestParams params, AsyncHttpResponseHandler responseHandler) {
return post(null, url, params, responseHandler);
} /**
* Perform a HTTP POST request and track the Android Context which initiated the request.
*
* @param context the Android Context which initiated the request.
* @param url the URL to send the request to.
* @param params additional POST parameters or files to send with the request.
* @param responseHandler the response handler instance that should handle the response.
*/
public RequestHandle post(Context context, String url, RequestParams params, AsyncHttpResponseHandler responseHandler) {
return post(context, url, paramsToEntity(params, responseHandler), null, responseHandler);
} /**
* Perform a HTTP POST request and track the Android Context which initiated the request.
*
* @param context the Android Context which initiated the request.
* @param url the URL to send the request to.
* @param entity a raw {@link org.apache.http.HttpEntity} to send with the request, for example, use this to send string/json/xml payloads to a server by passing a {@link org.apache.http.entity.StringEntity}.
* @param contentType the content type of the payload you are sending, for example application/json if sending a json payload.
* @param responseHandler the response ha ndler instance that should handle the response.
*/
public RequestHandle post(Context context, String url, HttpEntity entity, String contentType, AsyncHttpResponseHandler responseHandler) {
return sendRequest(httpClient, httpContext, addEntityToRequestBase(new HttpPost(url), entity), contentType, responseHandler, context);
} /**
* Perform a HTTP POST request and track the Android Context which initiated
* the request. Set headers only for this request
*
* @param context the Android Context which initiated the request.
* @param url the URL to send the request to.
* @param headers set headers only for this request
* @param params additional POST parameters to send with the request.
* @param contentType the content type of the payload you are sending, for
* example application/json if sending a json payload.
* @param responseHandler the response handler instance that should handle
* the response.
*/
public RequestHandle post(Context context, String url, Header[] headers, RequestParams params, String contentType,
AsyncHttpResponseHandler responseHandler) {
HttpEntityEnclosingRequestBase request = new HttpPost(url);
if (params != null) request.setEntity(paramsToEntity(params, responseHandler));
if (headers != null) request.setHeaders(headers);
return sendRequest(httpClient, httpContext, request, contentType,
responseHandler, context);
} /**
* Perform a HTTP POST request and track the Android Context which initiated
* the request. Set headers only for this request
*
* @param context the Android Context which initiated the request.
* @param url the URL to send the request to.
* @param headers set headers only for this request
* @param entity a raw {@link HttpEntity} to send with the request, for
* example, use this to send string/json/xml payloads to a server by
* passing a {@link org.apache.http.entity.StringEntity}.
* @param contentType the content type of the payload you are sending, for
* example application/json if sending a json payload.
* @param responseHandler the response handler instance that should handle
* the response.
*/
public RequestHandle post(Context context, String url, Header[] headers, HttpEntity entity, String contentType,
AsyncHttpResponseHandler responseHandler) {
HttpEntityEnclosingRequestBase request = addEntityToRequestBase(new HttpPost(url), entity);
if (headers != null) request.setHeaders(headers);
return sendRequest(httpClient, httpContext, request, contentType, responseHandler, context);
} //
// HTTP PUT Requests
// /**
* Perform a HTTP PUT request, without any parameters.
*
* @param url the URL to send the request to.
* @param responseHandler the response handler instance that should handle the response.
*/
public RequestHandle put(String url, AsyncHttpResponseHandler responseHandler) {
return put(null, url, null, responseHandler);
} /**
* Perform a HTTP PUT request with parameters.
*
* @param url the URL to send the request to.
* @param params additional PUT parameters or files to send with the request.
* @param responseHandler the response handler instance that should handle the response.
*/
public RequestHandle put(String url, RequestParams params, AsyncHttpResponseHandler responseHandler) {
return put(null, url, params, responseHandler);
} /**
* Perform a HTTP PUT request and track the Android Context which initiated the request.
*
* @param context the Android Context which initiated the request.
* @param url the URL to send the request to.
* @param params additional PUT parameters or files to send with the request.
* @param responseHandler the response handler instance that should handle the response.
*/
public RequestHandle put(Context context, String url, RequestParams params, AsyncHttpResponseHandler responseHandler) {
return put(context, url, paramsToEntity(params, responseHandler), null, responseHandler);
} /**
* Perform a HTTP PUT request and track the Android Context which initiated the request.
* And set one-time headers for the request
*
* @param context the Android Context which initiated the request.
* @param url the URL to send the request to.
* @param entity a raw {@link HttpEntity} to send with the request, for example, use this to send string/json/xml payloads to a server by passing a {@link org.apache.http.entity.StringEntity}.
* @param contentType the content type of the payload you are sending, for example application/json if sending a json payload.
* @param responseHandler the response handler instance that should handle the response.
*/
public RequestHandle put(Context context, String url, HttpEntity entity, String contentType, AsyncHttpResponseHandler responseHandler) {
return sendRequest(httpClient, httpContext, addEntityToRequestBase(new HttpPut(url), entity), contentType, responseHandler, context);
} /**
* Perform a HTTP PUT request and track the Android Context which initiated the request.
* And set one-time headers for the request
*
* @param context the Android Context which initiated the request.
* @param url the URL to send the request to.
* @param headers set one-time headers for this request
* @param entity a raw {@link HttpEntity} to send with the request, for example, use this to send string/json/xml payloads to a server by passing a {@link org.apache.http.entity.StringEntity}.
* @param contentType the content type of the payload you are sending, for example application/json if sending a json payload.
* @param responseHandler the response handler instance that should handle the response.
*/
public RequestHandle put(Context context, String url, Header[] headers, HttpEntity entity, String contentType, AsyncHttpResponseHandler responseHandler) {
HttpEntityEnclosingRequestBase request = addEntityToRequestBase(new HttpPut(url), entity);
if (headers != null) request.setHeaders(headers);
return sendRequest(httpClient, httpContext, request, contentType, responseHandler, context);
} //
// HTTP DELETE Requests
// /**
* Perform a HTTP DELETE request.
*
* @param url the URL to send the request to.
* @param responseHandler the response handler instance that should handle the response.
*/
public RequestHandle delete(String url, AsyncHttpResponseHandler responseHandler) {
return delete(null, url, responseHandler);
} /**
* Perform a HTTP DELETE request.
*
* @param context the Android Context which initiated the request.
* @param url the URL to send the request to.
* @param responseHandler the response handler instance that should handle the response.
*/
public RequestHandle delete(Context context, String url, AsyncHttpResponseHandler responseHandler) {
final HttpDelete delete = new HttpDelete(url);
return sendRequest(httpClient, httpContext, delete, null, responseHandler, context);
} /**
* Perform a HTTP DELETE request.
*
* @param context the Android Context which initiated the request.
* @param url the URL to send the request to.
* @param headers set one-time headers for this request
* @param responseHandler the response handler instance that should handle the response.
*/
public RequestHandle delete(Context context, String url, Header[] headers, AsyncHttpResponseHandler responseHandler) {
final HttpDelete delete = new HttpDelete(url);
if (headers != null) delete.setHeaders(headers);
return sendRequest(httpClient, httpContext, delete, null, responseHandler, context);
} /**
* Perform a HTTP DELETE request.
*
* @param context the Android Context which initiated the request.
* @param url the URL to send the request to.
* @param headers set one-time headers for this request
* @param params additional DELETE parameters or files to send along with request
* @param responseHandler the response handler instance that should handle the response.
*/
public RequestHandle delete(Context context, String url, Header[] headers, RequestParams params, AsyncHttpResponseHandler responseHandler) {
HttpDelete httpDelete = new HttpDelete(getUrlWithQueryString(isUrlEncodingEnabled, url, params));
if (headers != null) httpDelete.setHeaders(headers);
return sendRequest(httpClient, httpContext, httpDelete, null, responseHandler, context);
} /**
* Puts a new request in queue as a new thread in pool to be executed
*
* @param client HttpClient to be used for request, can differ in single requests
* @param contentType MIME body type, for POST and PUT requests, may be null
* @param context Context of Android application, to hold the reference of request
* @param httpContext HttpContext in which the request will be executed
* @param responseHandler ResponseHandler or its subclass to put the response into
* @param uriRequest instance of HttpUriRequest, which means it must be of HttpDelete, HttpPost, HttpGet, HttpPut, etc.
*/
protected RequestHandle sendRequest(DefaultHttpClient client, HttpContext httpContext, HttpUriRequest uriRequest, String contentType, AsyncHttpResponseHandler responseHandler, Context context) {
if (contentType != null) {
uriRequest.addHeader("Content-Type", contentType);
} Future<?> request = threadPool.submit(new AsyncHttpRequest(client, httpContext, uriRequest, responseHandler)); if (context != null) {
// Add request to request map
List<WeakReference<Future<? >>> requestList = requestMap.get(context);
if (requestList == null) {
requestList = new LinkedList<WeakReference<Future<?>>>();
requestMap.put(context, requestList);
} requestList.add(new WeakReference<Future<?>>(request)); // TODO: Remove dead weakrefs from requestLists?
} return new RequestHandle(request);
} /**
* Sets state of URL encoding feature, see bug #227, this method
* allows you to turn off and on this auto-magic feature on-demand.
*
* @param enabled desired state of feature
*/
public void setURLEncodingEnabled(boolean enabled) {
this.isUrlEncodingEnabled = enabled;
} /**
* Will encode url, if not disabled, and adds params on the end of it
*
* @param url String with URL, should be valid URL without params
* @param params RequestParams to be appended on the end of URL
*/
public static String getUrlWithQueryString(boolean isUrlEncodingEnabled, String url, RequestParams params) {
if (isUrlEncodingEnabled)
url = url.replace(" ", "%20"); if (params != null) {
String paramString = params.getParamString();
if (!url.contains("?")) {
url += "? " + paramString;
} else {
url += "&" + paramString;
}
} return url;
} /**
* Returns HttpEntity containing data from RequestParams included with request declaration.
* Allows also passing progress from upload via provided ResponseHandler
*
* @param params additional request params
* @param responseHandler AsyncHttpResponseHandler or its subclass to be notified on progress
*/
private HttpEntity paramsToEntity(RequestParams params, AsyncHttpResponseHandler responseHandler) {
HttpEntity entity = null; try {
if (params != null) {
entity = params.getEntity(responseHandler);
}
} catch (Throwable t) {
if (responseHandler != null)
responseHandler.sendFailureMessage(0, null, null, t);
else
t.printStackTrace();
} return entity;
} public boolean isUrlEncodingEnabled() {
return isUrlEncodingEnabled;
} /**
* Applicable only to HttpRequest methods extending HttpEntityEnclosingRequestBase, which is for example not DELETE
*
* @param entity entity to be included within the request
* @param requestBase HttpRequest instance, must not be null
*/
private HttpEntityEnclosingRequestBase addEntityToRequestBase(HttpEntityEnclosingRequestBase requestBase, HttpEntity entity) {
if (entity != null) {
requestBase.setEntity(entity);
} return requestBase;
} /**
* Enclosing entity to hold stream of gzip decoded data for accessing HttpEntity contents
*/
private static class InflatingEntity extends HttpEntityWrapper {
public InflatingEntity(HttpEntity wrapped) {
super(wrapped);
} @Override
public InputStream getContent() throws IOException {
return new GZIPInputStream(wrappedEntity.getContent());
} @Override
public long getContentLength() {
return -1;
}
}
}
loopj\android\http\AsyncHttpRequest.java
/*
Android Asynchronous Http Client
Copyright (c) 2011 James Smith <james@loopj.com>
http://loopj.com Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/ package com.loopj.android.http; import org.apache.http.HttpResponse;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.impl.client.AbstractHttpClient;
import org.apache.http.protocol.HttpContext; import java.io.IOException;
import java.net.MalformedURLException;
import java.net.UnknownHostException; class AsyncHttpRequest implements Runnable {
private final AbstractHttpClient client;
private final HttpContext context;
private final HttpUriRequest request;
private final AsyncHttpResponseHandler responseHandler;
private int executionCount; public AsyncHttpRequest(AbstractHttpClient client, HttpContext context, HttpUriRequest request, AsyncHttpResponseHandler responseHandler) {
this.client = client;
this.context = context;
this.request = request;
this.responseHandler = responseHandler;
} @Override
public void run() {
if (responseHandler != null) {
responseHandler.sendStartMessage();
} try {
makeRequestWithRetries();
} catch (IOException e) {
if (responseHandler != null) {
responseHandler.sendFailureMessage(0, null, null, e);
}
} if (responseHandler != null) {
responseHandler.sendFinishMessage();
}
} private void makeRequest() throws IOException {
if (!Thread.currentThread().isInterrupted()) {
// Fixes #115
if (request.getURI().getScheme() == null) {
// subclass of IOException so processed in the caller
throw new MalformedURLException("No valid URI scheme was provided");
} HttpResponse response = client.execute(request, context); if (!Thread.currentThread().isInterrupted()) {
if (responseHandler != null) {
responseHandler.sendResponseMessage(response);
}
}
}
} private void makeRequestWithRetries() throws IOException {
boolean retry = true;
IOException cause = null;
HttpRequestRetryHandler retryHandler = client.getHttpRequestRetryHandler();
try
{
while (retry) {
try {
makeRequest();
return;
} catch (UnknownHostException e) {
// switching between WI-FI and mobile data networks can cause a retry which then results in an UnknownHostException
// while the WI-FI is initialising. The retry logic will be invoked here, if this is NOT the first retry
// (to assist in genuine cases of unknown host) which seems better than outright failure
cause = new IOException("UnknownHostException exception: " + e.getMessage());
retry = (executionCount > 0) && retryHandler.retryRequest(cause, ++executionCount, context);
} catch (NullPointerException e) {
// there's a bug in HttpClient 4.0.x that on some occasions causes
// DefaultRequestExecutor to throw an NPE, see
// http://code.google.com/p/android/issues/detail?id=5255
cause = new IOException("NPE in HttpClient: " + e.getMessage());
retry = retryHandler.retryRequest(cause, ++executionCount, context);
} catch (IOException e) {
cause = e;
retry = retryHandler.retryRequest(cause, ++executionCount, context);
}
if(retry && (responseHandler != null)) {
responseHandler.sendRetryMessage();
}
}
} catch (Exception e) {
// catch anything else to ensure failure message is propagated
cause = new IOException("Unhandled exception: " + e.getMessage());
} // cleaned up to throw IOException
throw(cause);
}
}
loopj\android\http\AsyncHttpResponseHandler.java
/*
Android Asynchronous Http Client
Copyright (c) 2011 James Smith <james@loopj.com>
http://loopj.com Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/ package com.loopj.android.http; import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log; import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.StatusLine;
import org.apache.http.client.HttpResponseException;
import org.apache.http.util.ByteArrayBuffer; import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.lang.ref.WeakReference; /**
* Used to intercept and handle the responses from requests made using
* {@link AsyncHttpClient}. The {@link #onSuccess(int, org.apache.http.Header[], byte[])} method is
* designed to be anonymously overridden with your own response handling code.
* <p> </p>
* Additionally, you can override the {@link #onFailure(int, org.apache.http.Header[], byte[], Throwable)},
* {@link #onStart()}, {@link #onFinish()}, {@link #onRetry()} and {@link #onProgress(int, int)} methods as required.
* <p> </p>
* For example:
* <p> </p>
* <pre>
* AsyncHttpClient client = new AsyncHttpClient();
* client.get("http://www.google.com", new AsyncHttpResponseHandler() {
* @Override
* public void onStart() {
* // Initiated the request
* }
*
* @Override
* public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {
* // Successfully got a response
* }
*
* @Override
* public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) {
* // Response failed :(
* }
*
* @Override
* public void onRetry() {
* // Request was retried
* }
*
* @Override
* public void onProgress(int bytesWritten, int totalSize) {
* // Progress notification
* }
*
* @Override
* public void onFinish() {
* // Completed the request (either success or failure)
* }
* });
* </pre>
*/
public class AsyncHttpResponseHandler {
private static final String LOG_TAG = "AsyncHttpResponseHandler"; protected static final int SUCCESS_MESSAGE = 0;
protected static final int FAILURE_MESSAGE = 1;
protected static final int START_MESSAGE = 2;
protected static final int FINISH_MESSAGE = 3;
protected static final int PROGRESS_MESSAGE = 4;
protected static final int RETRY_MESSAGE = 5; protected static final int BUFFER_SIZE = 4096; private Handler handler;
public static final String DEFAULT_CHARSET = "UTF-8";
private String responseCharset = DEFAULT_CHARSET;
private Boolean useSynchronousMode = false; // avoid leaks by using a non-anonymous handler class
// with a weak reference
static class ResponderHandler extends Handler {
private final WeakReference<AsyncHttpResponseHandler> mResponder; ResponderHandler(AsyncHttpResponseHandler service) {
mResponder = new WeakReference<AsyncHttpResponseHandler>(service);
} @Override
public void handleMessage(Message msg) {
AsyncHttpResponseHandler service = mResponder.get();
if (service != null) {
service.handleMessage(msg);
}
}
} public boolean getUseSynchronousMode() {
return (useSynchronousMode);
} /**
* Set the response handler to use synchronous mode or not
*
* @param value true indicates that synchronous mode should be used
*/
public void setUseSynchronousMode(Boolean value) {
useSynchronousMode = value;
} /**
* Sets the charset for the response string. If not set, the default is UTF-8.
*
* @param charset to be used for the response string.
* @see <a href="http://docs.oracle.com/javase/7/docs/api/java/nio/charset/Charset.html">Charset</a>
*/
public void setCharset(final String charset) {
this.responseCharset = charset;
} public String getCharset() {
return this.responseCharset;
} /**
* Creates a new AsyncHttpResponseHandler
*/
public AsyncHttpResponseHandler() {
// Set up a handler to post events back to the correct thread if possible
if (Looper.myLooper() != null) {
handler = new ResponderHandler(this);
}
} //
// Callbacks to be overridden, typically anonymously
// /**
* Fired when the request progress, override to handle in your own code
*
* @param bytesWritten offset from start of file
* @param totalSize total size of file
*/
public void onProgress(int bytesWritten, int totalSize) {
} /**
* Fired when the request is started, override to handle in your own code
*/
public void onStart() {
} /**
* Fired in all cases when the request is finished, after both success and failure, override to handle in your own code
*/
public void onFinish() {
} /**
* Fired when a request returns successfully, override to handle in your own code
*
* @param content the body of the HTTP response from the server
* @deprecated use {@link #onSuccess(int, Header[], byte[])}
*/
@Deprecated
public void onSuccess(String content) {
} /**
* Fired when a request returns successfully, override to handle in your own code
*
* @param statusCode the status code of the response
* @param headers the headers of the HTTP response
* @param content the body of the HTTP response from the server
* @deprecated use {@link #onSuccess(int, Header[], byte[])}
*/
@Deprecated
public void onSuccess(int statusCode, Header[] headers, String content) {
onSuccess(statusCode, content);
} /**
* Fired when a request returns successfully, override to handle in your own code
*
* @param statusCode the status code of the response
* @param content the body of the HTTP response from the server
* @deprecated use {@link #onSuccess(int, Header[], byte[])}
*/
@Deprecated
public void onSuccess(int statusCode, String content) {
onSuccess(content);
} /**
* Fired when a request returns successfully, override to handle in your own code
*
* @param statusCode the status code of the response
* @param headers return headers, if any
* @param responseBody the body of the HTTP response from the server
*/
public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {
try {
String response = new String(responseBody, getCharset());
onSuccess(statusCode, headers, response);
} catch (UnsupportedEncodingException e) {
Log.e(LOG_TAG, e.toString());
onFailure(statusCode, headers, e, null);
}
} /**
* Fired when a request fails to complete, override to handle in your own code
*
* @param error the underlying cause of the failure
* @deprecated use {@link #onFailure(Throwable, String)}
*/
@Deprecated
public void onFailure(Throwable error) {
} /**
* Fired when a request fails to complete, override to handle in your own code
*
* @param error the underlying cause of the failure
* @param content the response body, if any
* @deprecated use {@link #onFailure(int, Header[], byte[], Throwable)}
*/
@Deprecated
public void onFailure(Throwable error, String content) {
// By default, call the deprecated onFailure(Throwable) for compatibility
onFailure(error);
} /**
* Fired when a request fails to complete, override to handle in your own code
*
* @param statusCode return HTTP status code
* @param error the underlying cause of the failure
* @param content the response body, if any
* @deprecated use {@link #onFailure(int, Header[], byte[], Throwable)}
*/
@Deprecated
public void onFailure(int statusCode, Throwable error, String content) {
// By default, call the chain method onFailure(Throwable,String)
onFailure(error, content);
} /**
* Fired when a request fails to complete, override to handle in your own code
*
* @param statusCode return HTTP status code
* @param headers return headers, if any
* @param error the underlying cause of the failure
* @param content the response body, if any
* @deprecated use {@link #onFailure(int, Header[], byte[], Throwable)}
*/
@Deprecated
public void onFailure(int statusCode, Header[] headers, Throwable error, String content) {
// By default, call the chain method onFailure(int,Throwable,String)
onFailure(statusCode, error, content);
} /**
* Fired when a request fails to complete, override to handle in your own code
*
* @param statusCode return HTTP status code
* @param headers return headers, if any
* @param responseBody the response body, if any
* @param error the underlying cause of the failure
*/
public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) {
String response;
try {
response = new String(responseBody, getCharset());
onFailure(statusCode, headers, error, response);
} catch (UnsupportedEncodingException e) {
Log.e(LOG_TAG, e.toString());
onFailure(statusCode, headers, e, null);
}
} /**
* Fired when a retry occurs, override to handle in your own code
*/
public void onRetry() {
} //
// Pre-processing of messages (executes in background threadpool thread)
// protected void sendProgressMessage(int bytesWritten, int totalSize) {
sendMessage(obtainMessage(PROGRESS_MESSAGE, new Object[]{bytesWritten, totalSize}));
} protected void sendSuccessMessage(int statusCode, Header[] headers, byte[] responseBody) {
sendMessage(obtainMessage(SUCCESS_MESSAGE, new Object[]{statusCode, headers, responseBody}));
} protected void sendFailureMessage(int statusCode, Header[] headers, byte[] responseBody, Throwable error) {
sendMessage(obtainMessage(FAILURE_MESSAGE, new Object[]{statusCode, headers, responseBody, error}));
} protected void sendStartMessage() {
sendMessage(obtainMessage(START_MESSAGE, null));
} protected void sendFinishMessage() {
sendMessage(obtainMessage(FINISH_MESSAGE, null));
} protected void sendRetryMessage() {
sendMessage(obtainMessage(RETRY_MESSAGE, null));
} // Methods which emulate android's Handler and Message methods
protected void handleMessage(Message msg) {
Object[] response; switch (msg.what) {
case SUCCESS_MESSAGE:
response = (Object[]) msg.obj;
if (response != null && response.length >= 3)
onSuccess((Integer) response[0], (Header[]) response[1], (byte[]) response[2]);
else
Log.e(LOG_TAG, "SUCCESS_MESSAGE didn't got enough params");
break;
case FAILURE_MESSAGE:
response = (Object[]) msg.obj;
if (response != null && response.length >= 4)
onFailure((Integer) response[0], (Header[]) response[1], (byte[]) response[2], (Throwable) response[3]);
else
Log.e(LOG_TAG, "FAILURE_MESSAGE didn't got enough params");
break;
case START_MESSAGE:
onStart();
break;
case FINISH_MESSAGE:
onFinish();
break;
case PROGRESS_MESSAGE:
response = (Object[]) msg.obj;
if (response != null && response.length >= 2)
onProgress((Integer) response[0], (Integer) response[1]);
else
Log.e(LOG_TAG, "PROGRESS_MESSAGE didn't got enough params");
break;
case RETRY_MESSAGE:
onRetry();
break;
}
} protected void sendMessage(Message msg) {
if (getUseSynchronousMode() || handler == null) {
handleMessage(msg);
} else if (!Thread.currentThread().isInterrupted()) { // do not send messages if request has been cancelled
handler.sendMessage(msg);
}
} protected void postRunnable(Runnable r) {
if (r != null) {
handler.post(r);
}
} protected Message obtainMessage(int responseMessage, Object response) {
Message msg;
if (handler != null) {
msg = handler.obtainMessage(responseMessage, response);
} else {
msg = Message.obtain();
if (msg != null) {
msg.what = responseMessage;
msg.obj = response;
}
}
return msg;
} // Interface to AsyncHttpRequest
void sendResponseMessage(HttpResponse response) throws IOException {
// do not process if request has been cancelled
if (!Thread.currentThread().isInterrupted()) {
StatusLine status = response.getStatusLine();
byte[] responseBody;
responseBody = getResponseData(response.getEntity());
// additional cancellation check as getResponseData() can take non-zero time to process
if (!Thread.currentThread().isInterrupted()) {
if (status.getStatusCode() >= 300) {
sendFailureMessage(status.getStatusCode(), response.getAllHeaders(), responseBody, new HttpResponseException(status.getStatusCode(), status.getReasonPhrase()));
} else {
sendSuccessMessage(status.getStatusCode(), response.getAllHeaders(), responseBody);
}
}
}
} byte[] getResponseData(HttpEntity entity) throws IOException {
byte[] responseBody = null;
if (entity != null) {
InputStream instream = entity.getContent();
if (instream != null) {
long contentLength = entity.getContentLength();
if (contentLength > Integer.MAX_VALUE) {
throw new IllegalArgumentException("HTTP entity too large to be buffered in memory");
}
if (contentLength < 0) {
contentLength = BUFFER_SIZE;
}
try {
ByteArrayBuffer buffer = new ByteArrayBuffer((int) contentLength);
try {
byte[] tmp = new byte[BUFFER_SIZE];
int l, count = 0;
// do not send messages if request has been cancelled
while ((l = instream.read(tmp)) != -1 && !Thread.currentThread().isInterrupted()) {
count += l;
buffer.append(tmp, 0, l);
sendProgressMessage(count, (int) contentLength);
}
} finally {
instream.close();
}
responseBody = buffer.buffer();
} catch (OutOfMemoryError e) {
System.gc();
throw new IOException("File too large to fit into available memory");
}
}
}
return responseBody;
}
}
\loopj\android\http\BinaryHttpResponseHandler.java
/*
Android Asynchronous Http Client
Copyright (c) 2011 James Smith <james@loopj.com>
http://loopj.com Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/ package com.loopj.android.http; import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.StatusLine;
import org.apache.http.client.HttpResponseException; import java.io.IOException;
import java.util.regex.Pattern; /**
* Used to intercept and handle the responses from requests made using
* {@link AsyncHttpClient}. Receives response body as byte array with a
* content-type whitelist. (e.g. checks Content-Type against allowed list,
* Content-length).
* <p> </p>
* For example:
* <p> </p>
* <pre>
* AsyncHttpClient client = new AsyncHttpClient();
* String[] allowedTypes = new String[] { "image/png" };
* client.get("http://www.example.com/image.png", new BinaryHttpResponseHandler(allowedTypes) {
* @Override
* public void onSuccess(byte[] imageData) {
* // Successfully got a response
* }
*
* @Override
* public void onFailure(Throwable e, byte[] imageData) {
* // Response failed :(
* }
* });
* </pre>
*/
public class BinaryHttpResponseHandler extends AsyncHttpResponseHandler {
// Allow images by default
private String[] mAllowedContentTypes = new String[]{
"image/jpeg",
"image/png"
}; /**
* Creates a new BinaryHttpResponseHandler
*/
public BinaryHttpResponseHandler() {
super();
} /**
* Creates a new BinaryHttpResponseHandler, and overrides the default allowed
* content types with passed String array (hopefully) of content types.
*
* @param allowedContentTypes content types array, eg. 'image/jpeg'
*/
public BinaryHttpResponseHandler(String[] allowedContentTypes) {
this();
mAllowedContentTypes = allowedContentTypes;
} //
// Callbacks to be overridden, typically anonymously
// /**
* Fired when a request returns successfully, override to handle in your own code
*
* @param binaryData the body of the HTTP response from the server
*/
public void onSuccess(byte[] binaryData) {
} /**
* Fired when a request returns successfully, override to handle in your own code
*
* @param statusCode the status code of the response
* @param binaryData the body of the HTTP response from the server
*/
public void onSuccess(int statusCode, byte[] binaryData) {
onSuccess(binaryData);
} /**
* Fired when a request returns successfully, override to handle in your own code
*
* @param statusCode response HTTP statuse code
* @param headers response headers, if any
* @param responseData the response body, if any
*/ @Override
public void onSuccess(int statusCode, Header[] headers, byte[] responseData) {
onSuccess(statusCode, responseData);
} /**
* Fired when a request fails to complete, override to handle in your own code
*
* @param statusCode response HTTP statuse code
* @param headers response headers, if any
* @param responseData the response body, if any
* @param error the underlying cause of the failure
*/ @Override
public void onFailure(int statusCode, Header[] headers, byte[] responseData, Throwable error) {
onFailure(statusCode, error, null);
} //
// Pre-processing of messages (in original calling thread, typically the UI thread)
// // Interface to AsyncHttpRequest
@Override
protected void sendResponseMessage(HttpResponse response) throws IOException {
StatusLine status = response.getStatusLine();
Header[] contentTypeHeaders = response.getHeaders("Content-Type");
if (contentTypeHeaders.length != 1) {
//malformed/ambiguous HTTP Header, ABORT!
sendFailureMessage(status.getStatusCode(), response.getAllHeaders(), null, new HttpResponseException(status.getStatusCode(), "None, or more than one, Content-Type Header found!"));
return;
}
Header contentTypeHeader = contentTypeHeaders[0];
boolean foundAllowedContentType = false;
for (String anAllowedContentType : mAllowedContentTypes) {
if (Pattern.matches(anAllowedContentType, contentTypeHeader.getValue())) {
foundAllowedContentType = true;
}
}
if (!foundAllowedContentType) {
//Content-Type not in allowed list, ABORT!
sendFailureMessage(status.getStatusCode(), response.getAllHeaders(), null, new HttpResponseException(status.getStatusCode(), "Content-Type not allowed!"));
return;
}
super.sendResponseMessage( response );
}
}
\loopj\android\http\FileAsyncHttpResponseHandler.java
package com.loopj.android.http; import org.apache.http.Header;
import org.apache.http.HttpEntity; import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream; public class FileAsyncHttpResponseHandler extends AsyncHttpResponseHandler { private File mFile; public FileAsyncHttpResponseHandler(File file) {
super();
this.mFile = file;
} public void onSuccess(File file) {
} public void onSuccess(int statusCode, File file) {
onSuccess(file);
} public void onFailure(Throwable e, File response) {
// By default call lower chain method
onFailure(e);
} public void onFailure(int statusCode, Throwable e, File response) {
// By default call lower chain method
onFailure(e, response);
} public void onFailure(int statusCode, Header[] headers, Throwable e, File response) {
// By default call lower chain method
onFailure(statusCode, e, response);
} @Override
public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) {
onFailure(statusCode, headers, error, mFile);
} @Override
public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {
onSuccess(statusCode, mFile);
} @Override
byte[] getResponseData(HttpEntity entity) throws IOException {
if (entity != null) {
InputStream instream = entity.getContent();
long contentLength = entity.getContentLength();
FileOutputStream buffer = new FileOutputStream(this.mFile);
if (instream != null) {
try {
byte[] tmp = new byte[BUFFER_SIZE];
int l, count = 0;
// do not send messages if request has been cancelled
while ((l = instream.read(tmp)) != -1 && !Thread.currentThread().isInterrupted()) {
count += l;
buffer.write(tmp, 0, l);
sendProgressMessage(count, (int) contentLength);
}
} finally {
instream.close();
buffer.flush();
buffer.close();
}
}
}
return null;
} }
loopj\android\http\FileAsyncHttpResponseHandler.java
package com.loopj.android.http; import org.apache.http.Header;
import org.apache.http.HttpEntity; import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream; public class FileAsyncHttpResponseHandler extends AsyncHttpResponseHandler { private File mFile; public FileAsyncHttpResponseHandler(File file) {
super();
this.mFile = file;
} public void onSuccess(File file) {
} public void onSuccess(int statusCode, File file) {
onSuccess(file);
} public void onFailure(Throwable e, File response) {
// By default call lower chain method
onFailure(e);
} public void onFailure(int statusCode, Throwable e, File response) {
// By default call lower chain method
onFailure(e, response);
} public void onFailure(int statusCode, Header[] headers, Throwable e, File response) {
// By default call lower chain method
onFailure(statusCode, e, response);
} @Override
public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) {
onFailure(statusCode, headers, error, mFile);
} @Override
public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {
onSuccess(statusCode, mFile);
} @Override
byte[] getResponseData(HttpEntity entity) throws IOException {
if (entity != null) {
InputStream instream = entity.getContent();
long contentLength = entity.getContentLength();
FileOutputStream buffer = new FileOutputStream(this.mFile);
if (instream != null) {
try {
byte[] tmp = new byte[BUFFER_SIZE];
int l, count = 0;
// do not send messages if request has been cancelled
while ((l = instream.read(tmp)) != -1 && !Thread.currentThread().isInterrupted()) {
count += l;
buffer.write(tmp, 0, l);
sendProgressMessage(count, (int) contentLength);
}
} finally {
instream.close();
buffer.flush();
buffer.close();
}
}
}
return null;
} }
loopj\android\http\JsonHttpResponseHandler.java
/*
Android Asynchronous Http Client
Copyright (c) 2011 James Smith <james@loopj.com>
http://loopj.com Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/ package com.loopj.android.http; import android.util.Log; import org.apache.http.Header;
import org.apache.http.HttpStatus;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONTokener; import java.io.UnsupportedEncodingException; /**
* Used to intercept and handle the responses from requests made using
* {@link AsyncHttpClient}, with automatic parsing into a {@link JSONObject}
* or {@link JSONArray}.
* <p> </p>
* This class is designed to be passed to get, post, put and delete requests
* with the {@link #onSuccess(JSONObject)} or {@link #onSuccess(JSONArray)}
* methods anonymously overridden.
* <p> </p>
* Additionally, you can override the other event methods from the
* parent class.
*/
public class JsonHttpResponseHandler extends TextHttpResponseHandler {
private static final String LOG_TAG = "JsonHttpResponseHandler"; /**
* Creates a new JsonHttpResponseHandler
*/ public JsonHttpResponseHandler() {
super(DEFAULT_CHARSET);
} public JsonHttpResponseHandler(String encoding) {
super(encoding);
} //
// Callbacks to be overridden, typically anonymously
// /**
* Fired when a request returns successfully and contains a json object
* at the base of the response string. Override to handle in your
* own code.
*
* @param response the parsed json object found in the server response (if any)
*/
public void onSuccess(JSONObject response) {
} /**
* Fired when a request returns successfully and contains a json array
* at the base of the response string. Override to handle in your
* own code.
*
* @param response the parsed json array found in the server response (if any)
*/
public void onSuccess(JSONArray response) {
} /**
* Fired when a request returns successfully and contains a json object
* at the base of the response string. Override to handle in your
* own code.
*
* @param statusCode the status code of the response
* @param headers the headers of the HTTP response
* @param response the parsed json object found in the server response (if any)
*/
public void onSuccess(int statusCode, Header[] headers, JSONObject response) {
onSuccess(statusCode, response);
} /**
* Fired when a request returns successfully and contains a json object
* at the base of the response string. Override to handle in your
* own code.
*
* @param statusCode the status code of the response
* @param response the parsed json object found in the server response (if any)
*/
public void onSuccess(int statusCode, JSONObject response) {
onSuccess(response);
} /**
* Fired when a request returns successfully and contains a json array
* at the base of the response string. Override to handle in your
* own code.
*
* @param statusCode the status code of the response
* @param headers the headers of the HTTP response
* @param response the parsed json array found in the server response (if any)
*/
public void onSuccess(int statusCode, Header[] headers, JSONArray response) {
onSuccess(statusCode, response);
} /**
* Fired when a request returns successfully and contains a json array
* at the base of the response string. Override to handle in your
* own code.
*
* @param statusCode the status code of the response
* @param response the parsed json array found in the server response (if any)
*/
public void onSuccess(int statusCode, JSONArray response) {
onSuccess(response);
} public void onFailure(Throwable e, JSONObject errorResponse) {
onFailure(e);
} public void onFailure(int statusCode, Throwable e, JSONObject errorResponse) {
onFailure(e, errorResponse);
} public void onFailure(int statusCode, Header[] headers, Throwable e, JSONObject errorResponse) {
onFailure(statusCode, e, errorResponse);
} public void onFailure(Throwable e, JSONArray errorResponse) {
onFailure(e);
} public void onFailure(int statusCode, Throwable e, JSONArray errorResponse) {
onFailure(e, errorResponse);
} public void onFailure(int statusCode, Header[] headers, Throwable e, JSONArray errorResponse) {
onFailure(statusCode, e, errorResponse);
} @Override
public void onSuccess(final int statusCode, final Header[] headers, final String responseBody) {
if (statusCode != HttpStatus.SC_NO_CONTENT) {
new Thread(new Runnable() {
@Override
public void run() {
try {
final Object jsonResponse = parseResponse(responseBody);
postRunnable(new Runnable() {
@Override
public void run() {
if (jsonResponse instanceof JSONObject) {
onSuccess(statusCode, headers, (JSONObject) jsonResponse);
} else if (jsonResponse instanceof JSONArray) {
onSuccess(statusCode, headers, (JSONArray) jsonResponse);
} else if (jsonResponse instanceof String) {
onSuccess(statusCode, headers, (String) jsonResponse);
} else {
onFailure(new JSONException("Unexpected type " + jsonResponse.getClass().getName()), (JSONObject) null);
} }
});
} catch (final JSONException ex) {
postRunnable(new Runnable() {
@Override
public void run() {
onFailure(ex, (JSONObject) null);
}
});
}
}
}).start();
} else {
onSuccess(statusCode, headers, new JSONObject());
}
} @Override
public void onFailure(final int statusCode, final Header[] headers, final String responseBody, final Throwable e) {
if (responseBody != null) {
new Thread(new Runnable() {
@Override
public void run() {
try {
final Object jsonResponse = parseResponse(responseBody);
postRunnable(new Runnable() {
@Override
public void run() {
if (jsonResponse instanceof JSONObject) {
onFailure(statusCode, headers, e, (JSONObject) jsonResponse);
} else if (jsonResponse instanceof JSONArray) {
onFailure(statusCode, headers, e, (JSONArray) jsonResponse);
} else if (jsonResponse instanceof String) {
onFailure(statusCode, headers, e, (String) jsonResponse);
} else {
onFailure(new JSONException("Unexpected type " + jsonResponse.getClass().getName()), (JSONObject) null);
}
}
}); } catch (final JSONException ex) {
postRunnable(new Runnable() {
@Override
public void run() {
onFailure(ex, (JSONObject) null);
}
}); }
}
}).start();
} else {
Log.v(LOG_TAG, "response body is null, calling onFailure(Throwable, JSONObject)");
onFailure(e, (JSONObject) null);
}
} protected Object parseResponse(String responseBody) throws JSONException {
if (null == responseBody)
return null;
Object result = null;
//trim the string to prevent start with blank, and test if the string is valid JSON, because the parser don't do this :(. If Json is not valid this will return null
String jsonString = responseBody.trim();
if (jsonString.startsWith("{") || jsonString.startsWith("[")) {
result = new JSONTokener(jsonString).nextValue();
}
if (result == null) {
result = jsonString;
}
return result;
}
}
loopj\android\http\MySSLSocketFactory.java
package com.loopj.android.http; import org.apache.http.conn.ssl.SSLSocketFactory; import java.io.IOException;
import java.net.Socket;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException; import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager; /**
* This file is introduced to fix HTTPS Post bug on API < ICS
* see http://code.google.com/p/android/issues/detail?id=13117#c14
*/
public class MySSLSocketFactory extends SSLSocketFactory {
SSLContext sslContext = SSLContext.getInstance("TLS"); public MySSLSocketFactory(KeyStore truststore)
throws NoSuchAlgorithmException, KeyManagementException,
KeyStoreException, UnrecoverableKeyException {
super(truststore); TrustManager tm = new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
} @Override
public void checkClientTrusted(
java.security.cert.X509Certificate[] chain, String authType)
throws java.security.cert.CertificateException {
} @Override
public void checkServerTrusted(
java.security.cert.X509Certificate[] chain, String authType)
throws java.security.cert.CertificateException {
}
};
sslContext.init(null, new TrustManager[]{tm}, null);
} @Override
public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException {
return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
} @Override
public Socket createSocket() throws IOException {
return sslContext.getSocketFactory().createSocket();
} public static KeyStore getKeystore() {
KeyStore trustStore = null;
try {
trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
trustStore.load(null, null);
} catch (Throwable t) {
t.printStackTrace();
}
return trustStore;
} public static SSLSocketFactory getFixedSocketFactory() {
SSLSocketFactory socketFactory;
try {
socketFactory = new MySSLSocketFactory(getKeystore());
socketFactory.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
} catch (Throwable t) {
t.printStackTrace();
socketFactory = SSLSocketFactory.getSocketFactory();
}
return socketFactory;
} }
loopj\android\http\PersistentCookieStore.java
/*
Android Asynchronous Http Client
Copyright (c) 2011 James Smith <james@loopj.com>
http://loopj.com Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/ package com.loopj.android.http; import android.content.Context;
import android.content.SharedPreferences;
import android.text.TextUtils; import org.apache.http.client.CookieStore;
import org.apache.http.cookie.Cookie; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap; /**
* A persistent cookie store which implements the Apache HttpClient
* {@link CookieStore} interface. Cookies are stored and will persist on the
* user's device between application sessions since they are serialized and
* stored in {@link SharedPreferences}.
* <p> </p>
* Instances of this class are designed to be used with
* {@link AsyncHttpClient#setCookieStore}, but can also be used with a
* regular old apache HttpClient/HttpContext if you prefer.
*/
public class PersistentCookieStore implements CookieStore {
private static final String COOKIE_PREFS = "CookiePrefsFile";
private static final String COOKIE_NAME_STORE = "names";
private static final String COOKIE_NAME_PREFIX = "cookie_"; private final ConcurrentHashMap<String, Cookie> cookies;
private final SharedPreferences cookiePrefs; /**
* Construct a persistent cookie store.
*
* @param context Context to attach cookie store to
*/
public PersistentCookieStore(Context context) {
cookiePrefs = context.getSharedPreferences(COOKIE_PREFS, 0);
cookies = new ConcurrentHashMap<String, Cookie>(); // Load any previously stored cookies into the store
String storedCookieNames = cookiePrefs.getString(COOKIE_NAME_STORE, null);
if (storedCookieNames != null) {
String[] cookieNames = TextUtils.split(storedCookieNames, ",");
for (String name : cookieNames) {
String encodedCookie = cookiePrefs.getString(COOKIE_NAME_PREFIX + name, null);
if (encodedCookie != null) {
Cookie decodedCookie = decodeCookie(encodedCookie);
if (decodedCookie != null) {
cookies.put(name, decodedCookie);
}
}
} // Clear out expired cookies
clearExpired(new Date());
}
} @Override
public void addCookie(Cookie cookie) {
String name = cookie.getName() + cookie.getDomain(); // Save cookie into local store, or remove if expired
if (!cookie.isExpired(new Date())) {
cookies.put(name, cookie);
} else {
cookies.remove(name);
} // Save cookie into persistent store
SharedPreferences.Editor prefsWriter = cookiePrefs.edit();
prefsWriter.putString(COOKIE_NAME_STORE, TextUtils.join(",", cookies.keySet()));
prefsWriter.putString(COOKIE_NAME_PREFIX + name, encodeCookie(new SerializableCookie(cookie)));
prefsWriter.commit();
} @Override
public void clear() {
// Clear cookies from persistent store
SharedPreferences.Editor prefsWriter = cookiePrefs.edit();
for (String name : cookies.keySet()) {
prefsWriter.remove(COOKIE_NAME_PREFIX + name);
}
prefsWriter.remove(COOKIE_NAME_STORE);
prefsWriter.commit(); // Clear cookies from local store
cookies.clear();
} @Override
public boolean clearExpired(Date date) {
boolean clearedAny = false;
SharedPreferences.Editor prefsWriter = cookiePrefs.edit(); for (ConcurrentHashMap.Entry<String, Cookie> entry : cookies.entrySet()) {
String name = entry.getKey();
Cookie cookie = entry.getValue();
if (cookie.isExpired(date)) {
// Clear cookies from local store
cookies.remove(name); // Clear cookies from persistent store
prefsWriter.remove(COOKIE_NAME_PREFIX + name); // We've cleared at least one
clearedAny = true;
}
} // Update names in persistent store
if (clearedAny) {
prefsWriter.putString(COOKIE_NAME_STORE, TextUtils.join(",", cookies.keySet()));
}
prefsWriter.commit(); return clearedAny;
} @Override
public List<Cookie> getCookies() {
return new ArrayList<Cookie>(cookies.values());
} //
// Cookie serialization/deserialization
// protected String encodeCookie(SerializableCookie cookie) {
ByteArrayOutputStream os = new ByteArrayOutputStream();
try {
ObjectOutputStream outputStream = new ObjectOutputStream(os);
outputStream.writeObject(cookie);
} catch (Exception e) {
return null;
} return byteArrayToHexString(os.toByteArray());
} protected Cookie decodeCookie(String cookieStr) {
byte[] bytes = hexStringToByteArray(cookieStr);
ByteArrayInputStream is = new ByteArrayInputStream(bytes);
Cookie cookie = null;
try {
ObjectInputStream ois = new ObjectInputStream(is);
cookie = ((SerializableCookie) ois.readObject()).getCookie();
} catch (Exception e) {
e.printStackTrace();
} return cookie;
} // Using some super basic byte array <-> hex conversions so we don't have
// to rely on any large Base64 libraries. Can be overridden if you like!
protected String byteArrayToHexString(byte[] b) {
StringBuilder sb = new StringBuilder(b.length * 2);
for (byte element : b) {
int v = element & 0xff;
if (v < 16) {
sb.append('0');
}
sb.append(Integer.toHexString(v));
}
return sb.toString().toUpperCase();
} protected byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i + 1), 16));
}
return data;
}
}
\loopj\android\http\RequestHandle.java
package com.loopj.android.http; import java.util.concurrent.Future; /**
* A Handle to an AsyncRequest which can be used to cancel a running request.
*
*/
public class RequestHandle {
private final Future<? > request; public RequestHandle(Future<?> request) {
this.request = request;
} /**
* Attempts to cancel this request. This attempt will fail if the request has
* already completed, has already been cancelled, or could not be cancelled
* for some other reason. If successful, and this request has not started
* when cancel is called, this request should never run. If the request has
* already started, then the mayInterruptIfRunning parameter determines
* whether the thread executing this request should be interrupted in an
* attempt to stop the request.
*
* After this method returns, subsequent calls to isDone() will always
* return true. Subsequent calls to isCancelled() will always return true
* if this method returned true.
*
* @param mayInterruptIfRunning true if the thread executing this request should be interrupted; otherwise, in-progress requests are allowed to complete
* @return false if the request could not be cancelled, typically because it has already completed normally; true otherwise
*/
public boolean cancel(boolean mayInterruptIfRunning) {
if (this.request == null) {
return false;
}
return request.cancel(mayInterruptIfRunning);
} /**
* Returns true if this task completed. Completion may be due to normal termination, an exception, or cancellation -- in all of these cases, this method will return true.
* @return true if this task completed
*/
public boolean isFinished() {
if (this.request == null) {
return true;
}
return request.isDone();
} /**
* Returns true if this task was cancelled before it completed normally.
* @return true if this task was cancelled before it completed
*/
public boolean isCancelled() {
if (this.request == null) {
return false;
}
return request.isCancelled();
}
}
\loopj\android\http\RequestParams.java
/*
Android Asynchronous Http Client
Copyright (c) 2011 James Smith <james@loopj.com>
http://loopj.com Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/ package com.loopj.android.http; import org.apache.http.HttpEntity;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP; import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; /**
* A collection of string request parameters or files to send along with
* requests made from an {@link AsyncHttpClient} instance.
* <p> </p>
* For example:
* <p> </p>
* <pre>
* RequestParams params = new RequestParams();
* params.put("username", "james");
* params.put("password", "123456");
* params.put("email", "my@email.com");
* params.put("profile_picture", new File("pic.jpg")); // Upload a File
* params.put("profile_picture2", someInputStream); // Upload an InputStream
* params.put("profile_picture3", new ByteArrayInputStream(someBytes)); // Upload some bytes
*
* Map<String, String> map = new HashMap<String, String>();
* map.put("first_name", "James");
* map.put("last_name", "Smith");
* params.put("user", map); // url params: "user[first_name]=James&user[last_name]=Smith"
*
* Set<String> set = new HashSet<String>(); // unordered collection
* set.add("music");
* set.add("art");
* params.put("like", set); // url params: "like=music&like=art"
*
* List<String> list = new ArrayList<String>(); // Ordered collection
* list.add("Java");
* list.add("C");
* params.put("languages", list); // url params: "languages[]=Java&languages[]=C"
*
* String[] colors = { "blue", "yellow" }; // Ordered collection
* params.put("colors", colors); // url params: "colors[]=blue&colors[]=yellow"
*
* List<Map<String, String>> listOfMaps = new ArrayList<Map<String, String>>();
* Map<String, String> user1 = new HashMap<String, String>();
* user1.put("age", "30");
* user1.put("gender", "male");
* Map<String, String> user2 = new HashMap<String, String>();
* user2.put("age", "25");
* user2.put("gender", "female");
* listOfMaps.add(user1);
* listOfMaps.add(user2);
* params.put("users", listOfMaps); // url params: "users[][age]=30&users[][gender]=male&users[][age]=25&users[][gender]=female"
*
* AsyncHttpClient client = new AsyncHttpClient();
* client.post("http://myendpoint.com", params, responseHandler);
* </pre>
*/
public class RequestParams { private static final String LOG_TAG = "RequestParams"; protected ConcurrentHashMap<String, String> urlParams;
protected ConcurrentHashMap<String, StreamWrapper> streamParams;
protected ConcurrentHashMap<String, FileWrapper> fileParams;
protected ConcurrentHashMap<String, Object> urlParamsWithObjects; /**
* Constructs a new empty <code>RequestParams</code> instance.
*/
public RequestParams() {
init();
} /**
* Constructs a new RequestParams instance containing the key/value
* string params from the specified map.
*
* @param source the source key/value string map to add.
*/
public RequestParams(Map<String, String> source) {
init(); for (Map.Entry<String, String> entry : source.entrySet()) {
put(entry.getKey(), entry.getValue());
}
} /**
* Constructs a new RequestParams instance and populate it with a single
* initial key/value string param.
*
* @param key the key name for the intial param.
* @param value the value string for the initial param.
*/
public RequestParams(String key, String value) {
init(); put(key, value);
} /**
* Constructs a new RequestParams instance and populate it with multiple
* initial key/value string param.
*
* @param keysAndValues a sequence of keys and values. Objects are
* automatically converted to Strings (including the value {@code null}).
* @throws IllegalArgumentException if the number of arguments isn't even.
*/
public RequestParams(Object... keysAndValues) {
init();
int len = keysAndValues.length;
if (len % 2 != 0)
throw new IllegalArgumentException("Supplied arguments must be even");
for (int i = 0; i < len; i += 2) {
String key = String.valueOf(keysAndValues[i]);
String val = String.valueOf(keysAndValues[i + 1]);
put(key, val);
}
} /**
* Adds a key/value string pair to the request.
*
* @param key the key name for the new param.
* @param value the value string for the new param.
*/
public void put(String key, String value) {
if (key != null && value != null) {
urlParams.put(key, value);
}
} /**
* Adds a file to the request.
*
* @param key the key name for the new param.
* @param file the file to add.
* @throws java.io.FileNotFoundException throws if wrong File argument was passed
*/
public void put(String key, File file) throws FileNotFoundException {
put(key, file, null);
} /**
* Adds a file to the request.
*
* @param key the key name for the new param.
* @param file the file to add.
* @param contentType the content type of the file, eg. application/json
* @throws java.io.FileNotFoundException throws if wrong File argument was passed
*/
public void put(String key, File file, String contentType) throws FileNotFoundException {
if (key != null && file != null) {
fileParams.put(key, new FileWrapper(file, contentType));
}
} /**
* Adds an input stream to the request.
*
* @param key the key name for the new param.
* @param stream the input stream to add.
*/
public void put(String key, InputStream stream) {
put(key, stream, null);
} /**
* Adds an input stream to the request.
*
* @param key the key name for the new param.
* @param stream the input stream to add.
* @param name the name of the stream.
*/
public void put(String key, InputStream stream, String name) {
put(key, stream, name, null);
} /**
* Adds an input stream to the request.
*
* @param key the key name for the new param.
* @param stream the input stream to add.
* @param name the name of the stream.
* @param contentType the content type of the file, eg. application/json
*/
public void put(String key, InputStream stream, String name, String contentType) {
if (key != null && stream != null) {
streamParams.put(key, new StreamWrapper(stream, name, contentType));
}
} /**
* Adds param with non-string value (e.g. Map, List, Set).
* @param key the key name for the new param.
* @param value the non-string value object for the new param.
*/
public void put(String key, Object value) {
if (key != null && value != null) {
urlParamsWithObjects.put(key, value);
}
} /**
* Adds string value to param which can have more than one value.
* @param key the key name for the param, either existing or new.
* @param value the value string for the new param.
*/
public void add(String key, String value) {
if (key != null && value != null) {
Object params = urlParamsWithObjects.get(key);
if (params == null) {
// Backward compatible, which will result in "k=v1&k=v2&k=v3"
params = new HashSet<String>();
this.put(key, params);
}
if (params instanceof List) {
((List<Object>) params).add(value);
} else if (params instanceof Set) {
((Set<Object>) params).add(value);
}
}
} /**
* Removes a parameter from the request.
*
* @param key the key name for the parameter to remove.
*/
public void remove(String key) {
urlParams.remove(key);
streamParams.remove(key);
fileParams.remove(key);
urlParamsWithObjects.remove(key);
} @Override
public String toString() {
StringBuilder result = new StringBuilder();
for (ConcurrentHashMap.Entry<String, String> entry : urlParams.entrySet()) {
if (result.length() > 0)
result.append("&"); result.append(entry.getKey());
result.append("=");
result.append(entry.getValue());
} for (ConcurrentHashMap.Entry<String, StreamWrapper> entry : streamParams.entrySet()) {
if (result.length() > 0)
result.append("&"); result.append(entry.getKey());
result.append("=");
result.append("STREAM");
} for (ConcurrentHashMap.Entry<String, FileWrapper> entry : fileParams.entrySet()) {
if (result.length() > 0)
result.append("&"); result.append(entry.getKey());
result.append("=");
result.append("FILE");
} List<BasicNameValuePair> params = getParamsList(null, urlParamsWithObjects);
for (BasicNameValuePair kv : params) {
if (result.length() > 0)
result.append("&"); result.append(kv.getName());
result.append("=");
result.append(kv.getValue());
} return result.toString();
} /**
* Returns an HttpEntity containing all request parameters
*
* @param progressHandler HttpResponseHandler for reporting progress on entity submit
* @return HttpEntity resulting HttpEntity to be included along with {@link org.apache.http.client.methods.HttpEntityEnclosingRequestBase}
* @throws IOException if one of the streams cannot be read
*/
public HttpEntity getEntity(AsyncHttpResponseHandler progressHandler) throws IOException {
if (streamParams.isEmpty() && fileParams.isEmpty()) {
return createFormEntity();
} else {
return createMultipartEntity(progressHandler);
}
} private HttpEntity createFormEntity() {
try {
return new UrlEncodedFormEntity(getParamsList(), HTTP.UTF_8);
} catch (UnsupportedEncodingException e) {
return null; // Actually cannot happen when using utf-8
}
} private HttpEntity createMultipartEntity(AsyncHttpResponseHandler progressHandler) throws IOException {
SimpleMultipartEntity entity = new SimpleMultipartEntity(progressHandler); // Add string params
for (ConcurrentHashMap.Entry<String, String> entry : urlParams.entrySet()) {
entity.addPart(entry.getKey(), entry.getValue());
} // Add non-string params
List<BasicNameValuePair> params = getParamsList(null, urlParamsWithObjects);
for (BasicNameValuePair kv : params) {
entity.addPart(kv.getName(), kv.getValue());
} // Add stream params
for (ConcurrentHashMap.Entry<String, StreamWrapper> entry : streamParams.entrySet()) {
StreamWrapper stream = entry.getValue();
if (stream.inputStream != null) {
entity.addPart(entry.getKey(), stream.name, stream.inputStream,
stream.contentType);
}
} // Add file params
for (ConcurrentHashMap.Entry<String, FileWrapper> entry : fileParams.entrySet()) {
FileWrapper fileWrapper = entry.getValue();
entity.addPart(entry.getKey(), fileWrapper.file, fileWrapper.contentType);
} return entity;
} private void init() {
urlParams = new ConcurrentHashMap<String, String>();
streamParams = new ConcurrentHashMap<String, StreamWrapper>();
fileParams = new ConcurrentHashMap<String, FileWrapper>();
urlParamsWithObjects = new ConcurrentHashMap<String, Object>();
} protected List<BasicNameValuePair> getParamsList() {
List<BasicNameValuePair> lparams = new LinkedList<BasicNameValuePair>(); for (ConcurrentHashMap.Entry<String, String> entry : urlParams.entrySet()) {
lparams.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
} lparams.addAll(getParamsList(null, urlParamsWithObjects)); return lparams;
} private List<BasicNameValuePair> getParamsList(String key, Object value) {
List<BasicNameValuePair> params = new LinkedList<BasicNameValuePair>();
if (value instanceof Map) {
Map<String, Object> map = (Map<String, Object>) value;
List<String> list = new ArrayList<String>(map.keySet());
// Ensure consistent ordering in query string
Collections.sort(list);
for (String nestedKey : list) {
Object nestedValue = map.get(nestedKey);
if (nestedValue != null) {
params.addAll(getParamsList(key == null ? nestedKey : String.format("%s[%s]", key, nestedKey),
nestedValue));
}
}
} else if (value instanceof List) {
List<Object> list = (List<Object>) value;
for (Object nestedValue : list) {
params.addAll(getParamsList(String.format("%s[]", key), nestedValue));
}
} else if (value instanceof Object[]) {
Object[] array = (Object[]) value;
for (Object nestedValue : array) {
params.addAll(getParamsList(String.format("%s[]", key), nestedValue));
}
} else if (value instanceof Set) {
Set<Object> set = (Set<Object>) value;
for (Object nestedValue : set) {
params.addAll(getParamsList(key, nestedValue));
}
} else if (value instanceof String) {
params.add(new BasicNameValuePair(key, (String) value));
}
return params;
} protected String getParamString() {
return URLEncodedUtils.format(getParamsList(), HTTP.UTF_8);
} private static class FileWrapper {
public File file;
public String contentType; public FileWrapper(File file, String contentType) {
this.file = file;
this.contentType = contentType;
}
} private static class StreamWrapper {
public InputStream inputStream;
public String name;
public String contentType; public StreamWrapper(InputStream inputStream, String name, String contentType) {
this.inputStream = inputStream;
this.name = name;
this.contentType = contentType;
}
}
}
\loopj\android\http\RetryHandler.java
/*
Android Asynchronous Http Client
Copyright (c) 2011 James Smith <james@loopj.com>
http://loopj.com Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/ /*
Some of the retry logic in this class is heavily borrowed from the
fantastic droid-fu project: https://github.com/donnfelker/droid-fu
*/ package com.loopj.android.http; import android.os.SystemClock; import org.apache.http.NoHttpResponseException;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.protocol.ExecutionContext;
import org.apache.http.protocol.HttpContext; import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.HashSet; import javax.net.ssl.SSLException; class RetryHandler implements HttpRequestRetryHandler {
private static HashSet<Class<?>> exceptionWhitelist = new HashSet<Class<? >>();
private static HashSet<Class<?>> exceptionBlacklist = new HashSet<Class<? >>(); static {
// Retry if the server dropped connection on us
exceptionWhitelist.add(NoHttpResponseException.class);
// retry-this, since it may happens as part of a Wi-Fi to 3G failover
exceptionWhitelist.add(UnknownHostException.class);
// retry-this, since it may happens as part of a Wi-Fi to 3G failover
exceptionWhitelist.add(SocketException.class); // never retry timeouts
exceptionBlacklist.add(InterruptedIOException.class);
// never retry SSL handshake failures
exceptionBlacklist.add(SSLException.class);
} private final int maxRetries;
private final int retrySleepTimeMS; public RetryHandler(int maxRetries, int retrySleepTimeMS) {
this.maxRetries = maxRetries;
this.retrySleepTimeMS = retrySleepTimeMS;
} @Override
public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {
boolean retry = true; Boolean b = (Boolean) context.getAttribute(ExecutionContext.HTTP_REQ_SENT);
boolean sent = (b != null && b); if (executionCount > maxRetries) {
// Do not retry if over max retry count
retry = false;
} else if (isInList(exceptionBlacklist, exception)) {
// immediately cancel retry if the error is blacklisted
retry = false;
} else if (isInList(exceptionWhitelist, exception)) {
// immediately retry if error is whitelisted
retry = true;
} else if (!sent) {
// for most other errors, retry only if request hasn't been fully sent yet
retry = true;
} if (retry) {
// resend all idempotent requests
HttpUriRequest currentReq = (HttpUriRequest) context.getAttribute(ExecutionContext.HTTP_REQUEST);
if (currentReq == null) {
return false;
}
String requestType = currentReq.getMethod();
retry = !requestType.equals("POST");
} if (retry) {
SystemClock.sleep(retrySleepTimeMS);
} else {
exception.printStackTrace();
} return retry;
} protected boolean isInList(HashSet<Class<?>> list, Throwable error) {
for (Class<? > aList : list) {
if (aList.isInstance(error)) {
return true;
}
}
return false;
}
}
\loopj\android\http\SerializableCookie.java
/*
Android Asynchronous Http Client
Copyright (c) 2011 James Smith <james@loopj.com>
http://loopj.com Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/ package com.loopj.android.http; import org.apache.http.cookie.Cookie;
import org.apache.http.impl.cookie.BasicClientCookie; import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Date; /**
* A wrapper class around {@link Cookie} and/or {@link BasicClientCookie}
* designed for use in {@link PersistentCookieStore}.
*/
public class SerializableCookie implements Serializable {
private static final long serialVersionUID = 6374381828722046732L; private transient final Cookie cookie;
private transient BasicClientCookie clientCookie; public SerializableCookie(Cookie cookie) {
this.cookie = cookie;
} public Cookie getCookie() {
Cookie bestCookie = cookie;
if (clientCookie != null) {
bestCookie = clientCookie;
}
return bestCookie;
} private void writeObject(ObjectOutputStream out) throws IOException {
out.writeObject(cookie.getName());
out.writeObject(cookie.getValue());
out.writeObject(cookie.getComment());
out.writeObject(cookie.getDomain());
out.writeObject(cookie.getExpiryDate());
out.writeObject(cookie.getPath());
out.writeInt(cookie.getVersion());
out.writeBoolean(cookie.isSecure());
} private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
String name = (String) in.readObject();
String value = (String) in.readObject();
clientCookie = new BasicClientCookie(name, value);
clientCookie.setComment((String) in.readObject());
clientCookie.setDomain((String) in.readObject());
clientCookie.setExpiryDate((Date) in.readObject());
clientCookie.setPath((String) in.readObject());
clientCookie.setVersion(in.readInt());
clientCookie.setSecure(in.readBoolean());
}
}
\loopj\android\http\SimpleMultipartEntity.java
/*
Android Asynchronous Http Client
Copyright (c) 2011 James Smith <james@loopj.com>
http://loopj.com Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/ /*
This code is taken from Rafael Sanches' blog.
http://blog.rafaelsanches.com/2011/01/29/upload-using-multipart-post-using-httpclient-in-android/
*/ package com.loopj.android.http; import android.util.Log; import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.message.BasicHeader; import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Random; /**
* Simplified multipart entity mainly used for sending one or more files.
*/
class SimpleMultipartEntity implements HttpEntity { private static final String LOG_TAG = "SimpleMultipartEntity"; private static final String APPLICATION_OCTET_STREAM = "application/octet-stream";
private static final byte[] CR_LF = ("\r\n").getBytes();
private static final byte[] TRANSFER_ENCODING_BINARY = "Content-Transfer-Encoding: binary\r\n"
.getBytes(); private final static char[] MULTIPART_CHARS = "-_1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray(); private String boundary;
private byte[] boundaryLine;
private byte[] boundaryEnd; private List<FilePart> fileParts = new ArrayList<FilePart>(); // The buffer we use for building the message excluding files and the last
// boundary
private ByteArrayOutputStream out = new ByteArrayOutputStream(); private AsyncHttpResponseHandler progressHandler; private int bytesWritten; private int totalSize; public SimpleMultipartEntity(AsyncHttpResponseHandler progressHandler) {
final StringBuilder buf = new StringBuilder();
final Random rand = new Random();
for (int i = 0; i < 30; i++) {
buf.append(MULTIPART_CHARS[rand.nextInt(MULTIPART_CHARS.length)]);
} boundary = buf.toString();
boundaryLine = ("--" + boundary + "\r\n").getBytes();
boundaryEnd = ("--" + boundary + "--\r\n").getBytes(); this.progressHandler = progressHandler;
} public void addPart(final String key, final String value, final String contentType) {
try {
out.write(boundaryLine);
out.write(createContentDisposition(key));
out.write(createContentType(contentType));
out.write(CR_LF);
out.write(value.getBytes());
out.write(CR_LF);
} catch (final IOException e) {
// Can't happen on ByteArrayOutputStream
Log.e(LOG_TAG, "addPart ByteArrayOutputStream exception", e);
}
} public void addPart(final String key, final String value) {
addPart(key, value, "text/plain; charset=UTF-8");
} public void addPart(String key, File file) {
addPart(key, file, null);
} public void addPart(final String key, File file, String type) {
if (type == null) {
type = APPLICATION_OCTET_STREAM;
}
fileParts.add(new FilePart(key, file, type));
} public void addPart(String key, String streamName, InputStream inputStream, String type)
throws IOException {
if (type == null) {
type = APPLICATION_OCTET_STREAM;
}
out.write(boundaryLine); // Headers
out.write(createContentDisposition(key, streamName));
out.write(createContentType(type));
out.write(TRANSFER_ENCODING_BINARY);
out.write(CR_LF); // Stream (file)
final byte[] tmp = new byte[4096];
int l;
while ((l = inputStream.read(tmp)) != -1) {
out.write(tmp, 0, l);
} out.write(CR_LF);
out.flush();
try {
inputStream.close();
} catch (final IOException e) {
// Not important, just log it
Log.w(LOG_TAG, "Cannot close input stream", e);
}
} private byte[] createContentType(String type) {
String result = "Content-Type: " + type + "\r\n";
return result.getBytes();
} private byte[] createContentDisposition(final String key) {
return ("Content-Disposition: form-data; name=\"" + key + "\"\r\n")
.getBytes();
} private byte[] createContentDisposition(final String key, final String fileName) {
return ("Content-Disposition: form-data; name=\"" + key + "\"; filename=\"" + fileName + "\"\r\n")
.getBytes();
} private void updateProgress(int count) {
bytesWritten += count;
progressHandler.sendProgressMessage(bytesWritten, totalSize);
} private class FilePart {
public File file;
public byte[] header; public FilePart(String key, File file, String type) {
header = createHeader(key, file.getName(), type);
this.file = file;
} private byte[] createHeader(String key, String filename, String type) {
ByteArrayOutputStream headerStream = new ByteArrayOutputStream();
try {
headerStream.write(boundaryLine); // Headers
headerStream.write(createContentDisposition(key, filename));
headerStream.write(createContentType(type));
headerStream.write(TRANSFER_ENCODING_BINARY);
headerStream.write(CR_LF);
} catch (IOException e) {
// Can't happen on ByteArrayOutputStream
Log.e(LOG_TAG, "createHeader ByteArrayOutputStream exception", e);
}
return headerStream.toByteArray();
} public long getTotalLength() {
long streamLength = file.length();
return header.length + streamLength;
} public void writeTo(OutputStream out) throws IOException {
out.write(header);
updateProgress(header.length); FileInputStream inputStream = new FileInputStream(file);
final byte[] tmp = new byte[4096];
int l;
while ((l = inputStream.read(tmp)) != -1) {
out.write(tmp, 0, l);
updateProgress(l);
}
out.write(CR_LF);
updateProgress(CR_LF.length);
out.flush();
try {
inputStream.close();
} catch (final IOException e) {
// Not important, just log it
Log.w(LOG_TAG, "Cannot close input stream", e);
}
}
} // The following methods are from the HttpEntity interface @Override
public long getContentLength() {
long contentLen = out.size();
for (FilePart filePart : fileParts) {
long len = filePart.getTotalLength();
if (len < 0) {
return -1; // Should normally not happen
}
contentLen += len;
}
contentLen += boundaryEnd.length;
return contentLen;
} @Override
public Header getContentType() {
return new BasicHeader("Content-Type", "multipart/form-data; boundary=" + boundary);
} @Override
public boolean isChunked() {
return false;
} @Override
public boolean isRepeatable() {
return false;
} @Override
public boolean isStreaming() {
return false;
} @Override
public void writeTo(final OutputStream outstream) throws IOException {
bytesWritten = 0;
totalSize = (int) getContentLength();
out.writeTo(outstream);
updateProgress(out.size()); for (FilePart filePart : fileParts) {
filePart.writeTo(outstream);
}
outstream.write(boundaryEnd);
updateProgress(boundaryEnd.length);
} @Override
public Header getContentEncoding() {
return null;
} @Override
public void consumeContent() throws IOException, UnsupportedOperationException {
if (isStreaming()) {
throw new UnsupportedOperationException(
"Streaming entity does not implement #consumeContent()");
}
} @Override
public InputStream getContent() throws IOException, UnsupportedOperationException {
throw new UnsupportedOperationException(
"getContent() is not supported. Use writeTo() instead.");
}
}
\loopj\android\http\SyncHttpClient.java
package com.loopj.android.http; import android.content.Context;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.protocol.HttpContext; public class SyncHttpClient extends AsyncHttpClient { /**
* Creates a new SyncHttpClient with default constructor arguments values
*/
public SyncHttpClient() {
super(false, 80, 443);
} /**
* Creates a new SyncHttpClient.
*
* @param httpPort non-standard HTTP-only port
*/
public SyncHttpClient(int httpPort) {
super(false, httpPort, 443);
} /**
* Creates a new SyncHttpClient.
*
* @param httpPort non-standard HTTP-only port
* @param httpsPort non-standard HTTPS-only port
*/
public SyncHttpClient(int httpPort, int httpsPort) {
super(false, httpPort, httpsPort);
} /**
* Creates new SyncHttpClient using given params
*
* @param fixNoHttpResponseException Whether to fix or not issue, by ommiting SSL verification
* @param httpPort HTTP port to be used, must be greater than 0
* @param httpsPort HTTPS port to be used, must be greater than 0
*/
public SyncHttpClient(boolean fixNoHttpResponseException, int httpPort, int httpsPort) {
super(fixNoHttpResponseException, httpPort, httpsPort);
} /**
* Creates a new SyncHttpClient.
*
* @param schemeRegistry SchemeRegistry to be used
*/
public SyncHttpClient(SchemeRegistry schemeRegistry) {
super(schemeRegistry);
} @Override
protected RequestHandle sendRequest(DefaultHttpClient client,
HttpContext httpContext, HttpUriRequest uriRequest,
String contentType, AsyncHttpResponseHandler responseHandler,
Context context) {
if (contentType != null) {
uriRequest.addHeader("Content-Type", contentType);
} responseHandler.setUseSynchronousMode(true); /*
* will execute the request directly
*/
new AsyncHttpRequest(client, httpContext, uriRequest, responseHandler).run(); // Return a Request Handle that cannot be used to cancel the request
// because it is already complete by the time this returns
return new RequestHandle(null);
}
}
\loopj\android\http\TextHttpResponseHandler.java
package com.loopj.android.http; import android.util.Log; import org.apache.http.Header; import java.io.UnsupportedEncodingException; /**
* Used to intercept and handle the responses from requests made using
* {@link AsyncHttpClient}. The {@link #onSuccess(String)} method is
* designed to be anonymously overridden with your own response handling code.
* <p/>
* Additionally, you can override the {@link #onFailure(String, Throwable)},
* {@link #onStart()}, and {@link #onFinish()} methods as required.
* <p/>
* For example:
* <p/>
* <pre>
* AsyncHttpClient client = new AsyncHttpClient();
* client.get("http://www.google.com", new TextHttpResponseHandler() {
* @Override
* public void onStart() {
* // Initiated the request
* }
*
* @Override
* public void onSuccess(String responseBody) {
* // Successfully got a response
* }
*
* @Override
* public void onFailure(String responseBody, Throwable e) {
* // Response failed :(
* }
*
* @Override
* public void onFinish() {
* // Completed the request (either success or failure)
* }
* });
* </pre>
*/
public class TextHttpResponseHandler extends AsyncHttpResponseHandler {
private static final String LOG_TAG = "TextHttpResponseHandler"; /**
* Creates a new TextHttpResponseHandler
*/ public TextHttpResponseHandler() {
this(DEFAULT_CHARSET);
} public TextHttpResponseHandler(String encoding) {
super();
setCharset(encoding);
} //
// Callbacks to be overridden, typically anonymously
// /**
* Fired when a request fails to complete, override to handle in your own
* code
*
* @param responseBody the response body, if any
* @param error the underlying cause of the failure
*/
public void onFailure(String responseBody, Throwable error) {
} /**
* Fired when a request fails to complete, override to handle in your own
* code
*
* @param statusCode the status code of the response
* @param headers HTTP response headers
* @param responseBody the response body, if any
* @param error the underlying cause of the failure
*/
public void onFailure(int statusCode, Header[] headers, String responseBody, Throwable error) {
onFailure(responseBody, error);
} /**
* Fired when a request returns successfully, override to handle in your own
* code
*
* @param statusCode the status code of the response
* @param headers HTTP response headers
* @param responseBody the body of the HTTP response from the server
*/
@Override
public void onSuccess(int statusCode, Header[] headers, String responseBody) {
onSuccess( statusCode, responseBody );
} @Override
public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {
try {
onSuccess(statusCode, headers, new String(responseBody, getCharset()));
} catch (UnsupportedEncodingException e) {
Log.v(LOG_TAG, "String encoding failed, calling onFailure(int, Header[], String, Throwable)");
onFailure(0, headers, (String) null, e);
}
} @Override
public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) {
try {
onFailure(statusCode, headers, new String(responseBody, getCharset()), error);
} catch (UnsupportedEncodingException e) {
Log.v(LOG_TAG, "String encoding failed, calling onFailure(int, Header[], String, Throwable)");
onFailure(0, headers, (String) null, e);
}
} }
完整项目下载地址:http://download.csdn.net/detail/iwanghang/9792768
转载请注明出处:http://blog.csdn.net/iwanghang/article/details/65633129
沈阳或周边城市公司有意开发Android,请与我联系
联系方式
微信:iwanghang
QQ:413711276
邮箱:iwanghang@qq.com
认为博文实用,请点赞。请评论,请关注。谢谢!~