Quantcast
Channel: CSDN博客推荐文章
Viewing all 35570 articles
Browse latest View live

如何在Rails Console中使用path和helper方法

$
0
0

我们知道Rails中的helper方法(比如link_to)默认只能在模板(Template)中使用,如果想要在控制台中调用,可以加前缀helper:

helper.link_to
#或者
ApplicationController.helpers.link_to

虽然比较少见,不过如果真的要在Controller或Model中呼叫Helper,则也可以用ApplicationController.helpers前缀调用helper方法.

接下来,如果你实际想写个链接试一下就会报错:

helper.link_to("staff",staff_path(Staff.first))
#报错如下:
NoMethodError: undefined method `staff_path' for main:Object

这是因为staff_path需要加上app前缀调用:

helper.link_to("staff",app.staff_path(Staff.first))
#输出
"<a href=\"/staffs/1\">staff</a>"

你可以添加任意相关属性:

helper.link_to("staff",app.staff_path(Staff.first),target:"_blank")
"<a href=\"/staffs/1\" target=\"_blank\">staff</a>"
作者:mydo 发表于2017/3/24 16:56:32 原文链接
阅读:138 评论:0 查看评论

【PMP】PMBOK 笔记 第7章 项目成本管理

$
0
0

第7章 项目成本管理

项目成本管理包含为使项目在批准的预算内完成而对成本进行规划、估算、预算、融资、筹资、管理和控制的各个过程,从而确保项目在批准的预算内完工。

图 7-1 项目成本管理概述

项目成本管理应考虑干系人对掌握成本情况的要求。

项目成本管理重点关注完成项目活动所需资源的成本,但同时也应考虑项目决策对项目产品、服务或成果的使用成本、维护成本和支持成本的影响。

总结

本章的重点是7.4

公式很多,会涉及到计算题。

成本管理的技术和工具和时间管理很像。

7.1 规划成本管理

规划成本管理是为规划、管理、花费和控制项目成本而制定政策、程序和文档的过程。

本过程的主要作用是,在整个项目中为如何管理项目成本提供指南和方向

图 7-2 规划成本管理:输入、工具与技术和输出

图 7-3 规划成本管理的数据流向图

7.1.1 规划成本管理:输入

7.1.1.1 项目管理计划

见 4.2.3.1 节。

  • 范围基准。项目范围说明书、WBS详细信息
  • 进度基准
  • 其他信息

7.1.1.2 项目章程

见 4.1.3.1 节。

7.1.1.3 事业环境因素

见 2.1.5 节。

7.1.1.4 组织过程资产

见 2.1.4 节。

7.1.2 规划成本管理:工具与技术

7.1.2.1 专家判断

7.1.2.2 分析技术

可能需要选择项目筹资的战略方法,如自筹资金、股权投资、借贷投资等。

可能也需详细说明筹集项目资源的方法,如自制、采购、租用或租赁。

7.1.2.3 会议

7.1.3 规划成本管理:输出

7.1.3.1 成本管理计划

成本管理计划是项目管理计划的组成部分,描述将如何规划、安排和控制项目成本。

  • 计量单位
  • 精确度
  • 准确度
  • 组织程序链接。工作分解结构(见 5.4 节)为成本管理计划提供了框架,以便据此规范地开展成本估算、预算和控制。在项目成本核算中使用的 WBS 组件,称为控制账户(CA)。
  • 控制临界值
  • 绩效测量规则。需要规定用于绩效测量的挣值管理(EVM)规则。
    • 定义 WBS 中用于绩效测量的控制账户
    • 确定拟用的挣值测量技术(如加权里程碑法、固定公式法、完成百分比法等)
    • 规定跟踪方法,以及用于计算项目完工估算(EAC)的挣值管理公式
  • 报告格式
  • 过程描述
  • 其他细节

《挣值管理实践标准》(Practice Standards for Earned Value Management)

7.2 估算成本

估算成本是对完成项目活动所需资金进行近似估算的过程。

本过程的主要作用是,确定完成项目工作所需的成本数额

这里写图片描述

图 7-5 估算成本的数据流向图

成本估算是在某特定时点,根据已知信息所做出的成本预测。

在启动阶段可得出项目的粗略量级估算

7.2.1 估算成本:输入

7.2.1.1 成本管理计划

见 7.1.3.1 节。

7.2.1.2 人力资源管理计划

见 9.1.3.1 节。

7.2.1.3 范围基准

  • 范围说明书。范围说明书(见 5.3.3.1 节)提供了产品描述、验收标准、主要可交付成果、项目边界及项目的假设条件和制约因素。间接成本是无法直接追溯到某个具体项目的成本,只能合理分摊到多个项目中。
  • 工作分解结构。工作分解结构(见 5.4 节)
  • WBS 词典。WBS 词典(见 5.4.3.1 节)

7.2.1.4 项目进度计划

见 6.6.3.2 节。

7.2.1.5 风险登记册

见 11.2.3.1 节。

7.2.1.6 事业环境因素

见 2.1.5 节。

  • 市场条件
  • 发布的商业信息

7.2.1.7 组织过程资产

见 2.1.4 节。

估算成本:工具与技术

7.2.2.1 专家判断

7.2.2.2 类比估算

成本类比估算是指以过去类似项目的参数值

在项目详细信息不足时,例如在项目的早期阶段,就经常使用这种技术来估算成本数值。

类比估算通常成本较低、耗时较少,但准确性也较低

7.2.2.3 参数估算

7.2.2.4 自下而上估算

7.2.2.5 三点估算

  • 最可能成本(cM)
  • 最乐观成本(cO)
  • 最悲观成本(cP)

两个常用公式如下:

  • 三角分布 cE= (cO + cM + cP) / 3
  • 贝塔分布 cE = (cO + 4cM + cP) / 6

7.2.2.6 储备分析

应急储备(有时称为“应急费用”) -> 应急储备是包含在成本基准内的一部分预算,用来应对已经接受的已识别风险

应急储备通常是预算的一部分

应急储备可取成本估算值的某一百分比、某个固定值,或者通过定量分析来确定。

随着项目信息越来越明确,可以动用、减少或取消应急储备。

应急储备是成本基准的一部分,也是项目整体资金需求的一部分。

管理储备用来应对会影响项目的“未知—未知”风险。管理储备不包括在成本基准中,但属于项目总预算和资金需求的一部分。当动用管理储备资助不可预见的工作时,就要把动用的管理储备增加到成本基准中,从而致成本基准变更。

7.2.2.7 质量成本(COQ)

质量成本(见 8.1.2.2 节)

7.2.2.8 项目管理软件

7.2.2.9 卖方投标分析

7.2.2.10 群体决策技术

基于团队的方法(如头脑风暴、德尔菲技术或名义小组技术)

7.2.3 估算成本:输出

7.2.3.1 活动成本估算

活动成本估算是对完成项目工作可能需要的成本的量化估算。

成本估算应该覆盖活动所使用的全部资源

7.2.3.2 估算依据

成本估算所需的支持信息的数量和种类,因应用领域而异

7.2.3.3 项目文件更新

风险登记册

7.3 制定预算

制定预算是汇总所有单个活动或工作包的估算成本,建立一个经批准的成本基准的过程。

本过程的主要作用是,确定成本基准,可据此监督和控制项目绩效。

图 7-6 制定预算:输入、工具与技术和输出

图 7-7 制定预算的数据流向图

7.3.1 制定预算:输入

7.3.1.1 成本管理计划

见 7.1.3.1 节。

7.3.1.2 范围基准

  • 项目范围说明书。组织、协议(见 12.2.3.2 节)
  • 工作分解结构。工作分解结构(见 5.4 节)
  • WBS 词典。在 WBS 词典(见 5.4.3.1 节)

7.3.1.3 活动成本估算

见 7.2.3.1 节。

7.3.1.4 估算依据

见 7.2.3.2 节。

7.3.1.5 项目进度计划

见 6.6.3.2 节。

7.3.1.6 资源日历

见 9.2.3.2 节和 12.2.3.3 节。

7.3.1.7 风险登记册

见 11.2.3.1 节。

7.3.1.8 协议

见 12.2.3.2 节。

7.3.1.9 组织过程资产

见 2.1.4 节。

7.3.2 制定预算:工具与技术

7.3.2.1 成本汇总

成本估算汇总到 WBS 中的工作包,再由工作包汇总至 WBS 更高层次(如控制账户),最终得出整个项目的总成本。

7.3.2.2 储备分析

通过预算储备分析,可以计算出项目的应急储备与管理储备。

见 7.2.2.6 节。

7.3.2.3 专家判断

7.3.2.4 历史关系

7.3.2.5 资金限制平衡

7.3.3 制定预算:输出

7.3.3.1 成本基准

成本基准是经过批准的、按时间段分配的项目预算,不包括任何管理储备,只有通过正式的变更控制程序才能变更

在成本基准之上增加管理储备(见 7.2.2.6 节),得到项目预算。当出现有必要动用管理储备的变更时,则应该在获得变更控制过程的批准之后,把适量的管理储备移入成本基准中。

图 7-8 项目预算的组成

图 7-9 成本基准、支出与资金需求

7.3.3.2 项目资金需求

7.3.3.3 项目文件更新

7.4 控制成本

控制成本是监督项目状态,以更新项目成本,管理成本基准变更的过程。

本过程的主要作用是,发现实际与计划的差异,以便采取纠正措施,降低风险。

图 7-10 控制成本:输入、工具与技术和输出

图 7-11 控制成本的数据流向图

只有经过实施整体变更控制过程(见 4.5节)的批准,才可以增加预算。

项目成本控制包括:

  • 对造成成本基准变更的因素施加影响
  • 确保所有变更请求都得到及时处理
  • 当变更实际发生时,管理这些变更
  • 确保成本支出不超过批准的资金限额,既不超出按时段、按 WBS 组件、按活动分配的限额,也不超出项目总限额
  • 监督成本绩效,找出并分析与成本基准间的偏差
  • 对照资金支出,监督工作绩效
  • 防止在成本或资源使用报告中出现未经批准的变更
  • 向有关干系人报告所有经批准的变更及其相关成本
  • 设法把预期的成本超支控制在可接受的范围内

7.4.1 控制成本:输入

7.4.1.1 项目管理计划

见 4.2.3.1 节。

  • 成本基准
  • 成本管理计划。成本管理计划规定了如何管理与控制项目成本(见 7.1.3.1 节)

7.4.1.2 项目资金需求

见 7.3.3.2 节。

7.4.1.3 工作绩效数据

见 4.3.3.2 节。

7.4.1.4 组织过程资产

见 2.1.4 节。

7.4.2 控制成本:工具与技术

7.4.2.1 挣值管理

挣值管理(EVM)是把范围、进度和资源绩效综合起来考虑,以评估项目绩效和进展的方法。

它是一种常用的项目绩效测量方法。

它针对每个工作包和控制账户,计算并监测以下三个关键指标:

  • 计划价值。计划价值(PV)是为计划工作分配的经批准的预算。PV 的总和有时被称为绩效测量基准(PMB),项目的总计划价值又被称为完工预算(BAC)。
  • 挣值。挣值(EV)是对已完成工作的测量值,用分配给该工作的预算来表示。
  • 实际成本。 实际成本(AC)是在给定时段内,执行某工作而实际发生的成本

监测实际绩效与基准之间的偏差:

  • 进度偏差。进度偏差(SV)是测量进度绩效的一种指标,表示为挣值与计划价值之差。SV = EV – PV
  • 成本偏差。成本偏差(CV)是在某个给定时点的预算亏空或盈余量,表示为挣值与实际成本之差。公式:CV = EV – AC。
  • 进度绩效指数。进度绩效指数(SPI)是测量进度效率的一种指标,表示为挣值与计划价值之比。公式:SPI=EV/PV。
  • 成本绩效指数。成本绩效指数(CPI)是测量预算资源的成本效率的一种指标,表示为挣值与实际成本之比。公式:CPI=EV/AC。

图 7-12 挣值、计划价值和实际成本

7.4.2.2 预测

最常用的三种方法:

  • 假设将按预算单价完成 ETC 工作。这种方法承认以实际成本表示的累计实际项目绩效(不论好坏),并预计未来的全部 ETC 工作都将按预算单价完成。公式:EAC = AC +(BAC – EV)。
  • 假设以当前 CPI 完成 ETC 工作。公式:EAC = BAC/CPI。
  • 假设 SPI 与 CPI 将同时影响 ETC 工作。公式: EAC =AC +[(BAC – EV)/(CPI x SPI)]。

7.4.2.3 完工尚需绩效指数(TCPI)

TCPI 是指为了实现具体的管理目标(如 BAC 或 EAC),剩余工作的实施必须达到的成本绩效指标。

基于 BAC 的 TCPI 公式:TCPI =(BAC – EV)/(BAC – AC)。

基于 EAC 的 TCPI 公式:TCPI=(BAC – EV)/(EAC – AC)。

图 7-13 完工尚需绩效指数 (TCPI)

7.4.2.4 绩效审查

  • 偏差分析。在 EVM 中,偏差分析用以解释成本偏差(CV = EV – AC)、进度偏差(SV = EV – PV)和完工偏差(VAC = BAC – EAC)的原因、影响和纠正措施。
  • 趋势分析
  • 挣值绩效

表 7-1 挣值计算汇总表

表 7-1 挣值计算汇总表

7.4.2.5 项目管理软件

7.4.2.6 储备分析

用储备分析来监督项目中应急储备和管理储备的使用情况,从而判断是否还需要这些储备,或者是否需要增加额外的储备。

7.4.3 控制成本:输出

7.4.3.1 工作绩效信息

WBS 各组件(尤其是工作包和控制账户)的 CV,SV,CPI,SPI,TCPI 和 VAC 值,都需要记录下来,并传达给干系人

7.4.3.2 成本预测

7.4.3.3 变更请求

7.4.3.4 项目管理计划更新

  • 成本基准
  • 成本管理计划

7.4.3.5 项目文件更新

7.4.3.6 组织过程资产更新

作者:diandianxiyu 发表于2017/3/24 16:59:21 原文链接
阅读:137 评论:0 查看评论

Android选择/拍照 剪裁 base64/16进制/byte上传图片+PHP接收图片

$
0
0
转载请注明出处:http://blog.csdn.net/iwanghang/article/details/65633129
觉得博文有用,请点赞,请评论,请关注,谢谢!~


老规矩,先上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:

\uploadimg\MainActivity.java
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



觉得博文有用,请点赞,请评论,请关注,谢谢!~

作者:iwanghang 发表于2017/3/24 17:02:34 原文链接
阅读:408 评论:1 查看评论

网易编程题六,最大的奇约数(递推计算)

$
0
0

最大的奇约数(递推计算)

小易是一个数论爱好者,并且对于一个数的奇数约数十分感兴趣。一天小易遇到这样一个问题: 定义函数f(x)为x最大的奇数约数,x为正整数。 例如:f(44) = 11.
现在给出一个N,需要求出 f(1) + f(2) + f(3).......f(N)
例如: N = 7 
f(1) + f(2) + f(3) + f(4) + f(5) + f(6) + f(7) = 1 + 1 + 3 + 1 + 5 + 3 + 7 = 21
小易计算这个问题遇到了困难,需要你来设计一个算法帮助他。 

输入描述:
输入一个整数N (1 ≤ N ≤ 1000000000)
输出描述:
输出一个整数,即为f(1) + f(2) + f(3).......f(N)
输入例子:
7
输出例子:
21
递推式在代码中一目了然

代码:

#include <iostream>
using namespace std;

long long f(int n)
{
	if (n == 1)return 1;
	long long a = (n + 1) / 2;
	return f(n / 2) + a*a;
}

int main()
{
	int n;
	cin >> n;
	cout << f(n);
	return 0;
}

作者:nameofcsdn 发表于2017/3/24 17:05:29 原文链接
阅读:109 评论:0 查看评论

网易编程题七,买苹果(计算)

$
0
0

买苹果(计算)

小易去附近的商店买苹果,奸诈的商贩使用了捆绑交易,只提供6个每袋和8个每袋的包装(包装不可拆分)。 可是小易现在只想购买恰好n个苹果,小易想购买尽量少的袋数方便携带。如果不能购买恰好n个苹果,小易将不会购买。 

输入描述:
输入一个整数n,表示小易想购买n(1 ≤ n ≤ 100)个苹果
输出描述:
输出一个整数表示最少需要购买的袋数,如果不能买恰好n个苹果则输出-1
输入例子:
20
输出例子:
3

代码:

#include <iostream>
using namespace std;

long long f(int n)
{
	if (n % 2)return -1;
	n /= 2;
	if (n % 4 == 0)return n / 4;
	if (n % 4 == 3 && n >= 3 || n % 4 == 2 && n >= 6 || n % 4 == 1 && n >= 9)return n / 4 + 1;
	return -1;
}

int main()
{
	int n;
	cin >> n;
	cout << f(n);
	return 0;
}

作者:nameofcsdn 发表于2017/3/24 17:17:05 原文链接
阅读:109 评论:0 查看评论

PAT L2-008. 最长对称子串(25) (暴力,Manacher算法和DP解决)

$
0
0

L2-008. 最长对称子串

时间限制
100 ms
内存限制
65536 kB
代码长度限制
8000 B
判题程序
Standard
作者
陈越

对给定的字符串,本题要求你输出最长对称子串的长度。例如,给定"Is PAT&TAP symmetric?",最长对称子串为"s PAT&TAP s",于是你应该输出11。

输入格式:

输入在一行中给出长度不超过1000的非空字符串。

输出格式:

在一行中输出最长对称子串的长度。

输入样例:
Is PAT&TAP symmetric?
输出样例:
11
原题链接:https://www.patest.cn/contests/gplt/L2-008

1000的长度,100ms,o(N^2)的复杂度是可以过的,那就暴力枚举吧,

每次枚举起点和终点没如果此子串是回文串,那终点-起点+1即为回文串的长度,即可求出最大长度.

中间有个小问题,看代码注释.

AC代码:

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=1000+5;
char a[maxn];
int getMax(int x,int y)
{
	//注:下面结束条件,必须为i<=j!!!;
	//当此字符串长度为偶数是会有问题
	//0	1	2	3	4
	//5	4	3	2	1
	for(int i=x,j=y; i<=j; i++,j--)
	{
		if(a[i]!=a[j])
			return 0;
	}
	return y-x+1;
}
int main()
{
	while(gets(a))
	{
		int len=strlen(a);
		int maxx=0;
		for(int i=0; i<len; i++)
		{
			for(int j=i; j<len; j++)
			{
				maxx=max(maxx,getMax(i,j));
			}
		}
		cout<<maxx<<endl;
	}
	return 0;
}

网上还有高手用了o(N)的时间复杂度解决此问题:

即(Manacher)算法:https://www.cnblogs.com/biyeymyhjob/archive/2012/10/04/2711527.html

DP解决:http://blog.csdn.net/yjf3151731373/article/details/51423812


作者:hurmishine 发表于2017/3/24 17:23:50 原文链接
阅读:111 评论:0 查看评论

Gradle 庖丁解牛(构建源头源码浅析)

$
0
0

1 背景

陆陆续续一年多,总是有人问 Gradle 构建,总是发现很多人用 Gradle 是迷糊状态的,于是最近准备来一个“Gradle 庖丁解牛”系列,一方面作为自己的总结,一方面希望真的能达到标题所示效果,同时希望通过该系列达到珍惜彼此时间的目的,因为目前市面上关于 Gradle 的教程都是在教怎么配置和怎么编写插件,很少有说明 Gradle 自己到底是个啥玩意的,还有是如何工作的,本系列以官方 release 3.4 版本为基础。

废话不多说,标题也表明了本篇所总结的内容 —— 构建源头源码浅析,不懂啥叫 Gradle 和 Groovy 的请先移步我以前文章《Groovy 脚本基础全攻略》《Gradle 脚本基础全攻略》,免得这一系列也看不明白咋回事。不过还是要先打个预防针,竟然还有人觉得 Gradle 只能构建 Android App,这 TM 就尴尬了,我想说 Gradle 就是一套脚手架,你想干啥玩意都可以,就看你想不想干,他就是个自动化构建框架,你整明白它的核心以后,他的插件你只用依据规则使用即可,譬如用来构建 Android 的 apply plugin: 'com.android.application' 只是它的一个小插件而已,实质就看你想搞啥了,Java、Web、JS、C 等等都可以用它构建;而整明白它原理核心之一就是你得先整明白他的规则,也就是本文所总结讨论的内容。

【工匠若水 http://blog.csdn.net/yanbober 未经允许严禁转载,请尊重作者劳动成果。私信联系我

2 基础技能叨叨叙

所谓基础技能就是一些铺垫,既然要说 Gradle 构建系列了,我们有必要知道 Gradle 相关的一些基本命令,方便下面演示时使用(注意:如下命令是针对安装 gradle 并配置环境变量的情况下执行,你如果做 Android 开发的话,Ubuntu 直接将如下所有 gradle 替换为 ./gradlew 即可,这样就可以用包装特性了,至于包装是咋回事后面会说),关于其他命令请呼叫 help 或者查看官方 User Guide 的 Using the Gradle Command-Line

//不懂 Gradle 命令了就常呼叫帮助吧。
gradle --help //或者 gradle -h 或者 gradle -? 。

//和本节相关的,查看当前 Gradle 构建包含哪些 task。
gradle tasks [--all] //--all可以更加详细。

//和本节相关的,运行 task。
gradle [taskName | tN] [taskName | tN] ... //支持多个 task 执行,支持驼峰缩写方式,譬如tN,但tN必须全局保持唯一。

//和本节相关的,当我们想修改 Gradle 插件默认定制约束配置时可以查看官方 dsl 文档或者运行如下命令。
gradle properties //结果会列出标准可配置属性列表和当前默认值,我们一般也可用该命令检查自己修改的属性值是否是期望的,譬如 Android 中修改 Project 的编译输出默认目录等。

//查看web版的构建性能耗时分布表,位于build/reports/profile目录下。
gradle taskName --profile

看完和本篇相关的命令总结后来看看前面提到的 gradle 替换 gradlew 执行是咋回事,其实实质可以查看官方 User Guide 的 The Gradle Wrapper,这里给出总结如下:

//项目目录下这四个文件的作用
gradlew (Unix Shell script)
gradlew.bat (Windows batch file)
gradle/wrapper/gradle-wrapper.jar (Wrapper JAR)
gradle/wrapper/gradle-wrapper.properties (Wrapper properties)

其实上面脚本的作用就是对 Gradle 的一个包装,保证任何机器都可以运行这个构建,即使这个机器没有安装 Gradle 或者安装的 Gradle 版本不兼容匹配,如果没装或者不兼容就会根据 gradle-wrapper.properties 里的配置下载特定版本,下载的包放在 $USER_HOME/.gradle/wrapper/dists 目录下,所以我们有时候第一次通过 gradlew 包装脚本执行构建时总会看到正在下载一个 zip 文件,实质就是在下 gradle-wrapper.properties 中指定的 zip 包。
gradlew 有一个非常人性化和牛逼的特点,解决了几种坑爹的问题,譬如团队开发保证 Gradle 构建版本一致性、gradle-wrapper.properties 下载地址方便切换到公司内部服务器等(甚至可以先通过 gradle.properties 文件配置公司服务器的帐号密码或者验证信息,然后在 gradle-wrapper.properties 中配置distributionUrl=https://username:password@somehost/path/to/gradle-distribution.zip,这样就可以达到公司内网加认证下载的双重安全了)。
gradlew 由来的最终原理其实是通过 Gradle 预置的 Wrapper (继承自 DefaultTask )来实现的(AS 内部默认实现了自动生成而已),譬如:

task createWrapper(type: Wrapper) {
    gradleVersion = '3.4'
}

运行 gradle createWrapper 就能生成上面描述的几个文件。而关于 Gradle 的 Wrapper 可以参考 DSL Reference 的 WrapperJavaDoc 的 Wrapper API,里面提供了一堆属性设置下载地址、解压路径、 gradleVersion 等,你也可以在 distributionUrl 中通过 ${gradleVersion} 来使用你设置的 DSL 变量,这里暂时不再展开。

说完命令我们接着说说 Groovy、DSL、Gradle 之间的关系,首先一定要明确,Groovy 不是 DSL,而是通用的编程语言,类似 Java、C++ 等,就是一种语言;但 Groovy 对编写 DSL 提供了很牛逼的支持,这些支持都源自 Groovy 自己语法的特性,比如闭包特性、省略分号特性、有参方法调用省略括弧特性、属性默认实现 getter、setter 方法特性等,当然,作为 Android 开发来说,Gradle 构建 Android 应用实质也是基于 Groovy 编写的 DSL,DSL 存在的意义就在于简化编写和阅读。

而 Gradle 的实质就是一个基于 Groovy 的框架了,也就是说我们得按照他的约束来玩了,和我们平时 Android 开发使用框架类似,一旦引入框架,我们就得按照框架的写法来规规矩矩的编写。Gradle 这个框架只负责流程约定,处理细节是我们自己的事,就像我们编译 Android App 时基于 Gradle 框架流程引入 apply plugin: 'com.android.application' 构建插件一样,具体做事是我们插件再约束的,插件又对我们简化了配置,我们只用基于 Gradle 框架和相关插件进行构建配置。

了所以简单粗暴的解释就是, Groovy 是一门语言,DSL 就是一种特定领域的配置文件,Gradle 就是基于 Groovy 的一种框架,就像我们以前做 Android 开发使用 Ant 构建一样,build.xml 就可以粗略的理解为 Ant 的 DSL 配置,所以我们编写 build.xml 时会相对觉得挺轻松(和后来的 Gradle 还是没法比的)。

搞清了他们之间的关系后我们就要深入看看为啥是这样了,因为关于 Gradle 构建现在中文网上的教程要么是教你如何配置 DSL 属性,要么就是教你如何使用 Groovy 去拓展自己的特殊 task,或者是教你怎么编写插件,却几乎没人提到 Gradle 这个构建框架的本质,所以使用起来总是心里发慌,有种不受控制的感觉。

【工匠若水 http://blog.csdn.net/yanbober 未经允许严禁转载,请尊重作者劳动成果。私信联系我

3 Gradle 源码源头分析

还记得我们前一小节讲的 gradlew 么,追踪溯源就从它开始,以前我也是出于好奇就去看了下它,发现这个 shell 脚本前面其实就是干了一堆没事干的事,大招就在它的最后一句,如下:

exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"

对的,大招就是 GradleWrapperMain,这货还支持通过 “$@” 传递参数,想想我们平时执行的 gradlew 命令,这下明白了吧,既然这样我们就拿他开涮,去看看他的源码,如下:

public class GradleWrapperMain {
    ......
    //执行 gradlew 脚本命令时触发调用的入口。
    public static void main(String[] args) throws Exception {
        //不多说,正如上面分析 gradlew 作用一样,去工程目录下获取 wrapper.jar 和 properties 文件。
        File wrapperJar = wrapperJar();
        File propertiesFile = wrapperProperties(wrapperJar);
        File rootDir = rootDir(wrapperJar);
        //解析gradlew 输入传递的参数等,反正就是一堆准备工作
        CommandLineParser parser = new CommandLineParser();
        ......
        //憋大招的两行
        WrapperExecutor wrapperExecutor = WrapperExecutor.forWrapperPropertiesFile(propertiesFile);
        wrapperExecutor.execute(
                args,
                new Install(logger, new Download(logger, "gradlew", wrapperVersion()), new PathAssembler(gradleUserHome)),
                new BootstrapMainStarter());
    }
}

上面 WrapperExecutor.forWrapperPropertiesFile 方法实质就是通过 java Properties 去解析 gradle/wrapper/gradle-wrapper.properties 文件里的配置,譬如 distributionUrl 等;接着执行 wrapperExecutor.execute 方法,args 参数就是我们执行 gradlew 脚本时传递的参数,Install 实例就是管理本地本项目是否有 wrapper 指定版本的 gradle,木有就去下载解压等等,BootstrapMainStarter 实例就是 wrapper 执行 gradle 真实入口的地方,所以我们接着看看 execute 这个方法,如下:

public void execute(String[] args, Install install, BootstrapMainStarter bootstrapMainStarter) throws Exception {
    //config 就是 gradle-wrapper.properties 解析的配置
    File gradleHome = install.createDist(config);
    bootstrapMainStarter.start(args, gradleHome);
}

到这里如果本地没有 wrapper 包装的 Gradle,就会下载解压等,然后准备一堆货,货备足后就调用了前面说的 BootstrapMainStarter 的 start 方法,如下:

public class BootstrapMainStarter {
    public void start(String[] args, File gradleHome) throws Exception {
        File gradleJar = findLauncherJar(gradleHome);
        URLClassLoader contextClassLoader = new URLClassLoader(new URL[]{gradleJar.toURI().toURL()}, ClassLoader.getSystemClassLoader().getParent());
        Thread.currentThread().setContextClassLoader(contextClassLoader);
        Class<?> mainClass = contextClassLoader.loadClass("org.gradle.launcher.GradleMain");
        Method mainMethod = mainClass.getMethod("main", String[].class);
        mainMethod.invoke(null, new Object[]{args});
        if (contextClassLoader instanceof Closeable) {
            ((Closeable) contextClassLoader).close();
        }
    }
    ......
}

不解释,快上车,真的 Gradle 要现身了,Wrapper 的使命即将终结,我们把重点转到 org.gradle.launcher.GradleMain 的 main 方法,如下:

public class GradleMain {
    public static void main(String[] args) throws Exception {
        new ProcessBootstrap().run("org.gradle.launcher.Main", args);
    }
}

GG了,莫慌,我们的重点不是看懂 Gradle 的每一句代码,我们需要捡自己需要的重点,这货设置各种 ClassLoader 后最终还是调用了 org.gradle.launcher.Main 的 run 方法,实质就是 EntryPoint 类的 run 方法,因为 Main 类是 EntryPoint 类的实现类,而 EntryPoint 的 run 方法最主要做的事情就是创建了一个回调监听接口,然后调用了 Main 重写的 doAction 方法,所以我们去到 Main 的 doAction 看看,如下:

public class Main extends EntryPoint {
    ......
    protected void doAction(String[] args, ExecutionListener listener) {
        createActionFactory().convert(Arrays.asList(args)).execute(listener);
    }

    CommandLineActionFactory createActionFactory() {
        return new CommandLineActionFactory();
    }
}

这货实质调用了 CommandLineActionFactory 实例的 convert 方法得到 Action 实例,然后调用了 Action 的 execute 方法,我去,真特么绕的深,这弯溜的,我们会发现 CommandLineActionFactory 里的 convert 方法实质除过 log 记录准备外干的惟一一件事就是创建其内部类 WithLogging 的对象,这时候我们可以发现 Action 的 execute 方法实质就是调用了 WithLogging 的 execute 实现,如下:

public void execute(ExecutionListener executionListener) {
    //executionListener 是前面传入的回调实现实例
    //各种解析config,譬如参数的--内容等等,不是我们的重点
    //各种初始化、log启动等等,不是我们的重点
    ......
    //大招!!!外面new WithLogging实例时传入的参数!!!
    action.execute(executionListener);
    ......
}

这不,最终还是执行了 new ExceptionReportingAction(
new JavaRuntimeValidationAction(
new ParseAndBuildAction(loggingServices, args)),
new BuildExceptionReporter(loggingServices.get(StyledTextOutputFactory.class), loggingConfiguration, clientMetaData())));
对象的 execute 方法(上面的 action 就是这个对象),关于这个对象的创建我们只用关注 new JavaRuntimeValidationAction(
new ParseAndBuildAction(loggingServices, args))
这个参数即可,这也是一个 Action,实例化后在 ExceptionReportingAction 的 execute 调用了他的 execute,而 ParseAndBuildAction 的 execute 又被 JavaRuntimeValidationAction 的 execute 触发,有点包装模式的感觉,所以我们直接关注 ParseAndBuildAction 的实例化和 execute 方法,因为其他不是我们的重点,如下:

private class ParseAndBuildAction implements Action<ExecutionListener> {
    ......
    public void execute(ExecutionListener executionListener) {
        List<CommandLineAction> actions = new ArrayList<CommandLineAction>();
        //给你一个默认的 help 和 version 的 CommandLineAction 加入 actions 列表
        actions.add(new BuiltInActions());
        //创建一个 GuiActionsFactory 和 BuildActionsFactory 加入 actions 列表
        createActionFactories(loggingServices, actions);
        //依据参数给各个添加到列表的 CommandLineAction 对象进行配置
        CommandLineParser parser = new CommandLineParser();
        for (CommandLineAction action : actions) {
            action.configureCommandLineParser(parser);
        }
        //依据这几个参数获取创建一个可用的 Action<? super ExecutionListener>
        Action<? super ExecutionListener> action;
        try {
            ParsedCommandLine commandLine = parser.parse(args);
            //如果输入的命令中包含 gui 参数则创建 GuiActionsFactory 的 action 备用。
            //如果输入的命令中包含 help 或者 version 参数则创建 BuiltInActions 的 action 备用。
            //其他参数的则创建 BuildActionsFactory 的 action 备用。
            action = createAction(actions, parser, commandLine);
        } catch (CommandLineArgumentException e) {
            action = new CommandLineParseFailureAction(parser, e);
        }
        //执行我们创建的备用 action。。。。
        action.execute(executionListener);
    }
    ......
}

既然我们是追主线分析(关于执行命令中带 help、version、gui 的情况我们就不分析了,也比较简单,当我们执行 gradle –help 或者 gradle –gui 时打印的 help 或者弹出的 GUI 是 BuiltInActions 或者 GuiActionsFactory ,比较简单,不作分析),我们看核心主线 BuildActionsFactory 的 createAction 方法和通过 createAction 方法生成的 Runnable 的 run 方法即可(所谓的主线就是我们执行 gradle taskName 命令走的流程,譬如 gradle asseambleDebug 等),如下是 BuildActionsFactory 的 createAction 方法:

public Runnable createAction(CommandLineParser parser, ParsedCommandLine commandLine) {
    //命令各种转换包装
    Parameters parameters = parametersConverter.convert(commandLine, new Parameters());
    ......
    //三种判断,哪个中了就返回,runXXX系列方法实质都调用了runBuildAndCloseServices方法,只是参数不同而已
    if (parameters.getDaemonParameters().isEnabled()) {
        return runBuildWithDaemon(parameters.getStartParameter(), parameters.getDaemonParameters(), loggingServices);
    }
    if (canUseCurrentProcess(parameters.getDaemonParameters())) {
        return runBuildInProcess(parameters.getStartParameter(), parameters.getDaemonParameters(), loggingServices);
    }
    return runBuildInSingleUseDaemon(parameters.getStartParameter(), parameters.getDaemonParameters(), loggingServices);
}

既然上面都判断最后调用都是类同的,那我们就假设调用了 runBuildInProcess 方法吧,如下:

private Runnable runBuildInProcess(StartParameter startParameter, DaemonParameters daemonParameters, ServiceRegistry loggingServices) {
    //创建client,这是个神奇的设计思路,大招!
    ServiceRegistry globalServices = ServiceRegistryBuilder.builder()
            .displayName("Global services")
            .parent(loggingServices)
            .parent(NativeServices.getInstance())
            .provider(new GlobalScopeServices(startParameter.isContinuous()))
            .build();
    //上面说的,BuildActionsFactory的createAction方法最后都是调用这个方法,只是传递参数不同而已!
    return runBuildAndCloseServices(startParameter, daemonParameters, globalServices.get(BuildExecuter.class), globalServices);
}

此刻您可憋住了,别小看这么简单的一个方法,这玩意麻雀虽小五脏俱全啊,在我第一次看这部分源码时是懵逼的,好在看见了相关类的注释才恍然大悟,至于为啥我们现在来分析下。先说说 globalServices 对象的构建吧,其实和 createGlobalClientServices() 这个方法类似,随意咯,我们就随便看个,如下:

    private ServiceRegistry createGlobalClientServices() {
        return ServiceRegistryBuilder.builder()
                .displayName("Daemon client global services")
                .parent(NativeServices.getInstance())
                .provider(new GlobalScopeServices(false))
                .provider(new DaemonClientGlobalServices())
                .build();
    }

看起来就是构造了一个 clientSharedServices 对象,然后交给下面的 runBuildAndCloseServices 方法使用,对的,就是这样的,只是这个 createGlobalClientServices() 方法真的很懵逼,ServiceRegistryBuilder 的 build() 方法实质是实例化了一个 DefaultServiceRegistry 对象,然后通过构造方法传递了 parent(NativeServices.getInstance()) 实例,通过 addProvider(provider) 方法传递了 provider(new GlobalScopeServices(false)) 和 provider(new DaemonClientGlobalServices()) 实例,巧妙的地方就在 DefaultServiceRegistry 类的注释上面,大家一定要先看注释,ServiceRegistryBuilder 的 build() 最后调用的是 DefaultServiceRegistry 对象的 addProvider 方法,实质调用的是 DefaultServiceRegistry 的 findProviderMethods(provider) 方法,如下:

private void findProviderMethods(Object target) {
    Class<?> type = target.getClass();
    RelevantMethods methods = getMethods(type);
    //把target自己和所有父类中以create开头的方法通过new DecoratorMethodService(target, method)包装加入到ownServices列表。
    for (Method method : methods.decorators) {
        ownServices.add(new DecoratorMethodService(target, method));
    }
    //把target自己和所有父类中以create开头的方法通过new DecoratorMethodService(target, method)包装加入到ownServices列表。
    for (Method method : methods.factories) {
        ownServices.add(new FactoryMethodService(target, method));
    }
    //把target自己和所有父类中叫cofigure的方法都反射调用一把。
    for (Method method : methods.configurers) {
        applyConfigureMethod(method, target);
    }
}

这时咱们先回过头看看前面说的 createGlobalClientServices() 方法,我们发现其中的 NativeServices、FileSystemServices、DaemonClientGlobalServices 都没有 config 方法,但是有一堆 createXXX 的方法,这些都会被加入 ownServices 列表,但是 GlobalScopeServices 类却有 config 方法,如下:

public class GlobalScopeServices {
    ......
    //该方法在DefaultServiceRegistry的findProviderMethods(provider)中被反射调用。
    //registration是DefaultServiceRegistry的newRegistration()方法返回的ServiceRegistration匿名实现对象。
    //classLoaderRegistry就是一个
    void configure(ServiceRegistration registration, ClassLoaderRegistry classLoaderRegistry) {
        //getAll根据PluginServiceRegistry.class传入后的一系列规则,找到所有factory方法。
        final List<PluginServiceRegistry> pluginServiceFactories = new DefaultServiceLocator(classLoaderRegistry.getRuntimeClassLoader(), classLoaderRegistry.getPluginsClassLoader()).getAll(PluginServiceRegistry.class);
        for (PluginServiceRegistry pluginServiceRegistry : pluginServiceFactories) {
            registration.add(PluginServiceRegistry.class, pluginServiceRegistry);
            if (pluginServiceRegistry instanceof GradleUserHomeScopePluginServices) {
                registration.add(GradleUserHomeScopePluginServices.class, (GradleUserHomeScopePluginServices) pluginServiceRegistry);
            }
            pluginServiceRegistry.registerGlobalServices(registration);
        }
    }
    ......
}

到这里你可以暂时松口气了,上面 config 等等一堆都是在做准备,说白了就是各种列表注册都放好,然后 DefaultServiceRegistry 的 get(…) 系列方法实质都是通过 doGet(Type serviceType) 的 invok 方法调用等。接着让我们把目光移到上面运行 gradle taskName 命令时分析的 BuildActionsFactory 的 runBuildInProcess(…) 方法,我们在该方法中调用 runBuildAndCloseServices(…) 方法时第三个参数传递的是 globalServices.get(BuildExecuter.class), 也就是调用了 DefaultServiceRegistry 的 get(BuildExecuter.class) 方法,刚刚说了 DefaultServiceRegistry 的 get(…) 实质就是 invoke 一个方法,在这里 serviceType 参数是 BuildExecuter.class,所以调用的就是 ToolingGlobalScopeServices 的 createBuildExecuter(…) 方法,ToolingGlobalScopeServices 是 LauncherServices 的 registerGlobalServices(…) 方法实例化的,而 LauncherServices implements PluginServiceRegistry 又是刚刚上面分析 GlobalScopeServices 的 configure(…) 方法里被实例化添加的,LauncherServices 的 registerGlobalServices(…) 方法也是在那调用的。

绕了一圈真是折腾,突然发现累觉不爱,觉得 Gradle 框架中 DefaultServiceRegistry 类的设计真的是挺颠覆我认知的,虽然没啥黑科技,但是这个设计思路真的是坑爹,很容易绕懵逼,好在后来整明白了,真想说句 ZNMKD。好了,牢骚也发完了,下面该正题了,我们接着上面说的去看看 LauncherServices 内部 ToolingGlobalScopeServices 的 createBuildExecuter(…) 方法,一贯做法,关注主线,咱们会发现这方法最主要的就是层层简单代理模式包装实例化 BuildActionExecuter 对象,最关键的就是实例化了 InProcessBuildActionExecuter 对象,这个对象就一个 execute 方法(这个 execute 方法被调用的地方就在上面分析的 BuildActionsFactory 的 runBuildInProcess 方法返回的 RunBuildAction 对象的 run 方法中,RunBuildAction 对象的 run 方法又是前面分析的源头触发的),如下:

public class InProcessBuildActionExecuter implements BuildActionExecuter<BuildActionParameters> {
    ......
    //BuildActionsFactory的runBuildInProcess方法返回的RunBuildAction对象的run方法触发该方法调用。
    //参数都是RunBuildAction中传递的,RunBuildAction的参数又是前面分析的BuildActionsFactory的runBuildInProcess方法传递。
    public Object execute(BuildAction action, BuildRequestContext buildRequestContext, BuildActionParameters actionParameters, ServiceRegistry contextServices) {
        //创建DefaultGradleLauncher对象,真是活菩萨啊,总算看到光明了!
        GradleLauncher gradleLauncher = gradleLauncherFactory.newInstance(action.getStartParameter(), buildRequestContext, contextServices);
        try {
            gradleLauncher.addStandardOutputListener(buildRequestContext.getOutputListener());
            gradleLauncher.addStandardErrorListener(buildRequestContext.getErrorListener());
            GradleBuildController buildController = new GradleBuildController(gradleLauncher);
            buildActionRunner.run(action, buildController);
            return buildController.getResult();
        } finally {
            gradleLauncher.stop();
        }
    }
}

赞,到此真想说句真是不容易啊!!!总算看见光明了,我 Gradle 的大 GradleLauncher,为啥这么称呼呢,因为你看了 GradleLauncher 实现你会有种柳暗花明又一村的感觉,真的,你会觉得前面这些复杂的初始化就是为了等到这个实例的到来,因为 GradleLauncher 实现里就真真切切的告诉你了 Gradle 构建的三大生命周期——-初始化、配置、执行,不信你看:

public class DefaultGradleLauncher implements GradleLauncher {
    //大名鼎鼎的 gradle 构建三步生命周期!!!!有种亲爹的感觉!
    private enum Stage {
        Load, Configure, Build
    }
    ......
}

到此构建源头就分析完了,下一篇会接着这里分析 DefaultGradleLauncher 及后续真正开始构建的流程,所以这时候你回过头会发现 Gradle 其实也就那么回事,也是代码写的(哈哈,找打!),只是这一篇我们只分析了 Gradle 框架自身初始化(非构建生命周期的初始化,要区分)的核心流程。

【工匠若水 http://blog.csdn.net/yanbober 未经允许严禁转载,请尊重作者劳动成果。私信联系我

4 总结

为了 Gradle 庖丁解牛系列做铺垫,本篇主要进行了 Gradle 基础铺垫说明总结,后面对 Gradle 框架自身初始化(非构建生命周期的初始化,要区分)的核心流程进行了分析,通过本文我们至少应该知道如下:

  • Gradle 只是一个构建框架,而且大多数代码是 Java 和 Groovy 编写。
  • gradlew 是 gradle 的一个兼容包装工具。
  • 执行 gradle 或者 gradlew 命令开始进行构建生命周期前做的第一步是对 Gradle 框架自身的初始化(本文浅析内容)。

有了这一篇的铺垫,下面几篇我们会以此分析继续,不过主线都是基于执行一个 gradle taskName 命令,所以如果想看懂这个系列文章,建议先补习下 Gradle 构建基础。

^v^当然咯,如果觉得对自己有帮助,不妨扫描打赏一点买羽毛球的票子,是一种动力也是一种鼓励,谢谢。

这里写图片描述
【工匠若水 http://blog.csdn.net/yanbober 未经允许严禁转载,请尊重作者劳动成果。私信联系我

作者:yanbober 发表于2017/3/24 17:54:57 原文链接
阅读:656 评论:6 查看评论

网易编程题八,计算糖果(计算)

$
0
0

计算糖果(计算)

A,B,C三个人是好朋友,每个人手里都有一些糖果,我们不知道他们每个人手上具体有多少个糖果,但是我们知道以下的信息:
A - B, B - C, A + B, B + C. 这四个数值.每个字母代表每个人所拥有的糖果数.
现在需要通过这四个数值计算出每个人手里有多少个糖果,即A,B,C。这里保证最多只有一组整数A,B,C满足所有题设条件。 

输入描述:
输入为一行,一共4个整数,分别为A - B,B - C,A + B,B + C,用空格隔开。
范围均在-30到30之间(闭区间)。
输出描述:
输出为一行,如果存在满足的整数A,B,C则按顺序输出A,B,C,用空格隔开,行末无空格。
如果不存在这样的整数A,B,C,则输出No
输入例子:
1 -2 3 4
输出例子:
2 1 3
代码:

#include <iostream>
using namespace std;

int main()
{
	int a, b, c, d;
	cin >> a >> b >> c >> d;
	int A = (a + c) / 2, B = c - A, C = d - B;
	if (A - B != a || B - C != b)cout << "No";
	else cout << A << " " << B << " " << C;
	return 0;
}

作者:nameofcsdn 发表于2017/3/24 18:04:54 原文链接
阅读:105 评论:0 查看评论

UGUI之坑点小结

$
0
0

以下是我总结断断续续遇到的一些UGUI上的问题,有机会能改则改,改不了的只能想办法注意和避免了。

UGUI刷新问题

场景中没有遮挡的背景时,首次打开UI 手机上不停闪烁或各种花屏问题:

处理办法:

场景中最好加一个物体遮挡,如进游戏底部加一块纯黑板背景,可以避免UI闪烁

其实是canvas相机照不到东西的时候,UGUI的显示不会及时刷新,比如把canvas中最后一个active的对象都隐藏的话,显示上会不刷新,即使拿到的属性activeself其实是false。即看到显示残留

如果父对象下面挂了几个子对象a,b,c,d,如果删除了其中部分子对象 如a,想立即修改bcd的先后层次的话,用SetSiblingIndex()方式就可能出问题,即出现 数值刷新了,但显示未刷新的问题。

解决办法:

因此对于兄弟节点出生销毁后同帧立即调整当前节点层级的话,最好通过transform.SetAsFirstSibling();或transform.SetAsLastSibling();来实现层级调整

UGUI的图集问题
1. UGUI的图集打包算法有问题,基本表现是它一定把不同实际压缩格式的小图放在了不同的group。比如有两个小图,用了不同的压缩格式,他们最终会在两个group图,导致一个图集扩成了两张;
2. 带透明通道和不带透明通道的素材也会被分在两个group!!坑的地方来了,使得如果众多素材中有几个不带透明通道的,那么你把那些透明素材压缩到死,也不会将非透明通道图合并到当前图集来,(因为是带和不带透明通道的两种图本身就会以两种压缩格式来处理))
3. 呵呵mitmap有或没有也会被拆分到连个group里

解决办法,几个都要保证:
  1. 同一个图集统一压缩格式;
  2. 在素材上,同一个图集中的所有素材都应该是带透明像素的,或者统一不带透明像素,遇到透明图集出现个别不包含透明像素的,去PS给将这个图其中一像素修改为有透明度就OK(如透明度99%);
  3. 想要使用UGUI默认的ETC压缩的话,单张图应该宽和高尺寸都能被4整除。否则的话,该单独素材会以RGB32压缩格式处理;

因此,如图中,所有标黄的地方,即便你填了相同的Packing Tag,但黄色设置有一项不一致,最终这批图不会出现在同一个图集中的

这里写图片描述

作者:Stephanie_1 发表于2017/3/24 18:34:11 原文链接
阅读:136 评论:0 查看评论

CSDN日报20170324——《程序员们,再不行动就来不及了!》

$
0
0

【程序人生】程序员们,再不行动就来不及了!”

作者:左潇龙

写这篇文章,其实就是想给程序员们敲个警钟,虽然未来的很多事都说不准,但其实还是有轨迹可循的。

另外,LZ觉得,随着程序员们的年纪越来越大,会有不少程序员在一线无法生存,这就会导致大批量年纪较大的程序员涌向二线。或许在不久的将来,一线将不会再是程序员的主阵地,而是二线、三线甚至四线这种生活成本较小的城市。

毕竟互联网又不像你开超市,你必须要开到北京,才能服务北京的人群。互联网的好处就是,它可以随时随地为你服务。


【开发工具】Gradle 庖丁解牛(构建源头源码浅析)

作者:工匠若水

陆陆续续一年多,总是有人问 Gradle 构建,总是发现很多人用 Gradle 是迷糊状态的,于是最近准备来一个“Gradle 庖丁解牛”系列,一方面作为自己的总结,一方面希望真的能达到标题所示效果,同时希望通过该系列达到珍惜彼此时间的目的,因为目前市面上关于 Gradle 的教程都是在教怎么配置和怎么编写插件,很少有说明 Gradle 自己到底是个啥玩意的,还有是如何工作的,本系列以官方 release 3.4 版本为基础。

废话不多说,标题也表明了本篇所总结的内容 —— 构建源头源码浅析,不懂啥叫 Gradle 和 Groovy 的请先移步我以前文章《Groovy 脚本基础全攻略》《Gradle 脚本基础全攻略》,免得这一系列也看不明白咋回事。


【图形处理】游戏运动模糊技术讲解

作者:姜雪伟

运动模糊是3D格斗游戏中非常受欢迎的技术,其目的是为移动物体增加模糊效果,这增强了玩家体验到的现实感,运动模糊可以以各种方式实现。 有一个基于相机的运动模糊,它专注于相机运动,并且有一个基于对象的运动模糊。 在本篇博客中,我们将研究一个以后完成的选项。

运动模糊的原理是我们可以计算两帧之间每个渲染像素的运动矢量(a.k.a运动矢量),
通过从当前颜色缓冲区沿着该向量进行采样并对结果进行平均,我们得到代表底层对象运动的像素, 让我们来看看下一个细节,以下是所需步骤,之后我们将审查实际代码。


【系统运维】Linux Bridge 的 IP NAT 细节探析-填补又一坑的过程

作者:赵亚

近日温州皮鞋厂老板正在忙着学习Linux Bridge以及诸多虚拟网卡相关的东西,老湿给了一些指导,但最根本的还要靠温州老板自己。就好像有仙灵在聆听心声,我正因为温州老板的缘故一而再再而三地怀念曾经玩转Linux Bridge,Linux Netfilter的那段痛并快乐着的时光,另外一个好玩的东西恰在此时切入。

大概有三年多没有玩Linux Bridge了,甚是想念。感谢同事给我一个Bridge方面的疑难杂症让我诊断!

凭着经验,很快搞定了问题,但是如果就此了断怕是在多年后错过一些吹嘘的机会,所以便作此文,以为后来留下当年之叹息。


【Java 编程】 J.U.C 之 AQS :阻塞和唤醒线程

作者:chenssy

在线程获取同步状态时如果获取失败,则加入 CLH 同步队列,通过通过自旋的方式不断获取同步状态,但是在自旋的过程中则需要判断当前线程是否需要阻塞,其主要方法在 acquireQueued():

在获取同步状态失败后,线程并不是立马进行阻塞,需要检查该线程的状态,检查状态的方法为 shouldParkAfterFailedAcquire(Node pred, Node node) 方法,该方法主要靠前驱节点判断当前线程是否应该被阻塞。


【人工智能】TensorFlow调试之一种很笨但行之有效的调试方案

作者:liuchonge

说道 TensorFlow 调试,想必大家都是深受其扰,特别是对于新手而言。主要是因为其分为模型搭建和图运行两个阶段,而我们在使用一般的 IDE 进行调试时只能调试前半部分,即模型搭建环节。在这一环节中,往往我们所能看到的信息是有限的,比如只能看到 Tensor 的 shape 却看不到其具体值等等,但是这样的话我们就不知道模型搭建的是否完全正确(譬如仅 shape 对应的话,很多时候并不能表征模型正确无误)。


【Android 开发】Retrofit/OkHttp API 接口加固技术实践(下)

作者:Tamic

上节加固介绍了APi单纯Post用对称加密(Base64 为列子)加密方式,这种加密方式还是存在一定的风险,加密效率虽高,但易破解,本节将介绍怎么用非对称加密 来加解密okhttp的数据,本文采用RSA加密算法为栗子。


【好书推荐】数源思维完成目标设定

作者:博文视点

数源思维是为非专业数据技术人员提供的一种有效利用数据解决问题的思维方法。这种方法的简单描述就是“从业务中来,回业务中去”。让非技术人员读懂数据、利用数据、还原数据背后的真实市场。在本文中,数源思维通过问、拆、解、谋四步就能将数据及其方法很好的融合到业务问题的解决中,从而将业务解题能力从经验时代提升到数据时代。

本文选自《数源思维:业务导向的数据思维秘籍》。


关注专栏【CSDN 日报】,获取最新及往期内容。

作者:blogdevteam 发表于2017/3/24 18:57:40 原文链接
阅读:1050 评论:2 查看评论

ExtJS图表

$
0
0

1.1 学习技能点

本次在线学习将学习以下知识技能:

Ø 柱状图

Ø 饼状图

Ø 折线图

1.2 学习任务

ExtJS3使用的Flash Chart来源于YUI,其中包括柱状图、饼状图等多种图表,这些图表可以与ExtJS组件完美整合,不仅可以在Panel中显示图表,还可以通过Store为图表提供数据。

1.2.1 任务1使用柱状图统计每月的访问人数

需求说明

首先定义一个JsonStroe为我们要实现的图表提供数据,代码如下:

var store = new Ext.data.JsonStore({

        fields:['name', 'visits', 'views'],

        data: [

            {name:'Jul 07', visits: 245000, views: 3000000},

            {name:'Aug 07', visits: 240000, views: 3500000},

            {name:'Sep 07', visits: 355000, views: 4000000},

            {name:'Oct 07', visits: 375000, views: 4200000},

            {name:'Nov 07', visits: 490000, views: 4500000},

            {name:'Dec 07', visits: 495000, views: 5800000},

            {name:'Jan 08', visits: 520000, views: 6000000},

            {name:'Feb 08', visits: 620000, views: 7500000}

        ]

 });

JsonStroe中包含3列数据,分别是namevisitsviews,分别表示日期、访问人数、浏览量,本章各个任务都使用此数据。

大家已经学习了可以使用grid显示这些数据,但是不利于分析,也很难看出数据的变化,下面就使用柱状图统计每个月的访问人数,效果如图6.1.1所示。

 

6.1.1 柱状图

实现步骤

//此行代码必须,指定图表swf文件路径

Ext.chart.Chart.CHART_URL = 'extjs/resources/charts.swf';

Ext.onReady(function(){

   var store = new Ext.data.JsonStore({

        fields:['name', 'visits', 'views'],

        data: [

            {name:'Jul 07', visits: 245000, views: 3000000},

            {name:'Aug 07', visits: 240000, views: 3500000},

            {name:'Sep 07', visits: 355000, views: 4000000},

            {name:'Oct 07', visits: 375000, views: 4200000},

            {name:'Nov 07', visits: 490000, views: 4500000},

            {name:'Dec 07', visits: 495000, views: 5800000},

            {name:'Jan 08', visits: 520000, views: 6000000},

            {name:'Feb 08', visits: 620000, views: 7500000}

        ]

    });

    new Ext.Panel({

        title: 'Chart',

        renderTo: 'chart',

        width:500,

        height:300,

        frame:true,

        layout:'fit',

        items: {

            xtype: 'columnchart',//指定是柱状图

            store: store,//指定数据

            xField: 'name',//X坐标数据来源

            yField: 'visits'//Y坐标数据来源

        }

    });

});

注意:包含图表的页面必须部署到服务器中进行访问,否则无法显示图表。

1.2.2 任务2使用折线图统计每月的访问人数

需求说明

使用折线图统计每月的访问人数,效果如图6.1.2所示。

 

6.1.2 折线图

1.2.3 任务3:使用饼状图统计每月的访问人数

需求说明

使用饼状图统计每月的访问人数,效果如图6.1.3所示。

 

6.1.3 饼状图

1.3 参考资料

本章节学习资料来源于:

http://www.sencha.com/

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

第2章 复习指导

2.1 知识总结

2.1.1 阶段核心技能目标

本课程要掌握如下技能和知识:

Ø 掌握XML文档和解析

Ø 熟练应用ExtJS常用组件

Ø 熟练应用ExtJS常用布局

Ø 掌握ExtJS工具栏和菜单

Ø 掌握ExtJS图表

2.1.2 知识体系总结

本课程所学知识如图6.1.1所示,从图中可以总结使用ExtJS开发常用知识。

 

7.1.1 使用ExtJS开发RIA应用知识

 

2.2 综合实训

2.2.1 任务描述

本次综合实训任务是使用ExtJS作为前端RIA框架,后台技术使用SSH实现一个学生管理系统。系统首页如图7.1.2所示。

 

7.1.2 学生管理系统首页

点击添加工具按钮,出现添加学生界面,效果如图7.1.3所示。

 

7.1.3 添加学生信息界面

选中Grid中的一行数据后,点击修改工具按钮出现学生信息修改,效果界面如图7.1.4所示。

 

7.1.4 学生信息修改界面

双击Grid中的一行数据,将使用RowEditor进行编辑学生信息,效果如图7.1.5所示。

 

7.1.5 使用RowEditor编辑学生信息

修改学生信息,点击更新按钮后完成学生信息修改,效果如图7.1.6所示。

 

7.1.6 使用RowEditor修改学生信息成功

2.2.2 系统功能

本系统包括以下功能:

Ø 使用Grid本页显示学生信息

Ø 添加学生信息

Ø 修改学生信息

Ø 删除学生信息

Ø 使用行编辑器编辑学生信息

2.2.3 开发要求

ExtJS3Struts2Hibernate3Spring2.5JSONLib

2.2.4 实现步骤

1. 新建Web项目并添加SSH框架支持

2. 编写Hibernate实体类和映射文件

实体类代码如下所示:

package com.yccn.student.entity;

public class Student {

private int id;

private String code;

private String name;

private int sex;

private int age;

private String political;

private String origin;

//省略gettersetter

}

3. 编写DAO层接口和实现

DAO接口代码代码如下所示:

package com.yccn.student.dao;

public interface StudentDAO {

Serializable save(Student st);

Student getById(int id);

void deleteById(int id);

List<Student> queryByPage(int start,int limit);

Object merge(Student st);

Long getCount();

}

DAO实现类代码如下所示:

package com.yccn.student.dao.impl;

import java.io.Serializable;

import java.util.List;

import org.hibernate.Session;

import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import com.yccn.student.dao.StudentDAO;

import com.yccn.student.entity.Student;

 

public class StudentDAOImpl extends HibernateDaoSupport implements StudentDAO {

@SuppressWarnings("unchecked")

@Override

public List<Student> queryByPage(int start, int limit) {

Session session = getSession(false);

List<Student> students = session.createQuery(

"from Student s order by s.code").setFirstResult(start)

.setMaxResults(limit).list();

return students;

}

 

@Override

public Serializable save(Student st) {

return getHibernateTemplate().save(st);

}

 

@Override

public Student getById(int id) {

return (Student) getHibernateTemplate().get(Student.class, id);

}

 

@Override

public void deleteById(int id) {

getHibernateTemplate().delete(getById(id));

}

 

@Override

public Object merge(Student st) {

return getHibernateTemplate().merge(st);

}

 

@Override

public Long getCount() {

return (Long) getHibernateTemplate().find(

"select count(id) from Student").get(0);

}

 

}

4. 编写业务逻辑层接口和实现类

业务逻辑层接口代码参考如下:

package com.yccn.student.service;

import java.io.Serializable;

import java.util.List;

import com.yccn.student.entity.Student;

public interface StudentService {

List<Student> listStudentsByPage(int start, int limit);

Serializable doAdd(Student st);

Object doEdit(Student st);

void doDelete(int id);

Long getCount();

}

 

业务逻辑层实现类代码参考如下:

package com.yccn.student.service.impl;

 

import java.io.Serializable;

import java.util.List;

import com.yccn.student.dao.StudentDAO;

import com.yccn.student.entity.Student;

import com.yccn.student.service.StudentService;

public class StudentServiceImpl implements StudentService {

private StudentDAO studentDAO;

public void setStudentDAO(StudentDAO studentDAO) {

this.studentDAO = studentDAO;

}

public List<Student> listStudentsByPage(int start,int limit){

return studentDAO.queryByPage(start, limit);

}

 

@Override

public Serializable doAdd(Student st) {

return studentDAO.save(st);

}

 

@Override

public Object doEdit(Student st) {

return studentDAO.merge(st);

}

 

@Override

public void doDelete(int id) {

studentDAO.deleteById(id);

}

 

@Override

public Long getCount() {

return studentDAO.getCount();

}

}

5. 编写Action

Action类代码参考如下:

package com.yccn.student.action;

 

import java.io.IOException;

import java.io.PrintWriter;

import java.util.HashMap;

import java.util.List;

import java.util.Map;

import javax.servlet.http.HttpServletResponse;

import net.sf.json.JSONObject;

import org.apache.struts2.ServletActionContext;

import com.opensymphony.xwork2.ModelDriven;

import com.yccn.student.entity.Student;

import com.yccn.student.service.StudentService;

 

public class StudentAction implements ModelDriven<Student> {

private Student student = new Student();

private StudentService studentService;

private int start;

private int limit;

public int getStart() {

return start;

}

public void setStart(int start) {

this.start = start;

}

public int getLimit() {

return limit;

}

public void setLimit(int limit) {

this.limit = limit;

}

public void setStudentService(StudentService studentService) {

this.studentService = studentService;

}

@Override

public Student getModel() {

return student;

}

//分页查询学生信息

public String listStudents() throws Exception {

List<Student> students = studentService.listStudentsByPage(start, limit);

Map<String,Object> data = new HashMap<String,Object>();

data.put("totalCount", studentService.getCount());

data.put("result", students);

this.outPrint(this.toJSONString(data));

return null;

}

//添加学生信息

public String add() throws Exception {

studentService.doAdd(student);

outPrint("{success:true,msg:'添加学生信息成功'}");

return null;

}

//修改学生信息

public String edit() throws Exception {

studentService.doEdit(student);

System.out.println(student);

outPrint("{success:true,msg:'修改学生信息成功'}");

return null;

}

//删除学生信息

public String delete() throws Exception {

studentService.doDelete(student.getId());

System.out.println(student.getId());

outPrint("{success:true,msg:'删除学生信息成功'}");

return null;

}

private String toJSONString(Object o){

return JSONObject.fromObject(o).toString();

}

private void outPrint(String s) throws IOException{

HttpServletResponse response = ServletActionContext.getResponse();

response.setCharacterEncoding("utf8");

PrintWriter out = response.getWriter();

out.print(s);

}

}

6. 框架配置

最终各个配置文件如下所示:

web.xml

<?xml version="1.0" encoding="UTF-8"?>

<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://java.sun.com/xml/ns/javaee

http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

<listener>

<listener-class>

org.springframework.web.context.ContextLoaderListener

</listener-class>

</listener>

<context-param>

<param-name>contextConfigLocation</param-name>

<param-value>classpath:applicationContext_*.xml</param-value>

</context-param>

<filter>

<filter-name>struts2</filter-name>

<filter-class>

org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter

</filter-class>

</filter>

<filter-mapping>

<filter-name>struts2</filter-name>

<url-pattern>/*</url-pattern>

</filter-mapping>

</web-app>

Hibernate配置文件:

<?xml version='1.0' encoding='UTF-8'?>

<!DOCTYPE hibernate-configuration PUBLIC

          "-//Hibernate/Hibernate Configuration DTD 3.0//EN"

          "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<hibernate-configuration>

<session-factory>

<property name="dialect">

org.hibernate.dialect.MySQLDialect

</property>

<property name="connection.url">jdbc:mysql:///test</property>

<property name="connection.username">root</property>

<property name="connection.password">admin</property>

<property name="connection.driver_class">

com.mysql.jdbc.Driver

</property>

<property name="hibernate.show_sql">true</property>

<property name="hibernate.hbm2ddl.auto">update</property>

<mapping resource="com/yccn/student/entity/Student.hbm.xml" />

</session-factory>

</hibernate-configuration>

Spring配置使用多配置文件的方式,其中applicationContext_common.xml代码如下:

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"

xmlns:tx="http://www.springframework.org/schema/tx"

xsi:schemaLocation="

       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd

       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd

       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">

 

<bean id="sessionFactory"

class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">

<property name="configLocation" value="classpath:hibernate.cfg.xml">

</property>

</bean>

<bean id="myTxManager"

class="org.springframework.orm.hibernate3.HibernateTransactionManager">

<property name="sessionFactory" ref="sessionFactory" />

</bean>

 

<aop:config>

<aop:pointcut id="serviceMethods"

expression="execution(* com.yccn.student.service.impl.*.*(..))" />

<aop:advisor advice-ref="txAdvice" pointcut-ref="serviceMethods" />

</aop:config>

 

<tx:advice id="txAdvice" transaction-manager="myTxManager">

<tx:attributes>

<tx:method name="do*" />

<tx:method name="*" propagation="SUPPORTS" read-only="true" />

</tx:attributes>

</tx:advice>

</beans>

applicationContext_student.xml代码如下

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"

xmlns:tx="http://www.springframework.org/schema/tx"

xsi:schemaLocation="

       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd

       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd

       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">

 

<bean name="studentDAO" class="com.yccn.student.dao.impl.StudentDAOImpl">

<property name="sessionFactory" ref="sessionFactory"></property>

</bean>

<bean name="studentService" class="com.yccn.student.service.impl.StudentServiceImpl">

<property name="studentDAO" ref="studentDAO"></property>

</bean>

<bean name="studentAction" class="com.yccn.student.action.StudentAction" scope="prototype">

<property name="studentService" ref="studentService"></property>

</bean>

</beans>

7. 编写前端界面

前端使用ExtJS实现,参考代码如下所示。

Ext.onReady(function() {

Ext.QuickTips.init();

    var sexRenderer = function(value) {

        if (value == 1) {

            return '<span style="color:red;font-weight:bold;"></span>';

        } else if (value == 2) {

            return '<span style="color:green;font-weight:bold;"></span>';

        }

    };

 var editor = new Ext.ux.grid.RowEditor({

        saveText: '更新',

        cancelText:'取消'

        

});

editor.on("afteredit",function(roweditor, changes, record, rowIndex){

Ext.Ajax.request({

        url: 'student_edit.action',

        success: function(response) {

         record.commit();

            var json = Ext.decode(response.responseText);

            if (json.success) {

                Ext.example.msg('操作提示',json.msg);

            }

        },

        failure: function() {

            Ext.Msg.alert('错误', "删除失败");

        },

        params: record.data

});

});

 

    var StudentRecord = Ext.data.Record.create([

        {name: 'id', type: 'int'},

        {name: 'code', type: 'string'},

        {name: 'name', type: 'string'},

        {name: 'sex', type: 'int'},

        {name: 'age', type: 'int'},

        {name: 'political', type: 'string'},

        {name: 'origin', type: 'string'},

        {name: 'professional', type: 'string'}

    ]);

 

    var store = new Ext.data.Store({

        proxy: new Ext.data.HttpProxy({url: 'student_listStudents.action'}),

        reader: new Ext.data.JsonReader({

            totalProperty: 'totalCount',

            root: 'result'

        },StudentRecord),

        remoteSort: true

    });

    store.load({params:{start:0,limit:10}});

var sexCombo = new Ext.form.ComboBox({

fieldLabel: '性别',

name: 'sexText',

        hiddenName: 'sex',

triggerAction: 'all',

mode: 'local',

valueField: 'value',

displayField: 'text',

store: new Ext.data.SimpleStore({

    fields: ['value','text'],

    data: [['1',''],['2','']]

})

});

var politicalCombo = new Ext.form.ComboBox({

name: 'political',

store: new Ext.data.SimpleStore({

                fields: ['text'],

                data: [['群众'],['党员'],['团员']]

            }),

        emptyText: '请选择',

        mode: 'local',

        triggerAction: 'all',

        valueField: 'text',

        displayField: 'text',

        fieldLabel: '政治面貌'

});

    var columns = new Ext.grid.ColumnModel([{

header : '学号',

dataIndex : 'code',

editor : {

xtype : 'textfield',

allowBlank : false

}

}, {

header : '姓名',

dataIndex : 'name',

editor : {

xtype : 'textfield',

allowBlank : false

}

}, {

header : '性别',

dataIndex : 'sex',

renderer : sexRenderer,

editor:{

xtype:'combo',

triggerAction: 'all',

mode: 'local',

valueField: 'value',

displayField: 'text',

store: new Ext.data.SimpleStore({

    fields: ['value','text'],

    data: [['1',''],['2','']]

})

}

}, {

header : '年龄',

dataIndex : 'age',

editor : {

xtype : 'numberfield',

allowBlank : false

}

}, {

header : '政治面貌',

dataIndex : 'political',

editor:{

xtype: 'combo',

store: new Ext.data.SimpleStore({

                fields: ['text'],

                data: [['群众'],['党员'],['团员']]

            }),

        emptyText: '请选择',

        mode: 'local',

        triggerAction: 'all',

        valueField: 'text',

        displayField: 'text'

}

}, {

header : '籍贯',

dataIndex : 'origin',

editor : {

xtype : 'textfield',

allowBlank : false

}

}]);

    columns.defaultSortable = true;

 

    // grid start

    var grid = new Ext.grid.GridPanel({

        title: '学生信息列表',

        region: 'center',

        loadMask: true,

        stripeRows:true,

        plugins: [editor],

        store: store,

        cm: columns,

        sm: new Ext.grid.RowSelectionModel({singleSelect:true}),

        viewConfig: {

            forceFit: true

        },

        bbar: new Ext.PagingToolbar({

            pageSize: 10,

            store: store,

            displayInfo: true,

            plugins: new Ext.ux.ProgressBarPager()

        }),

        tbar:[{

         text:'添加',

         icon:'icon/add.gif',

         handler:function(){

         form.getForm().reset();

         window.show();

         }

        },'-',{

         text:'修改',

         icon:'icon/edit.png',

         handler:function(){

         var record = grid.getSelectionModel().getSelected();

         if(!record){

         Ext.Msg.alert("提示","请选择要操作的记录行");

         } else {

         form.getForm().loadRecord(record);

         window.show();

         }

         }

        },'-',{

         text:'删除',

         icon:'icon/delete.gif',

         handler: function() {

                var record = grid.getSelectionModel().getSelected();

                if (!record) {

                    Ext.Msg.alert('提示', '请选择需要删除的信息。');

                } else {

                 Ext.Msg.confirm("提示","删除后将无法恢复,确定要删除记录吗?",

                 function(btn){

                 if(btn == "yes"){

                 Ext.Ajax.request({

                        url: 'student_delete.action',

                        success: function(response) {

                          var json = Ext.decode(response.responseText);

                          if (json.success) {

                            Ext.Msg.alert('消息', json.msg, function() {

                                    grid.getStore().reload();

                                    form.getForm().reset();

                                });

                            }

                        },

                        failure: function() {

                            Ext.Msg.alert('错误', "删除失败");

                        },

                        params: "id=" + record.data.id

                    });

                 }

                 })

                }

            }

        },'-',{

         xtype:'textfield',

         width:250

        },'-',{

         text:'搜索',

         icon:'icon/query.png'

        }]

    });

    /*grid.on("rowdblclick",function(g,i){

     var rc = grid.getStore().getAt(i);

      form.getForm().reset();

        form.getForm().loadRecord(rc);

        window.show();

    });*/

    // grid end

 

    // form start

    var form = new Ext.form.FormPanel({

        frame: true,

        width: 300,

        autoHeight: true,

        labelAlign: 'right',

        labelWidth: 60,

        defaultType: 'textfield',

        buttonAlign:'center',

        defaults: {

            width: 200,

            allowBlank: false

        },

        items: [{

            xtype: 'hidden',

            name: 'id'

        },{

            fieldLabel: '学号',

            name: 'code'

        },{

            fieldLabel: '姓名',

            name: 'name'

        },{

            fieldLabel: '年龄',

            name: 'age',

            xtype: 'numberfield',

            allowNegative: false

        },sexCombo,politicalCombo,{

            fieldLabel: '籍贯',

            name: 'origin'

        }],

        buttons: [{

            text: '提交',

            handler: function() {

                if (!form.getForm().isValid()) {

                    return;

                }

                var v = form.getForm().findField("id").getValue();

                //alert(v);

                if(v == ""){

                  // 添加

               form.getForm().submit({

                    url: 'student_add.action',

                    success: function(f, action) {

                        if (action.result.success) {

                        window.hide();

                          Ext.Msg.alert('消息', action.result.msg, function() {

                                grid.getStore().reload();

                                form.getForm().reset();

                            });

                        }

                    },

                    failure: function() {

                        Ext.Msg.alert('错误', "添加失败");

                    }

               });

                } else {

                 //修改

                 form.getForm().submit({

                    url: 'student_edit.action',

                    success: function(f, action) {

                     if (action.result.success) {

                       window.hide();

                       Ext.Msg.alert('消息', action.result.msg, function() {

                                grid.getStore().reload();

                                form.getForm().reset();

                            });

                      }

                    },

                    failure: function() {

                        Ext.Msg.alert('错误', "添加失败");

                    }

               });

                }

               

            }

        },{

            text: '重置',

            handler: function() {

                form.getForm().reset();

            }

        }]

    });

    // form end

var window = new Ext.Window({

title:'编辑学生信息',

closable:true,

width:312,

closeAction:'hide',

modal:true,

items:form

});

 

    // layout start

    var viewport = new Ext.Viewport({

        layout: 'border',

        items: [grid]

    });

    // layout end

});

 

 

 

 

 

 

 

 

作者:zhangchen124 发表于2017/3/24 21:31:52 原文链接
阅读:85 评论:0 查看评论

深入理解Java之jvm启动流程

$
0
0

概述

当我们写一个Java类,并重写Main方法,程序就能运行起来。main方法的背后,程序为什么能运行,jvm究竟做了什么处理?要理解这些,就需要了解jvm的设计原理以及启动的流程。

虚拟机的启动入口位于share/tools/launcher/java.c的main方法,整个流程分为如下几个步骤:
1、配置JVM装载环境
2、解析虚拟机参数
3、设置线程栈大小
4、执行Java main方法

jvm启动流程分析

配置JVM装载环境

Java代码执行时需要一个JVM环境,JVM环境的创建包括两部分:JVM.dll文件的查找和装载。

JVM.dll文件查找

我们来看一段Jre通过环境的路径和系统版本寻找jvm.cfg文件的代码。
这里写图片描述

说明:
1、GetJREPath()查找当前JRE环境的所在路径;
2、ReadKnownVms()读取JRE路径\lib\ARCH(CPU构架)\JVM.cfg文件,其中ARCH(CPU构架)通过GetArch方法获取,在window下有三种情况:amd64、ia64和i386;
3、CheckJvmType确定当前JVM类型,先判断是否通过-J、-XXaltjvm=或-J-XXaltjvm=参数指定,如果没有,则读取JVM.cfg文件中配置的第一个类型;
4、GetJVMPath根据上一步确定的JVM类型,找到对应的JVM.dll文件;

JVM.dll文件的装载

调用JVM.dll文件中定义的函数初始化虚拟机中的函数。

这里写图片描述

JVM.dll文件的装载:

1、LoadLibrary方法装载JVM.dll动态连接库;
2、把JVM.dll文件中定义的函数JNI_CreateJavaVM和JNI_GetDefaultJavaVMInitArgs绑定到InvocationFunctions变量的CreateJavaVM和GetDefaultJavaVMInitArgs函数指针变量上;

虚拟机参数解析

装载完JVM环境之后,需要对启动参数进行解析,其实在装载JVM环境的过程中已经解析了部分参数,该过程通过ParseArguments方法实现,并调用AddOption方法将解析完成的参数保存到JavaVMOption中,JavaVMOption结构实现如下:
这里写图片描述

AddOption代码:
这里写图片描述

AddOption核心就是对-Xss参数进行特殊处理,并设置threadStackSize,因为参数格式比较特殊,其它是key/value键值对,它是-Xss512的格式。后续Arguments类会对JavaVMOption数据进行再次处理,并验证参数的合理性。

参数处理

Arguments::parse_each_vm_init_arg方法负责处理经过解析过的JavaVMOption数据,部分实现如下:
这里写图片描述

这里列出了JavaVMOption三个常用的参数:
1、-Xmn:设置新生代的大小NewSize和MaxNewSize;
2、-Xms:设置堆的初始值InitialHeapSize,也是堆的最小值;
3、-Xmx:设置堆的最大值MaxHeapSize;

参数验证

Arguments::check_gc_consistency方法负责验证虚拟机启动参数中配置GC的合理性,实现如下:
这里写图片描述

1、如果参数为-XX:+UseSerialGC -XX:+UseParallelGC,由于UseSerialGC和UseParallelGC不能兼容,JVM启动时会抛出错误信息;
2、如果参数为-XX:+UseConcMarkSweepGC -XX:+UseParNewGC,其中UseConcMarkSweepGC和UseParNewGC可以兼容,JVM可以正常启动;

设置线程栈大小

这里写图片描述

如果启动参数未设置-Xss,即threadStackSize为0,则调用InvocationFunctions的GetDefaultJavaVMInitArgs方法获取JavaVM的初始化参数,即调用JVM.dll函数JNI_GetDefaultJavaVMInitArgs,定义在share\vm\prims\jni.cpp,实现如下:

这里写图片描述

ThreadStackSize定义在globals.hpp中,根据当前系统类型,加载对应的配置文件,所以在不同的系统中,ThreadStackSize的默认值也不同。

执行main方法

这里写图片描述

线程栈大小确定后,通过ContinueInNewThread方法创建新线程,并执行JavaMain函数,JavaMain函数的大概流程如下:

1、新建JVM实例

InitializeJVM方法调用InvocationFunctions的CreateJavaVM方法,即调用JVM.dll函数JNI_CreateJavaVM,新建一个JVM实例,该过程比较复杂,会在后续文章进行分析。

2、加载主类的class

Java运行方式有两种:jar方式和class方式。

jar方式:

这里写图片描述

1、调用GetMainClassName方法找到META-INF/MANIFEST.MF文件指定的Main-Class的主类名;
2、调用LoadClass方法加载主类的class文件;

class方式:

这里写图片描述

1、调用NewPlatformString方法创建类名的String对象;
2、调用LoadClass方法加载主类的class文件;

3,查找main方法

通过GetStaticMethodID方法查找指定方法名的静态方法,实现如下:
这里写图片描述

最终调用JVM.dll函数jni_GetStaticMethodID实现。

这里写图片描述

其中get_method_id方法根据类文件对应的instanceKlass对象查找指定方法。

4、执行main方法

这里写图片描述

1、重新创建参数数组;
2、其中mainID是main方法的入口地址,CallStaticVoidMethod方法最终调用JVM.dll中的jni_CallStaticVoidMethodV函数。

这里写图片描述

这里写图片描述

最终通过JavaCalls::call执行main方法,到此Jvm调用main方法启动类的完整流程就讲完了。

作者:xiangzhihong8 发表于2017/3/24 21:46:25 原文链接
阅读:94 评论:0 查看评论

警告:由于aix的操作系统patch导致的Oracle数据库块损坏问题

$
0
0

摘自:
ALERT: Database Corruption ORA-600 ORA-7445 errors after applying AIX SP patches - AIX 6.1.9.8 or AIX 7.1.3.8 or AIX 7.1.4.3 or AIX 7.2.0.3 or AIX 7.2.1.0, 01 (Doc ID 2237498.1)

APPLIES TO:

Oracle Database - Enterprise Edition - Version 11.2.0.3 to 12.2.0.1 [Release 11.2 to 12.2]
IBM AIX on POWER Systems (64-bit)
A problem has been discovered in the latest SP patches for IBM AIX 6.1 and 7.1 (SP 08 and SP 03) where 11.2.0.3, 11.2.0.4, or 12.1 or 12.2 are running. ORA-600 errors and possible database corruption.

upgrade from AIX 6.1.9.7 to SP08
upgrade from AIX 7.1.4.2 to SP03
or running on one of the oslevels listed below in this note.

This is only known to impact Oracle 11.2.0.3.x, 11.2.0.4.x, 12.1.0.2, or 12.2.0.1 on AIX platforms. It has been observed on various Oracle PSU versions.
The symptoms observed so far are ORA-600 memory related failures with examples below.
Additionally, Redo log corruption has been observed in at least two cases.

DESCRIPTION

 Database Corruption and/or ORA-600 ORA-7445 errors after applying IBM AIX SP patches - After update from AIX 6.1.9.7 to SP08 or AIX 7.1.4.2 to SP03 (note the earlier service packs (SP 07 or SP 02 are not impacted)

OCCURRENCE

The only changes were upgrades to the latest IBM SP patches.

upgraded from AIX 6.1.9.7 to SP08  --> SP08 has the problem.
upgraded from AIX 7.1.4.2 to SP03  --> SP03 has the problem.

 To check for AIX patch levels that are exposed to this risk, run the following command and look for any of the following:

# oslevel -s

If any of the following are listed, exposure to this problem exists:

6100-09-08
7100-03-08
7100-04-03
7200-00-03
7200-01-00
7200-01-01

 

 

SYMPTOMS

 The following ORA-600 errors have been observed. Note that not all errors are needed, and not all customers have seen all these errors.

=========================================================================================
ORA-00600: internal error code, arguments: [kkoipt:invalid aptyp], [0], [0], [], [], [], [], [], [], [], [], []
Optimizer - Maps the structures from memory
=========================================================================================
ORA-00600: internal error code, arguments: [kghssgai2], [1], [32], [], [], [], [], [], [], [], [], []
--looks to be pga related allocations
Generic memory Heap manager -we can't have both a heap and an allocation function passed in to us
=========================================================================================
ORA-00600: internal error code, arguments: [qkkAssignKey:1], [], [], [], [], [], [], [], [], [], [], []
qkkAssignKey - copy keys from source to destination key
=========================================================================================
ORA-00600: internal error code, arguments: [kclgclks_3], [454], [2431642561], [], [], [], [], [], [], [], [], []
kclgclks - CR Server request
=========================================================================================
ORA-00600: internal error code, arguments: [kkqvmRmViewFromLst1], [], [], [], [], [], [], [], [], [], [], []
View Merging - list management
=========================================================================================
ORA-00600: internal error code, arguments: [kghstack_underflow_internal_1], [0x082024000], [rpi role space], [], [], [], [], [], [], [], [], []
shared heap manager Stack segment underflow, failure to follow stack discipline.
assert no previous chunk in this segment
=========================================================================================
ORA-00600: internal error code, arguments: [qerghFetch.y], [], [], [], [], [], [], [], [], [], [], []
Implements hash aggregation for query source
=========================================================================================
ORA-00600: internal error code, arguments: [qeshQBNextLoad.1], [], [], [], [], [], [], [], [], [], [], []
Hash Table Infrastructure -get Next buffer during Load
=========================================================================================
ORA-00600: internal error code, arguments: [qkshtQBGet:1], [], [], [], [], [], [], [], [], [], [], []
gets memory pointer for a query block.
Make sure the query block pointer is not NULL
=========================================================================================
ORA-00600: internal error code, arguments: [qeshIHBuildOnPartition block missed], [], [], [], [], [], [], [], [], [], [], []
Hash Table Infrastructure
update the partition at the end.
=========================================================================================
ORA-00600: internal error code, arguments: [kghssgfr2], [1]
=========================================================================================
ORA-07445: exception encountered: core dump [PC:0x0] [SIGILL] [ADDR:0x0] [PC:0x0] [Illegal opcode]
=========================================================================================
ORA-00600 [kkogbro: no kkoaptyp]
=========================================================================================
ORA-00600: internal error code, arguments: [kewrose_1], [600]
========================================================================================
ORA-00600: internal error code, arguments: [1868], [0x000000000], [], [], [], [], [], [], [], [], [], []
Core dumps are also possible.

---------------

Redo log corruption with checksum error has also been observed.

Two known examples below:

example 1:

Alert.log messages:

ORA-00368: checksum error in redo log block
ORA-00353: log corruption near block 73804 change 8112409541614 time 12/07/2016 07:12:25
ORA-00334: archived log: '/dev/rredo13'
ORA-07445: exception encountered: core dump [pkrdi()+780] [SIGSEGV] [ADDR:0x0] [PC:0x10367B26C] [Invalid permissions for mapped


--------------- 

There have been also transient database block corruptions or control file block corruption with checksum errors in the database where a reread finds valid data.

example 2 (transient database block corruption with checksum error):

Corrupt block relative dba: 0x5a066b2f (file 360, block 420655)
Bad check value found during buffer read
Data in bad block:
type: 6 format: 2 rdba: 0x5a066b2f
last change scn: 0x00cc.6a826294 seq: 0x1 flg: 0x06
spare1: 0x0 spare2: 0x0 spare3: 0x0
consistency value in tail: 0x62940601
check value in block header: 0x9e7d
computed block checksum: 0x0           ---> 0x0 means that checksum is good when printing the error message (transient problem)
Reading datafile 'Datafile name' for corruption at rdba: 0x5a066b2f (file 360, block 420655)
Reread (file 360, block 420655) found valid data
Hex dump of (file 360, block 420655) in trace file ....
Repaired corruption at (file 360, block 420655)

 

example 3 (transient control file corruption with checksum error):

Hex dump of (file 0, block 1) in trace file ...
Corrupt block relative dba: 0x00000001 (file 0, block 1)
Bad check value found during control file header read
Data in bad block:
type: 21 format: 2 rdba: 0x00000001
last change scn: 0x0000.00000000 seq: 0x1 flg: 0x04
spare1: 0x0 spare2: 0x0 spare3: 0x0
consistency value in tail: 0x00001501
check value in block header: 0xca35
computed block checksum: 0x0                 ---> 0x0 means that checksum is good when printing the error message (transient problem)
Errors in file ..:
ORA-00202: control file: '/oracle/dbs/control_01.ctl'
Errors in file ...
ORA-00227: corrupt block detected in control file: (block 1, # blocks 1)
ORA-00202: control file: '/oracle/dbs/control_01.ctl'

 

 

WORKAROUND

The current solution is to revert back to the previous SP patches on the AIX host.

 

PATCHES

 The fix is now ready from IBM 

It can be downloaded for the above releases via:

ftp://aix.software.ibm.com/aix/ifixes/

Affected AIX Levels     Fixed In           iFix / APAR (ftp://aix.software.ibm.com/aix/ifixes/)
6100-09-08               6100-09-09      IV93840
7100-03-08               7100-03-09      IV93884
7100-04-03               7100-04-04      IV93845
7200-00-03               7200-00-04      IV93883
7200-01-01               7200-01-02      IV93885

The fix is included in the next to be released AIX Service Packs.

IBM HIPER APAR
Abstract: PROBLEMS CAN OCCUR WITH THREAD_CPUTIME AND THREAD_CPUTIME_FAST

This APAR corrects an issue with system call thread_cputime_self with floating point registers which is exposed by Oracle Database 11gR2.

PROBLEM SUMMARY:
The thread_cputime or thread_cputime_fast interfaces can
cause invalid data in the FP/VMX/VSX registers if the thread
page faults in this function

For more information see the following from IBM:

http://www-01.ibm.com/support/docview.wss?uid=isg1SSRVPOAIX71HIPER170303-1247

 

 

HISTORY

24-FEB-2017 Article has been created

28-FEB-2017 Added the transient control file corruption example with ORA-227 and added the next patch levels that are also causing this issue: 7100-03-08, 7200-00-03, 7200-01-00, 7200-01-01

02-MAR-2017 Added the AIX fix detail APAR -IV93763 and ftp site at IBM for patch downloads as well as fix for each AIX version

14-MAR-2017 Clarified some detail as to what service packs are problems.  Added link to IBM problem description.

15-MAR-2017 Expanded scope of the database versions at risk (12.1 and 12.2 are also at risk)


作者:msdnchina 发表于2017/3/24 22:10:16 原文链接
阅读:79 评论:0 查看评论

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version

$
0
0

找了很久 最后百度无意中发现有人提了一句可能和Sql关键字冲突了。。突然想到了order by ….我的天
我就把order表改了 成功解决。还是太嫩 唉

作者:su20145104009 发表于2017/3/24 23:17:41 原文链接
阅读:69 评论:0 查看评论

【NDN VANET】Data Naming in Vehicle-to-Vehicle Communications 学习笔记

$
0
0

1、 车辆通信方式:V2V (Vehicle-to-Vehicle) 和 V2R (Vehicle-to-Road side unit)。

2、 ITS——Intelligent Transportation Systems,智能传输系统

      DSRC——Dedicated Short Range Communications,专用短距离通信

      WAVE——Wireless Access in Vehicular Environments,车辆环境中的无线访问

      RSU——Road Side Unit, small static stations deployed along the roads,路边单元

3、 DSRC/WAVE运行于5.9GHz带宽;依据所在的无线频谱,传输范围为100-500m;在此范围内,车辆DSRC一跳可达10到几百辆邻居车辆;车辆行驶速度为60mph;每秒交换至少10个包,每个包3K bits。

4、 道路上行驶的车辆可以生成并存储的信息包括:数据产生的时间戳,车辆的位置信息、如经度纬度,车辆的行驶速度。

5、 我们假定每个车辆嵌入一个NDN转发引擎,用来管理一个或多个网络接口,比如DSRC/WAVE和WiFi接口。车辆头单元中的行驶应用程序指导NDN模块获取期望的信息,NDN模块在ad-hoc模式下用WiFi或者用DSRC/WAVE通过一跳广播向其他车辆发出兴趣包,而不需要任何网络基础设施支持。我们也可以运行NDN模块来从路边单元获取信息。

6、 在V2V和V2R通信中,存在3种角色:数据发布者、数据骡、数据消费者。

      (1)数据发布者生产数据并将数据存储在缓存中;

      (2)数据骡收集不是自己产生的来自其他车辆的数据,并在接收到请求后向发送请求的车辆提供数据。数据骡不仅能够帮助向许多不同位置的车辆传递交通信息,而且在最初发布者离开网络后,仍然能够保持信息可达;

      (3)数据消费者发送兴趣包来从发布者和数据骡获取数据。

7、 V2V通信中的数据名字结构格式如下:

       /traffic/geolocation/timestamp/data type/nonce

      (1)traffic代表应用程序ID。

      (2)geolocation代表地理位置信息,格式为road ID/direction/section number。road ID为道路名字,加上link ID,保证在不同的城市和国家,道路名字的唯一性;direction代表行驶方向;section number代表高速公路的出口号,一对section number代表高速公路的一段。

      (3)timestamp代表数据的UNIX时间戳,使用一对时间戳来代表一段时间。当消费者接收到数据包,应用程序模块可以转换时间戳格式到人类可读的格式。

      (4)data type代表数据的类型信息,如车辆行驶速度等。

      (5)随机数nonce由发布者生成,前面的数据不同的生产者生成的数据可能相同,nonce用以区别不同生产者生成的数据。

      示例1:/traffic/Highway 101/north/{400,410}/{1323201600,1323205200}/speed/19375887

                  代表车辆于2011年12月6号12:00-13:00向北行驶在101号高速公路400-410区域间,速度为19375887(单位未知)。

      示例2:要请求405-415区域内的信息需要发送两个兴趣包:

                   /traffic/Highway 101/north/{400,410}/{1323201600,1323205200}/speed

                   /traffic/Highway 101/north/{410,420}/{1323201600,1323205200}/speed

      示例3:要请求特定区域在任意时间生成的数据,而不考虑数据类型,兴趣包如下:

                   /traffic/Highway 101/north/{400,410}/

      示例4:要请求highway 101上的所有交通信息,而不考虑区域和时间,兴趣包如下:

                   /traffic/Highway 101/

8、对于一个兴趣包的回复包可能有多片数据,如果这多片数据不能放在一个数据包中回复,则回复方案有以下两种:

      (1)在数据包中列出可用数据片的名字,如果消费者需要哪一片,再发兴趣包去具体请求;

      (2)随机选择匹配的数据片,假如共有10个数据片,一个车辆发送的数据包只能装得下其中4片,则在这10片中随机选择4片,如果有多辆车都能满足请求兴趣包,则每辆车都可以选择不同的数据片发送。


作者:gongxifacai_believe 发表于2017/3/24 23:45:30 原文链接
阅读:62 评论:0 查看评论

Android性能优化 内存优化 避免OOM

$
0
0

转载请注明出处:http://blog.csdn.net/smartbetter/article/details/65442706

怎样才能写出高性能的应用程序,如何避免程序出现OOM,或者当程序内存占用过高的时候该怎么样去排查。这些问题对于一个优秀的应用程序应当处理得恰到好处。为此,我也阅读了不少Android官方给出的性能优化建议。本篇将系统的从 Android的内存管理方式 到 App内存优化方法,最后到OOM问题优化,系统的讲解内存优化的一些方案、见解,帮助大家能够写出更加出色的应用程序,避免OOM。

建议阅读的官方文档:https://developer.android.google.cn/topic/performance/memory.html

1.Android的内存管理方式

我们知道Android系统是多任务系统,通过分时复用的方式,多个应用可以同时在一个手机上运行。

我们打开终端,输入:

$ adb shell     // 进入安卓底层Linux系统的命令
$ ps            // 查看系统里面进程的命令

ps

USER:用户, PID:进程id, PPID:父进程id, VSIZE:进程虚拟地址空间大小, RSS:进程正在使用的物理内存大小, WCHAN:进程处于休眠状态时在内核中的地址, PC:program counter, NAME:进程名称.

$ dumpsys meminfo com.android.bluetooth   // 查看指定进程相关信息

dumpsys meminfo

1.Android系统内存分配与回收方式

一个App通常就是一个进程对应一个虚拟机。
GC只在Heap剩余空间不够时才触发垃圾回收,而且GC触发时,所有的线程都会被暂停(如果GC时间比较长,还有可能出现内存抖动的现象)。

2.App内存限制机制

每个App分配的最大内存限制,随不同设备而不同。系统分配的大小肯定是够用的,如果你的App出现OOM,往往是你的App优化做的不是很好。
其中吃内存比较厉害就是图片了。

Android上App的运行是有内存限制的,OOM导致App崩溃。

我们可以通过代码的方式查看一下手机的内存限制和最大内存限制:

ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
Log.i("JAVA", "内存限制:" + manager.getMemoryClass() + "M");
Log.i("JAVA", "最大内存限制:" + manager.getLargeMemoryClass() + "M");

3.切换应用时后台App清理机制

多个App切换的时候使用的是 LRU Cache(其中是使用LRU算法进行清理排序的。LRU算法:最近使用的排在最前面,最少可能的被清理掉)。
当具体清理的时候,系统还会发出 onTrimMemory() 的回调,随着系统内存有变化的时候发出回调给各个应用,通知系统的内存情况,然后我们的App可以做相应处理,把App中不用的内存尽快清理掉,这样你的App的占用就相对小一点,系统在查看后台App的时候发现你这个App内存占用比较少,那么在清理的时候就会小一点。

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
    @Override
    public void onTrimMemory(int level) {
        super.onTrimMemory(level);
        Log.i("JAVA", "level:" + level);
    }
}

4.监控内存的几种方法

我们可以通过代码的方式监控内存:

Runtime runtime = Runtime.getRuntime();
Log.i("JAVA", "总内存:" + runtime.totalMemory() * 1.0f/(1024*1024) + "M");
Log.i("JAVA", "空闲内存:" + runtime.freeMemory() * 1.0f/(1024*1024) + "M");
Log.i("JAVA", "可申请最大内存:" + runtime.maxMemory() * 1.0f/(1024*1024) + "M");

我们还可以通过 Android Studio 的 Android Monitors工具 方便的监控内存:

Android Monitors

除此之外,Android Studio还提供了Android Device Monitor工具,可用于整体的监控内存:

Android Device Monitor

我们先选住应用程序,再点击 Heap 按钮:

Heap

然后点击 Cause GC 按钮:

Cause GC

此时Android Device Monitor就为我们展示了当前整体的内存情况:

Cause GC Updates

其中我们主要看的就是 data object 和 class object 这两个,如果不停的运行,这两个也不停的变大,那么很有可能内存泄漏。

2.App内存优化方法

1.数据结构优化

1)频繁字符串拼接用 StringBuilder,字符串通过”+”的方式拼接,会产生中间字符串内存块;
2)ArrayMap、SparseArray 替换 HashMap,内存使用更少,数据量大了效率更高;
3)内存抖动(监控内存时发现内存情况呈现 锯齿形),一般是代码设计的时候变量使用不当引起的;

内存抖动

4)再小的Class也要耗费 0.5KB;
5)HashMap每一个entry需要额外占用 32B。

2.对象复用

1)复用系统自带的资源;
2)ListView/GridView 的 ConvertView 复用;
3)避免在 onDraw方法 里面执行对象的创建,把对象创建放在外面。

3.避免内存泄漏

内存泄漏,由于代码有瑕疵,导致这块内存发生内存泄漏,虽然是停止不用了,但是依然被其他东西引用着,使得GC没法对它回收。
1)内存泄漏会导致剩余可用 Heap 越来越少,频繁触发GC,尤其是Activity泄漏;
2)引用上下文选用 Application Context 而不是 Activity Context;
3)注意 Cursor对象 及时关闭。

3.OOM问题优化

1.OOM问题分析

OOM的绝大部分场景发生在图片。

2.强引用、软引用

强引用:GC绝不会回收它,JVM宁愿抛出OutOfMemoryError错误,一般new出来的对象都是强引用。

// 如果是在Activity中创建则生命周期同Activity,如果在方法中创建则生命周期同方法。
// String str; 时就已经创建,new是进行实例化的(分配对象内存,并将该内存初始化为缺省值)。
String str = String.valueOf(Math.random());

软引用:当内存空间不足,GC会回收这些对象的内存,使用软引用构建敏感数据的缓存。

// 生命周期同强引用,只是当内存空间不足,GC会回收这些对象的内存。运行过程中可能会出现softref为null的情况。
SoftReference<String> softref = new SoftReference<String>(String.valueOf(Math.random()));

弱引用:在GC线程扫描内存区域的过程中,不管当前内存空间足够与否,都会回收内存,使用弱引用 构建非敏感数据的缓存。

虚引用:在任何时候都可能被垃圾回收,虚引用与软引用和弱引用的一个区别在于:虚引用必须和引用队列联合使用,虚引用主要用来跟踪对象 被垃圾回收的活动。

3.Activity onTrimMemory()回调方法

@Override
public void onTrimMemory(int level) {
    super.onTrimMemory(level);
}

1)UI 不可见时释放资源:

在 onStop 中关闭网络连接、注销广播接收器、释放传感器等资源;

在 onTrimMemory() 回调方法中监听 TRIM_MEMORY_UI_HIDDEN 级别的信号,此时可在 Activity 中释放 UI 使用的资源,大符减少应用占用的内存,从而避免被系统清除出内存。

2)内存紧张时释放资源:

运行中的程序,如果内存紧张,会在 onTrimMemory() 回调方法中接收到以下级别的信号:
TRIM_MEMORY_RUNNING_MODERATE:系统可用内存较低,正在杀掉LRU缓存中的进程。你的进程正在运行,没有被杀掉的危险。
TRIM_MEMORY_RUNNING_LOW:系统可用内存更加紧张,程序虽然没有被杀死的危险,但是应该尽量释放一些资源,以提升系统的性能。
TRIM_MEMORY_RUNNING_CRITICAL:系统内存极度紧张,而LRU缓存中的大部分进程已被杀死,如果仍然无法获得足够的资源的话,接下来会清理掉LRU中的所有进程,并且开始杀死一些系统通常会保留的进程,比如后台运行的服务等。

当程序未在运行,保留在 LRU 缓存中时, onTrimMemory() 回调方法中接收到以下级别的信号:
TRIM_MEMORY_BACKGROUND:系统可用内存低,而你的程序处在LRU的顶端,不会被杀死,但是此时应释放一些程序再次打开时比较容易恢复的 UI 资源。
TRIM_MEMORY_MODERATE:系统可用内存低,程序处于LRU的中部位置,如果内存状态得不到缓解,程序会有被杀死的可能。
TRIM_MEMORY_COMPLETE:系统可用内存低,你的程序处于LRU尾部,如果系统仍然无法回收足够的内存资源,你的程序将首先被杀死,此时应释放无助于恢复程序状态的所有资源。

注意:该 API 在版本 14 中加入,旧版本的onLowMemory() 方法,大致相当于 onTrimMemory(int level) 中接收到 TRIM_MEMORY_COMPLETE 级别的信号。

尽管系统主要按照 LRU 中顺序来杀进程,不过系统也会考虑程序占用的内存多少,那些占用内存高的进程有更高的可能性会被首先杀死。

4.优化OOM问题的方案

1)注意临时 Bitmap 对象的及时回收
2)避免 Bitmap 的浪费
3)try catch 某些大内存分配的操作
4)加载 Bitmap(安卓手机上一般一个像素用4个字节来表示(ARGB)):缩放比例、解码格式、局部加载、软引用

作者:smartbetter 发表于2017/3/25 0:19:25 原文链接
阅读:156 评论:0 查看评论

spark.mllib源码阅读-分类算法1-LogisticRegression

$
0
0

LogisticRegression解释:

传统的线性回归模型z(x)=wx+b,其输出为负无穷至正无穷的区间,如果输出值为一个事件发生的概率,那么就要求输出区间为[0,1],传统的一些线性回归模型就不能work了,一个很简单的想法就是在z(x)线性输出的基础上增加一个从01光滑的单调递增的函数。同时对于很多事件来说,在事件确定发生的概率区间内 条件的微弱变化几乎不影响事件的发生,而在事件发生与不发生的交界区间 条件的微弱变化对事件发生的概率产生了极大的影响。因此,我们就需要一个函数g(z),其在z的两个相当大的区间内其输出几乎不随z的变化而变化,而在一个小区间内变化又很大,同时整体的变化的平滑的。sigmod函数即很好的符合上述的要求:


sigmoid函数

这样,输入到概率输出的映射用函数表示为


称之为Logistic函数。

事件发生和不发生的概率表示为:


上式可简化为:


通常使用极大似然来进行Logistic回归的参数估计,在m个样本的训练集上,其似然函数为:


对数似然函数为:


要最大化对数似然函数,可以参照梯度下降法的方法,对对数似然函数求各个参数的偏导数:


由于是求极大值的最优化问题,参数更新的方向是沿着梯度的正方向:,参数更新的规则为:


以上LogisticRegression函数由来是个人从形象上推测的。LogisticRegression函数严格的数学推导和后面的参数求解过程,可以参阅斯坦福大学的课件


LogisticRegression回归实现:

讲完了理论,下面来看看Spark具体的LogisticRegression的实现。LogisticRegressionSpark实现包括LogisticRegression模型的定义和参数的求解两部分。

LogisticRegressionModel

Logistic回归分类模型实现的分类器,包括分类和多分类问题.Logistic回归分类模型仍然是一个广义的线性回归问题,因此使用了LogisticRegressionModel作为它的基类。

在二分类问题上,Logistic回归输出值是一个0-1区间的实数值,通过与阀值threshold比较来判断其类别。在多分类问题上,Logistic回归输出值是一个0-1区间的实数值序列,通过选取最大的输出值,来选取最优的分类类别。

override protected def predictPoint(
    dataMatrix: Vector,
    weightMatrix: Vector,
    intercept: Double) = {
  require(dataMatrix.size == numFeatures)
  // If dataMatrix and weightMatrix have the same dimension, it's binary logistic regression.
  if (numClasses == 2) {
    val margin = dot(weightMatrix, dataMatrix) + intercept
    val score = 1.0 / (1.0 + math.exp(-margin))
    threshold match {
      case Some(t) => if (score > t) 1.0 else 0.0
      case None => score
    }
  } else {
    //多分类问题,weightsArray存储的是每个分类器的权重和偏置
    //最后取输出概率P最大的类别,这里并没有显式求出P值,而是计算并比较的g(x)值
    var bestClass = 0
    var maxMargin = 0.0
    val withBias = dataMatrix.size + 1 == dataWithBiasSize
    (0 until numClasses - 1).foreach { i =>
      var margin = 0.0
      dataMatrix.foreachActive { (index, value) =>
        if (value != 0.0) margin += value * weightsArray((i * dataWithBiasSize) + index)
      }
      if (withBias) {
        margin += weightsArray((i * dataWithBiasSize) + dataMatrix.size)
      }
      if (margin > maxMargin) {
        maxMargin = margin
        bestClass = i + 1
      }
    }
    bestClass.toDouble
  }
}

LogisticRegression参数求解

SparkLogisticRegression实现了两类优化求解算法,LogisticRegressionWithSGDLogisticRegressionWithLBFGS。两类算法都使用的Logistic损失函数LogisticGradient L2正则化SquaredL2UpdaterLogisticRegressionWithSGDspark.mllib源码阅读-回归算法1-LinearRegression中介绍的回归方法训练模型思路一直,均是调用父类GeneralizedLinearAlgorithmrun方法来实现模型训练。

LogisticRegressionWithLBFGS类优化求解器采用的LBFGS(在spark.mllib源码阅读-优化算法3-Optimizer进行了相关的介绍),同时覆写了父类GeneralizedLinearAlgorithm的run方法。

if (numOfLinearPredictor == 1) {
  def runWithMlLogisticRegression(elasticNetParam: Double) = {
    // Prepare the ml LogisticRegression based on our settings
    //调用了另外一个ML包的LogisticRegression实现,该实现只能处理二分类问题
    val lr = new org.apache.spark.ml.classification.LogisticRegression()
    lr.setRegParam(optimizer.getRegParam())
    lr.setElasticNetParam(elasticNetParam)
    lr.setStandardization(useFeatureScaling)
    if (userSuppliedWeights) {
      val uid = Identifiable.randomUID("logreg-static")
      lr.setInitialModel(new org.apache.spark.ml.classification.LogisticRegressionModel(uid,
        new DenseMatrix(1, initialWeights.size, initialWeights.toArray),
        Vectors.dense(1.0).asML, 2, false))
    }
    lr.setFitIntercept(addIntercept)
    lr.setMaxIter(optimizer.getNumIterations())
    lr.setTol(optimizer.getConvergenceTol())
    // Convert our input into a DataFrame
    val spark = SparkSession.builder().sparkContext(input.context).getOrCreate()
    val df = spark.createDataFrame(input.map(_.asML))
    // Determine if we should cache the DF
    val handlePersistence = input.getStorageLevel == StorageLevel.NONE
    // Train our model
    val mlLogisticRegressionModel = lr.train(df, handlePersistence)
    // convert the model
    val weights = Vectors.dense(mlLogisticRegressionModel.coefficients.toArray)
    createModel(weights, mlLogisticRegressionModel.intercept)
  }
  optimizer.getUpdater() match {
    case x: SquaredL2Updater => runWithMlLogisticRegression(0.0)
    case x: L1Updater => runWithMlLogisticRegression(1.0)
    case _ => super.run(input, initialWeights)
  }
} else {
  //这里调用了父类GeneralizedLinearAlgorithm的run进行模型训练
  super.run(input, initialWeights)
}

二分类问题调用的是org.apache.spark.ml.classification.LogisticRegression(),这个是在Spark1.2后期版本加入的Logistic回归模型。

这里就有个疑问了,ml包下的Logistic回归模型和mllib下的Logistic回归模型有什么不同。

粗略看了二者的源码,在二分类问题上,不同点主要是ml.LogisticRegression加入了elastic net这样一个L1正则化和L2正则化这样一个调制因子。在多分类问题上,ml.LogisticRegression主要采用的是softmax函数来进行预测分类,K个类别的概率总和等于1。mllib.LogisticRegression使用的是OneVsAll就是把当前某一类看成一类,其他所有类别看作一类,这样有成了二分类的问题了,假如有k个类别,选取lable=0作为“pivot”类,则构建k-1个分类器:

     classifier1:lable=0 VS lable=1

     classifier2:lable=0 VS lable=2

    classifierk-1:lable=0 VS lable=k-1

最后输出K-1个分类器中输出概率最大的那个类。并且这个概率是与Lable0事件相比的发生概率。OneVsAll假设了classifierilable=0lable=i之间存在了关联性。

这就需要选取一个合适的“pivot”类了。

由于Logistic回归用于预测事件发生与否,如预测一个点击行为:不点击、点击A、点击B、点击C等,用户可能发生点击A,也可能发生点击AB,重点是要找到最有可能发生的点击行为。那么可以使用lable="不点击"作为“pivot”类。

而如果选取lable="点击A"作为“pivot”类,就会出现问题了。

回过头来看ml.LogisticRegression,其是找到K个类别中输出概率最大的类,并且各类别的输出概率之和为1,同时,各类别发生与否是相互独立的。



作者:zbc1090549839 发表于2017/3/25 15:20:47 原文链接
阅读:132 评论:0 查看评论

CCF201703-1 分蛋糕

$
0
0

试题编号:    201703-1
试题名称:    分蛋糕
时间限制:    1.0s
内存限制:    256.0MB
问题描述:    
问题描述
  小明今天生日,他有n块蛋糕要分给朋友们吃,这n块蛋糕(编号为1到n)的重量分别为a1, a2, …, an。小明想分给每个朋友至少重量为k的蛋糕。小明的朋友们已经排好队准备领蛋糕,对于每个朋友,小明总是先将自己手中编号最小的蛋糕分给他,当这个朋友所分得蛋糕的重量不到k时,再继续将剩下的蛋糕中编号最小的给他,直到小明的蛋糕分完或者这个朋友分到的蛋糕的总重量大于等于k。
  请问当小明的蛋糕分完时,总共有多少个朋友分到了蛋糕。
输入格式
  输入的第一行包含了两个整数n, k,意义如上所述。
  第二行包含n个正整数,依次表示a1, a2, …, an
输出格式
  输出一个整数,表示有多少个朋友分到了蛋糕。
样例输入
6 9
2 6 5 6 3 5
样例输出
3
样例说明
  第一个朋友分到了前3块蛋糕,第二个朋友分到了第4、5块蛋糕,第三个朋友分到了最后一块蛋糕。
评测用例规模与约定
  对于所有评测用例,1 ≤ n ≤ 1000,1 ≤ k ≤ 10000,1 ≤ ai ≤ 1000。


问题链接:无。

问题描述(参见上文)。

问题分析:(略)。

程序说明:(略)。

提交后得100分的C++语言程序如下:

/* CCF201703-1 分蛋糕 */

#include <iostream>

using namespace std;

int main()
{
    int n, k, count=0, val, sub=0;

    cin >> n >> k;
    for(int i=1; i<=n; i++) {
        cin >> val;

        if((sub += val) >= k) {
            count++;
            sub = 0;
        }
    }
    if(sub > 0)
        count++;

    cout << count << endl;

    return 0;
}




作者:tigerisland45 发表于2017/3/25 15:48:11 原文链接
阅读:141 评论:0 查看评论

Recycleview上拉刷新_下拉加载_侧滑删除加强篇

$
0
0

总有那么几个二比产品,让你上拉刷新下拉加载之后,又想让你可以侧滑删除,我想静静.
产品狗虽然可恨,可是我们还是得乖乖的去实现,没办法,谁让我们是打工的,加油骚年们.

看下我们的效果


这里写图片描述

首先定义我们最重要的一个侧滑处理类,使用ViewDragHelper来处理的.不懂的可以看下弘扬大神的博客


Android ViewDragHelper完全解析 自定义ViewGroup神器

package yuan.kuo.yu.view;

import android.content.Context;
import android.graphics.Rect;
import android.support.v4.widget.ViewDragHelper;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.FrameLayout;

/**
 * Created by yukuoyuan on 2017/3/10.
 * 这是一个可以侧滑菜单的条目的父布局
 */

public class SwipeRecycleviewItemLayout extends FrameLayout {


    private View menu;
    private View content;
    private final ViewDragHelper dragHelper;
    private boolean isOpen;
    private int currentState;

    /**
     * 构造方法
     *
     * @param context 上下文
     * @param attrs   属性集合
     */
    public SwipeRecycleviewItemLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        /**
         * 初始化我们自定义处理触摸事件的方法
         */
        dragHelper = ViewDragHelper.create(this, rightCallback);
    }

    private ViewDragHelper.Callback rightCallback = new ViewDragHelper.Callback() {

        // 触摸到View的时候就会回调这个方法。
        // return true表示抓取这个View。
        @Override
        public boolean tryCaptureView(View child, int pointerId) {
            return content == child;
        }

        /**
         * 重新处理子view的左侧
         * @param child
         * @param left
         * @param dx
         * @return
         */
        @Override
        public int clampViewPositionHorizontal(View child, int left, int dx) {
            return left > 0 ? 0 : left < -menu.getWidth() ? -menu.getWidth() : left;
        }

        /**
         * 当手指释放的时候回调
         * @param releasedChild
         * @param xvel
         * @param yvel
         */
        @Override
        public void onViewReleased(View releasedChild, float xvel, float yvel) {

            // x轴移动速度大于菜单一半,或者已经移动到菜单的一般之后,展开菜单
            if (isOpen) {
                if (xvel > menu.getWidth() || -content.getLeft() < menu.getWidth() / 2) {
                    close();
                } else {
                    open();
                }
            } else {
                if (-xvel > menu.getWidth() || -content.getLeft() > menu.getWidth() / 2) {
                    open();
                } else {
                    close();
                }
            }
        }

        /**
         * view 横向移动的范围
         * @param child
         * @return
         */
        @Override
        public int getViewHorizontalDragRange(View child) {
            return 1;
        }

        /**
         *view纵向移动的范围
         * @param child
         * @return
         */
        @Override
        public int getViewVerticalDragRange(View child) {
            return 1;
        }

        /**
         * 当ViewDragHelper状态发生变化的时候调用(IDLE,DRAGGING,SETTING[自动滚动时])
         * @param state
         */
        @Override
        public void onViewDragStateChanged(int state) {
            super.onViewDragStateChanged(state);
            currentState = state;
        }
    };

    /**
     * 处理触摸事件(交给draghelper去处理)
     *
     * @param event
     * @return
     */
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        dragHelper.processTouchEvent(event);
        return true;
    }

    /**
     * 处理触摸事件
     *
     * @param ev
     * @return
     */
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return dragHelper.shouldInterceptTouchEvent(ev);
    }

    /**
     * 获取当前的状态
     *
     * @return
     */
    public int getState() {
        return currentState;
    }

    private Rect outRect = new Rect();

    public Rect getMenuRect() {
        menu.getHitRect(outRect);
        return outRect;
    }

    /**
     * 当绘制完毕调用的方法
     */
    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        menu = getChildAt(0);
        content = getChildAt(1);
    }

    /**
     * 这是一个关闭菜单的方法
     */
    public void close() {
        dragHelper.smoothSlideViewTo(content, 0, 0);
        isOpen = false;
        invalidate();
    }

    /**
     * 这是一个打开菜单的方法
     */
    public void open() {
        dragHelper.smoothSlideViewTo(content, -menu.getWidth(), 0);
        isOpen = true;
        invalidate();
    }

    /**
     * 计算滚动事件
     */
    @Override
    public void computeScroll() {
        super.computeScroll();
        if (dragHelper.continueSettling(true)) {
            invalidate();
        }
    }

    /**
     * 设置点击事件
     *
     * @param l
     */
    @Override
    public void setOnClickListener(OnClickListener l) {
        content.setOnClickListener(l);
    }

    public boolean isOpen() {
        return this.isOpen;
    }
}

然后定义我们的两个布局

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:background="?android:colorBackground"
    android:layout_height="60dp">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TextView
            android:id="@+id/item_content"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="#49ff0000"
            android:gravity="center"
            android:text="小雨来了"
            android:textColor="@android:color/white"
            android:textSize="16sp" />
    </RelativeLayout>
</FrameLayout>

带侧滑删除的类型

<?xml version="1.0" encoding="utf-8"?>
<yuan.kuo.yu.view.SwipeRecycleviewItemLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="60dp"
    android:background="?android:colorBackground">

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="right"
        android:orientation="horizontal">

        <TextView
            android:id="@+id/delete"
            android:layout_width="60dp"
            android:layout_height="match_parent"
            android:background="#FF6A6A"
            android:gravity="center"
            android:text="删除"
            android:textColor="#fff"
            android:textSize="18sp" />

        <TextView
            android:id="@+id/ok"
            android:layout_width="60dp"
            android:layout_height="match_parent"
            android:background="#e0e0e0"
            android:gravity="center"
            android:text="确定"
            android:textColor="#fff"
            android:textSize="16sp" />
    </LinearLayout>

    <include layout="@layout/item_content" />

</yuan.kuo.yu.view.SwipeRecycleviewItemLayout>

接下来看下我们的适配器

package cn.yu.yuan;

import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by yukuo on 2016/4/30.
 */
public class DemoSwipeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    private List<SwipeDate> list = new ArrayList<>();

    public DemoSwipeAdapter(List<SwipeDate> list) {
        this.list = list;
    }

    public void addReFreshData() {
        notifyDataSetChanged();
    }

    public void addRLoadMOreData() {
        notifyDataSetChanged();
    }

    /**
     * 删除一个数据的方法
     *
     * @param position 索引
     */
    // TODO 一定要按照这个方式写,不然会crash,希望你有更好的解决方案
    public void removeData(int position) {
        list.remove(position);
        notifyItemRemoved(position + 1);
        if (position != list.size()) {
            if (position == 0) {
                notifyDataSetChanged();
            } else if (position == (list.size() - 1)) {
                notifyItemRangeChanged(position, 0);
            } else {
                notifyItemRangeChanged(position, list.size() - position);
            }
        }
    }

    @Override
    public int getItemViewType(int position) {
        return list.get(position).type;
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view;
        if (viewType == 1) {
            view = View.inflate(parent.getContext(), R.layout.item_swipe_menu, null);
            return new MySwipeMenuHolder(view);
        } else {
            view = View.inflate(parent.getContext(), R.layout.item_content, null);
            return new MyHolder(view);
        }
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
        if (holder instanceof MyHolder) {
            MyHolder myHolder = (MyHolder) holder;
            myHolder.item_content.setText(list.get(position).name);
        } else if (holder instanceof MySwipeMenuHolder) {
            MySwipeMenuHolder myHolder = (MySwipeMenuHolder) holder;
            myHolder.item_content.setText(list.get(position).name + "######" + position);
            myHolder.item_content.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Toast.makeText(v.getContext(), list.get(position).name, Toast.LENGTH_SHORT).show();
                }
            });
            myHolder.delete.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    removeData(position);
                }
            });
        }
    }

    @Override
    public int getItemCount() {
        return list.size();
    }

    class MyHolder extends RecyclerView.ViewHolder {

        private final TextView item_content;

        public MyHolder(View itemView) {
            super(itemView);
            item_content = (TextView) itemView.findViewById(R.id.item_content);
        }
    }

    class MySwipeMenuHolder extends RecyclerView.ViewHolder {

        private final TextView delete;
        private final TextView ok;
        private final TextView item_content;

        public MySwipeMenuHolder(View itemView) {
            super(itemView);
            item_content = (TextView) itemView.findViewById(R.id.item_content);

            delete = (TextView) itemView.findViewById(R.id.delete);
            ok = (TextView) itemView.findViewById(R.id.ok);
        }
    }
}

ok,到此我们自定义的侧滑删除功能就实现了,其实并没有太多难点,主要是在viewDragHelper这个类里边

Demo地址
欢迎Fork和Star,如果有问题,记得留言反馈给我啊.谢谢

作者:EaskShark 发表于2017/3/25 16:23:37 原文链接
阅读:231 评论:0 查看评论

图像拼接(十三):OpenCV拼接多幅图像(以中间图像为参考)

$
0
0

图像拼接(七):OpenCV单应变换模型拼接多幅图像 这篇博客中实现了用单应变换模型拼接多幅图像,图像拼接使用的OpenCV库函数warpPerspective()

因为这个函数只有在右侧图像变换到左侧图像时才能完整显示,所以拼接过程选择了以最左侧图像为参考帧。由于累加误差,最右侧的图像出现严重的变形。如下所示:

这里写图片描述

在这篇博客中,我们以中间幅图像为参考图像,实现多幅拼接。图像数量为4张,从左到右分别为img4img3img2img1。以左侧第2幅图像,即img3为参考图像。

从右到左,img2img1的单应变形仍可直接使用warpPerspective(),那么从左到右,img4img3怎么办呢?

解决的办法是对img3添加一个向右距离为img3.width的平移变换。这样变形后的img4即可显示在画布中了。

这个平移变换矩阵为:

Tx=100010img3.cols01

img3 点坐标设为Ximg4点坐标设为X,则他们之间的关系为:

TxX=TxH43X

所以img4img3变换后的图像如下,注意img3的原点向右位移至中间。在之后的拼接中要考虑这一点。

img4->img3
这里写图片描述

其它图像之间的变换:

img2->img3
这里写图片描述

img1->img3
这里写图片描述

所有的4幅图像的拼接结果为:

这里写图片描述

整体观感相比图像拼接(七):OpenCV单应变换模型拼接多幅图像的结果提升不少,最右侧图像变形失真减轻。

代码

#include"Homography.h"

int main()
{
    //从右向左升序
    string imgPath1 = "trees_003.jpg";
    string imgPath2 = "trees_002.jpg";
    string imgPath3 = "trees_001.jpg";
    string imgPath4 = "trees_000.jpg";

    Mat img1 = imread(imgPath1, CV_LOAD_IMAGE_GRAYSCALE);
    Mat img2 = imread(imgPath2, CV_LOAD_IMAGE_GRAYSCALE);
    Mat img3 = imread(imgPath3, CV_LOAD_IMAGE_GRAYSCALE);
    Mat img4 = imread(imgPath4, CV_LOAD_IMAGE_GRAYSCALE);

    Mat img1_color = imread(imgPath1, CV_LOAD_IMAGE_COLOR);
    Mat img2_color = imread(imgPath2, CV_LOAD_IMAGE_COLOR);
    Mat img3_color = imread(imgPath3, CV_LOAD_IMAGE_COLOR);
    Mat img4_color = imread(imgPath4, CV_LOAD_IMAGE_COLOR);

    Homography homo12(img1, img2);
    Homography homo23(img2, img3);
    Homography homo34(img3, img4);

    Mat h12 = homo12.getHomography();
    Mat h23 = homo23.getHomography();
    Mat h34 = homo34.getHomography();

    /*homo12.drawMatches();
    homo23.drawMatches();
    homo34.drawMatches();*/

    //以从左至右第2幅图像为参考,即img3
    Mat h13 = h23*h12;
    Mat h43 = h34.inv(DECOMP_LU);

    double scale_h13 = h13.at<double>(2, 2);
    h13 = h13 / scale_h13;
    double scale_h43 = h43.at<double>(2, 2);
    h43 = h43 / scale_h43;

    Mat warp1;
    warpPerspective(img1_color, warp1, h13, Size(img3.cols * 4, img3.rows));
    Mat warp2;
    warpPerspective(img2_color, warp2, h23, Size(img3.cols * 4, img3.rows));
    Mat warp4;
    Mat Tx = (Mat_<double>(3, 3) << 1, 0, img3.cols, 0, 1, 0, 0, 0, 1);
    warpPerspective(img4_color, warp4, Tx*h43, Size(img3.cols * 2, img3.rows));

    imshow("warp1", warp1);
    imshow("warp2", warp2);
    imshow("warp4", warp4);

    imwrite("warp1.jpg", warp1);
    imwrite("warp2.jpg", warp2);
    imwrite("warp4.jpg", warp4);

    int d = img3.cols * 2 / 5;
    int x2 = h23.at<double>(0, 2) + d;
    int x1 = x2 + h12.at<double>(0, 2);

    Mat canvas(img3.rows, img3.cols * 4, CV_8UC3);
    img3_color.copyTo(canvas(Range::all(), Range(img3.cols, img3.cols*2)));
    warp2(Range::all(), Range(x2, x1)).copyTo(canvas(Range::all(), Range(x2 + img3.cols, x1 + img3.cols)));
    warp1(Range::all(), Range(x1, x1+img3.cols)).copyTo(canvas(Range::all(), Range(x1 + img3.cols, x1+img3.cols*2)));
    warp4(Range::all(), Range(0, img3.cols)).copyTo(canvas(Range::all(), Range(0, img3.cols)));

    canvas(Range::all(), Range(x1 + img3.cols * 2, img3.cols * 4)) = Scalar::all(0);

    imwrite("canvas.jpg", canvas);
    imshow("canvas", canvas);

    waitKey(0);
    return 0;
}
作者:czl389 发表于2017/3/25 16:48:59 原文链接
阅读:103 评论:0 查看评论
Viewing all 35570 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>