[转载]用代理方式实现android系统抓包 - 数据分析点滴 - 博客频道 - CSDN.NET

mikel阅读(1096)

[转载]用代理方式实现android系统抓包 – 数据分析点滴 – 博客频道 – CSDN.NET.

调试Android应用的网络交互时,常常希望看到网络包的交互过程。而在破解app时也经常希望看到网络交互过程的抓包。之前的思路一直是在手机 上安装抓包软件,这种方式实时性不好而且分析能力有限。有天看到测试组的MM用一个简洁的方式解决的这个问题,很巧妙,特记录下分享。

1 设置手机上的代理到pc电脑的端口8888

可以再系统中设置。有个软件是autoproxy可以设置多个代理的切换,很好用(前提是你有su权限)

2 在pc安装代理抓包一体的fiddle

fiddle是一款作为代理并能显示经过代理的网络包的软件,很实用。安装好以后自动监听8888端口。默认设置只是作为本地的代理,需要在tools/fiddle option/connection里面允许远端的机器访问该代理。设置成功后重启fiddle。

3. 在手机上开启代理后访问,就可以在fiddle上显示出来了。

ps:调试可用性时,可以直接用http请求你的代理端口,这是一个echo服务,会有一些相应,方便的确定手机到代理的网络是不是有问题。

[转载]Android 使用ContentProvider扫描手机中的图片,仿微信显示本地图片效果 - Mobile Internet developer - 博客频道 - CSDN.NET

mikel阅读(951)

[转载]Android 使用ContentProvider扫描手机中的图片,仿微信显示本地图片效果 – Mobile Internet developer – 博客频道 – CSDN.NET.

转载请注明本文出自xiaanming的博客(http://blog.csdn.net/xiaanming/article/details/18730223),请尊重他人的辛勤劳动成果,谢谢!

写 这篇文章之前,先简单说几句,首先是先恭喜下自己获得了2013年的博客之星称号,很意外也很开心,自己是从2013年开始写博客,那时候也不知道怎么 写,我从小就不喜欢写日记,作文什么的,所以刚开始都是贴代码,也没有人看,后面慢慢的,写的文章被推荐博客首页和CSDN首页(这里也要小小的感谢下小 编MM),访问量逐渐的多了起来,有更多的人看我的文章,这也使自己有了继续写文章的动力,也希望我写的东西对大家有点帮助吧,在2014年我会继续在 CSDN上面写博客,然后是感谢博客之星给我投票支持我的朋友们,谢谢你们支持我的每一票,最后就是2014春节马上就到了,提前祝福大家新年快乐,工作 顺利,事事顺心!

回到主题,之前群里面有朋友问我,有没有关于本地图片选择的Demo,类似微信的效果,他说网上没有这方面的Demo,问 我能不能写一篇关于这个效果的Demo,于是我研究了下微信的本地图片选择的Demo,自己仿照的写了下分享给大家,希望对以后有这样子需求的朋友有一点 帮助吧,主要使用的是ContentProvider扫描手机中的图片,并用GridView将图片显示出来,关于GridView和ListView显 示图片的问题,一直是一个很头疼的问题,因为我们手机的内存有限,手机给每个应用程序分配的内存也有限,所以图片多的情况下很容易伴随着OOM的发生,不 过现在也有很多的开源的图片显示框架,大家有兴趣的可以去了解了解,今天我的这篇文章使用的是LruCache这个类(之前写了一篇使用LruCache 加载网络图片的Android 异步加载图片,使用LruCache和SD卡或手机缓存,效果非常的流畅)以及对图片进行相对应的裁剪,这样也可以尽量的避免OOM的发生,我们先看下微信的效果吧

接下来我们就来实现这些效果吧,首先我们新建一个项目,取名ImageScan

首 先我们先看第一个界面吧,使用将手机中的图片扫描出来,然后根据图片的所在的文件夹将其分类出来,并显示所在文件夹里面的一张图片和文件夹中图片个数,我 们根据界面元素(文件夹名, 文件夹图片个数,文件夹中的一张图片)使用一个实体对象ImageBean来封装这三个属性

package com.example.imagescan;

/**
* GridView的每个item的数据对象
*
* @author len
*
*/
public class ImageBean{
/**
* 文件夹的第一张图片路径
*/
private String topImagePath;
/**
* 文件夹名
*/
private String folderName;
/**
* 文件夹中的图片数
*/
private int imageCounts;

public String getTopImagePath() {
return topImagePath;
}
public void setTopImagePath(String topImagePath) {
this.topImagePath = topImagePath;
}
public String getFolderName() {
return folderName;
}
public void setFolderName(String folderName) {
this.folderName = folderName;
}
public int getImageCounts() {
return imageCounts;
}
public void setImageCounts(int imageCounts) {
this.imageCounts = imageCounts;
}

}

接下来就是主界面的布局啦,上面的导航栏我没有加进去,只有下面的GridView,所以说主界面布局中只有一个GridView


接下来就是GridView的Item的布局,看上面的图也行你会认为他的效果是2张图片添加的效果,其实不是,后面的叠加效果只是一张背景图片而已,代码先贴上来

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

&nbsp;

&nbsp;

看到上面的布局代码,也行你已经发现了,上面使用的是自定义的MyImageView,我先不说这个自定义MyImageView的作用,待会再给大家说,我们继续看代码

第一个界面的主要代码

package com.example.imagescan;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import android.app.Activity;
import android.app.ProgressDialog;
import android.content.ContentResolver;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.provider.MediaStore;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.GridView;
/**
* @blog http://blog.csdn.net/xiaanming
*
* @author xiaanming
*
*
*/
public class MainActivity extends Activity {
private HashMap&lt;String, List&gt; mGruopMap = new HashMap&lt;String, List&gt;();
private List list = new ArrayList();
private final static int SCAN_OK = 1;
private ProgressDialog mProgressDialog;
private GroupAdapter adapter;
private GridView mGroupGridView;

private Handler mHandler = new Handler(){

@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case SCAN_OK:
//关闭进度条
mProgressDialog.dismiss();

adapter = new GroupAdapter(MainActivity.this, list = subGroupOfImage(mGruopMap), mGroupGridView);
mGroupGridView.setAdapter(adapter);
break;
}
}

};

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

mGroupGridView = (GridView) findViewById(R.id.main_grid);

getImages();

mGroupGridView.setOnItemClickListener(new OnItemClickListener() {

@Override
public void onItemClick(AdapterView&lt;?&gt; parent, View view,
int position, long id) {
List childList = mGruopMap.get(list.get(position).getFolderName());

Intent mIntent = new Intent(MainActivity.this, ShowImageActivity.class);
mIntent.putStringArrayListExtra("data", (ArrayList)childList);
startActivity(mIntent);

}
});

}

/**
* 利用ContentProvider扫描手机中的图片,此方法在运行在子线程中
*/
private void getImages() {
//显示进度条
mProgressDialog = ProgressDialog.show(this, null, "正在加载...");

new Thread(new Runnable() {

@Override
public void run() {
Uri mImageUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
ContentResolver mContentResolver = MainActivity.this.getContentResolver();

//只查询jpeg和png的图片
Cursor mCursor = mContentResolver.query(mImageUri, null,
MediaStore.Images.Media.MIME_TYPE + "=? or "
+ MediaStore.Images.Media.MIME_TYPE + "=?",
new String[] { "image/jpeg", "image/png" }, MediaStore.Images.Media.DATE_MODIFIED);

if(mCursor == null){
return;
}

while (mCursor.moveToNext()) {
//获取图片的路径
String path = mCursor.getString(mCursor
.getColumnIndex(MediaStore.Images.Media.DATA));

//获取该图片的父路径名
String parentName = new File(path).getParentFile().getName();

//根据父路径名将图片放入到mGruopMap中
if (!mGruopMap.containsKey(parentName)) {
List chileList = new ArrayList();
chileList.add(path);
mGruopMap.put(parentName, chileList);
} else {
mGruopMap.get(parentName).add(path);
}
}

//通知Handler扫描图片完成
mHandler.sendEmptyMessage(SCAN_OK);
mCursor.close();
}
}).start();

}

/**
* 组装分组界面GridView的数据源,因为我们扫描手机的时候将图片信息放在HashMap中
* 所以需要遍历HashMap将数据组装成List
*
* @param mGruopMap
* @return
*/
private List subGroupOfImage(HashMap&lt;String, List&gt; mGruopMap){
if(mGruopMap.size() == 0){
return null;
}
List list = new ArrayList();

Iterator&lt;Map.Entry&lt;String, List&gt;&gt; it = mGruopMap.entrySet().iterator();
while (it.hasNext()) {
Map.Entry&lt;String, List&gt; entry = it.next();
ImageBean mImageBean = new ImageBean();
String key = entry.getKey();
List value = entry.getValue();

mImageBean.setFolderName(key);
mImageBean.setImageCounts(value.size());
mImageBean.setTopImagePath(value.get(0));//获取该组的第一张图片

list.add(mImageBean);
}

return list;

}

}

首先看getImages()这个方法,该方法是使用ContentProvider将手机中的图片扫描出来,我这里只扫描了手机的外部存储中的图片,由于手机中可能存在很多的图片,扫描图片又比较耗时,所以我们在这里开启了子线程去获取图片,扫描的图片都存放在Cursor中,我们先要将图片按照文件夹进行分类,我们使用了HashMap来进行分类并将结果存储到mGruopMap(Key是文件夹名,Value是文件夹中的图片路径的List)中,分类完了关闭Cursor并利用Handler来通知主线程
然后是subGroupOfImage()方法,改方法是将mGruopMap的数据组装到List中,在List中存放GridView中的每个item的数据对象ImageBean, 遍历HashMap对象,具体的逻辑看代码,之后就是给GridView设置Adapter。
设置item点击事件,点击文件夹跳转到展示文件夹图片的Activity, 我们需要传递每个文件夹中的图片的路径的集合

看GroupAdapter的代码之前,我们先看一个比较重要的类,本地图片加载器NativeImageLoader

package com.example.imagescan;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Point;
import android.os.Handler;
import android.os.Message;
import android.support.v4.util.LruCache;

/**
* 本地图片加载器,采用的是异步解析本地图片,单例模式利用getInstance()获取NativeImageLoader实例
* 调用loadNativeImage()方法加载本地图片,此类可作为一个加载本地图片的工具类
*
* @blog http://blog.csdn.net/xiaanming
*
* @author xiaanming
*
*/
public class NativeImageLoader {
private LruCache&lt;String, Bitmap&gt; mMemoryCache;
private static NativeImageLoader mInstance = new NativeImageLoader();
private ExecutorService mImageThreadPool = Executors.newFixedThreadPool(1);

private NativeImageLoader(){
//获取应用程序的最大内存
final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);

//用最大内存的1/4来存储图片
final int cacheSize = maxMemory / 4;
mMemoryCache = new LruCache&lt;String, Bitmap&gt;(cacheSize) {

//获取每张图片的大小
@Override
protected int sizeOf(String key, Bitmap bitmap) {
return bitmap.getRowBytes() * bitmap.getHeight() / 1024;
}
};
}

/**
* 通过此方法来获取NativeImageLoader的实例
* @return
*/
public static NativeImageLoader getInstance(){
return mInstance;
}

/**
* 加载本地图片,对图片不进行裁剪
* @param path
* @param mCallBack
* @return
*/
public Bitmap loadNativeImage(final String path, final NativeImageCallBack mCallBack){
return this.loadNativeImage(path, null, mCallBack);
}

/**
* 此方法来加载本地图片,这里的mPoint是用来封装ImageView的宽和高,我们会根据ImageView控件的大小来裁剪Bitmap
* 如果你不想裁剪图片,调用loadNativeImage(final String path, final NativeImageCallBack mCallBack)来加载
* @param path
* @param mPoint
* @param mCallBack
* @return
*/
public Bitmap loadNativeImage(final String path, final Point mPoint, final NativeImageCallBack mCallBack){
//先获取内存中的Bitmap
Bitmap bitmap = getBitmapFromMemCache(path);

final Handler mHander = new Handler(){

@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
mCallBack.onImageLoader((Bitmap)msg.obj, path);
}

};

//若该Bitmap不在内存缓存中,则启用线程去加载本地的图片,并将Bitmap加入到mMemoryCache中
if(bitmap == null){
mImageThreadPool.execute(new Runnable() {

@Override
public void run() {
//先获取图片的缩略图
Bitmap mBitmap = decodeThumbBitmapForFile(path, mPoint == null ? 0: mPoint.x, mPoint == null ? 0: mPoint.y);
Message msg = mHander.obtainMessage();
msg.obj = mBitmap;
mHander.sendMessage(msg);

//将图片加入到内存缓存
addBitmapToMemoryCache(path, mBitmap);
}
});
}
return bitmap;

}

/**
* 往内存缓存中添加Bitmap
*
* @param key
* @param bitmap
*/
private void addBitmapToMemoryCache(String key, Bitmap bitmap) {
if (getBitmapFromMemCache(key) == null &amp;&amp; bitmap != null) {
mMemoryCache.put(key, bitmap);
}
}

/**
* 根据key来获取内存中的图片
* @param key
* @return
*/
private Bitmap getBitmapFromMemCache(String key) {
return mMemoryCache.get(key);
}

/**
* 根据View(主要是ImageView)的宽和高来获取图片的缩略图
* @param path
* @param viewWidth
* @param viewHeight
* @return
*/
private Bitmap decodeThumbBitmapForFile(String path, int viewWidth, int viewHeight){
BitmapFactory.Options options = new BitmapFactory.Options();
//设置为true,表示解析Bitmap对象,该对象不占内存
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path, options);
//设置缩放比例
options.inSampleSize = computeScale(options, viewWidth, viewHeight);

//设置为false,解析Bitmap对象加入到内存中
options.inJustDecodeBounds = false;

return BitmapFactory.decodeFile(path, options);
}

/**
* 根据View(主要是ImageView)的宽和高来计算Bitmap缩放比例。默认不缩放
* @param options
* @param width
* @param height
*/
private int computeScale(BitmapFactory.Options options, int viewWidth, int viewHeight){
int inSampleSize = 1;
if(viewWidth == 0 || viewWidth == 0){
return inSampleSize;
}
int bitmapWidth = options.outWidth;
int bitmapHeight = options.outHeight;

//假如Bitmap的宽度或高度大于我们设定图片的View的宽高,则计算缩放比例
if(bitmapWidth &gt; viewWidth || bitmapHeight &gt; viewWidth){
int widthScale = Math.round((float) bitmapWidth / (float) viewWidth);
int heightScale = Math.round((float) bitmapHeight / (float) viewWidth);

//为了保证图片不缩放变形,我们取宽高比例最小的那个
inSampleSize = widthScale &lt; heightScale ? widthScale : heightScale;
}
return inSampleSize;
}

/**
* 加载本地图片的回调接口
*
* @author xiaanming
*
*/
public interface NativeImageCallBack{
/**
* 当子线程加载完了本地的图片,将Bitmap和图片路径回调在此方法中
* @param bitmap
* @param path
*/
public void onImageLoader(Bitmap bitmap, String path);
}
}
  1. 该类是一个单例类,提供了本地图片加载,内存缓存,裁剪等逻辑,该类在加载本地图片的时候采用的是异步加载的方式,对于大图片的加载也是 比较耗时的,所以采用子线程的方式去加载,对于图片的缓存机制使用的是LruCache,使用手机分配给应用程序内存的1/4用来缓存图片,除了使用 LruCache缓存图片之外,还对图片进行了裁剪,举个很简单的例子,假如我们的控件大小是100 * 100, 而我们的图片是400*400,我们加载这么大的图片需要很多的内存,所以我们采用了图片裁剪,根据控件的大小来确定图片的裁剪比例,从而减小内存的消 耗,提过GridView滑动的流畅度,介绍里面几个比较重要的方法,computeScale()计算图片需要裁剪的比例,根据控件的大小和图片的大小 确定比例,如果图片比控件大,我们就进行裁剪,否则不需要。decodeThumbBitmapForFile()方法是根据计算好了图片裁剪的比例之后 从文件中加载图片,我们先设置options.inJustDecodeBounds = true表示解析不占用内存,但是我们能获取图片的具体大小,利用computeScale()计算好比例,在将 options.inJustDecodeBounds=false,再次解析Bitmap,这样子就对图片进行了裁剪。
  2. loadNativeImage(final String path, final Point mPoint, final NativeImageCallBack mCallBack)我们在客户端只需要调用该方法就能获取到Bitmap对象,里面的具体逻辑是先判断内存缓存LruCache中是否存在该 Bitmap,不存在就开启子线程去读取,为了方便管理加载本地图片线程,这里使用了线程池,池中只能容纳一个线程,读取完了本地图片先将Bitmap加 入到LruCache中,保存的Key为图片路径,然后再使用Handler通知主线程图片加载好了,之后将Bitmap和路径回调到方法 onImageLoader(Bitmap bitmap, String path)中,该方法的mPoint是用来封装控件的宽和高的对象,如果不对图片进行裁剪直接这个方法的重载方法 loadNativeImage(final String path, final NativeImageCallBack mCallBack)就行了,逻辑是一样的,只是这个方法不对图片进行裁剪

接下来就是GridView的Adapter类的代码

package com.example.imagescan;

import java.util.List;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Point;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.TextView;

import com.example.imagescan.MyImageView.OnMeasureListener;
import com.example.imagescan.NativeImageLoader.NativeImageCallBack;

public class GroupAdapter extends BaseAdapter{
private List list;
private Point mPoint = new Point(0, 0);//用来封装ImageView的宽和高的对象
private GridView mGridView;
protected LayoutInflater mInflater;

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

@Override
public Object getItem(int position) {
return list.get(position);
}

@Override
public long getItemId(int position) {
return position;
}

public GroupAdapter(Context context, List list, GridView mGridView){
this.list = list;
this.mGridView = mGridView;
mInflater = LayoutInflater.from(context);
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
final ViewHolder viewHolder;
ImageBean mImageBean = list.get(position);
String path = mImageBean.getTopImagePath();
if(convertView == null){
viewHolder = new ViewHolder();
convertView = mInflater.inflate(R.layout.grid_group_item, null);
viewHolder.mImageView = (MyImageView) convertView.findViewById(R.id.group_image);
viewHolder.mTextViewTitle = (TextView) convertView.findViewById(R.id.group_title);
viewHolder.mTextViewCounts = (TextView) convertView.findViewById(R.id.group_count);

//用来监听ImageView的宽和高
viewHolder.mImageView.setOnMeasureListener(new OnMeasureListener() {

@Override
public void onMeasureSize(int width, int height) {
mPoint.set(width, height);
}
});

convertView.setTag(viewHolder);
}else{
viewHolder = (ViewHolder) convertView.getTag();
viewHolder.mImageView.setImageResource(R.drawable.friends_sends_pictures_no);
}

viewHolder.mTextViewTitle.setText(mImageBean.getFolderName());
viewHolder.mTextViewCounts.setText(Integer.toString(mImageBean.getImageCounts()));
//给ImageView设置路径Tag,这是异步加载图片的小技巧
viewHolder.mImageView.setTag(path);

//利用NativeImageLoader类加载本地图片
Bitmap bitmap = NativeImageLoader.getInstance().loadNativeImage(path, mPoint, new NativeImageCallBack() {

@Override
public void onImageLoader(Bitmap bitmap, String path) {
ImageView mImageView = (ImageView) mGridView.findViewWithTag(path);
if(bitmap != null &amp;&amp; mImageView != null){
mImageView.setImageBitmap(bitmap);
}
}
});

if(bitmap != null){
viewHolder.mImageView.setImageBitmap(bitmap);
}else{
viewHolder.mImageView.setImageResource(R.drawable.friends_sends_pictures_no);
}

return convertView;
}

public static class ViewHolder{
public MyImageView mImageView;
public TextView mTextViewTitle;
public TextView mTextViewCounts;
}

}

首先我们将每个item的图片路径设置到该ImageView上面,然后利用NativeImageLoader来加载本地图片,很普通,但是我们想在 getView()中获取ImageView的宽和高存在问题,在getView()里面刚开始显示item的时候利用 ImageView.getWidth()获取的都是0,这个比较郁闷,但是我们想要获取ImageView的宽和高怎么办呢?于是我想到了自定义 ImageView,在onMeasure()中利用回调的模式主动通知 我ImageView测量的宽和高,但是这有一个小小的问题,就是显示GridView的第一个item的时候,获取的宽和高还是0,第二个就能正常获取 了,第一个宽和高为0,我们不对第一张图片进行裁剪而已,在效率上也没啥问题,不知道大家有没有好的方法,可以在getView()中获取Item中某个控件的宽和高。

自定义MyImageView的代码,我们只需要设置OnMeasureListener监听,当MyImageView测量完毕之后,就会将测量的宽和高回调到onMeasureSize()中,然后我们可以根据MyImageView的大小来裁剪图片

package com.example.imagescan;

import android.content.Context;
import android.util.AttributeSet;
import android.widget.ImageView;

public class MyImageView extends ImageView {
private OnMeasureListener onMeasureListener;

public void setOnMeasureListener(OnMeasureListener onMeasureListener) {
this.onMeasureListener = onMeasureListener;
}

public MyImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}

public MyImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);

//将图片测量的大小回调到onMeasureSize()方法中
if(onMeasureListener != null){
onMeasureListener.onMeasureSize(getMeasuredWidth(), getMeasuredHeight());
}
}

public interface OnMeasureListener{
public void onMeasureSize(int width, int height);
}

}

上面这些代码就完成了第一个界面的功能了,接下来就是点击GridView的item跳转另一个界面来显示该文件夹下面的所有图片,功能跟第一个界面差不多,也是使用GridView来显示图片,第二个界面的布局代码我就不贴了,直接贴上界面的代码

package com.example.imagescan;

import java.util.List;

import android.app.Activity;
import android.os.Bundle;
import android.widget.GridView;
import android.widget.Toast;

public class ShowImageActivity extends Activity {
private GridView mGridView;
private List list;
private ChildAdapter adapter;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.show_image_activity);

mGridView = (GridView) findViewById(R.id.child_grid);
list = getIntent().getStringArrayListExtra("data");

adapter = new ChildAdapter(this, list, mGridView);
mGridView.setAdapter(adapter);

}

@Override
public void onBackPressed() {
Toast.makeText(this, "选中 " + adapter.getSelectItems().size() + " item", Toast.LENGTH_LONG).show();
super.onBackPressed();
}

}

GridView的item上面一个我们自定义的MyImageView用来显示图片,另外还有一个CheckBox来记录我们选中情况,Adapter的代码如下

package com.example.imagescan;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Point;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.ImageView;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.GridView;

import com.example.imagescan.MyImageView.OnMeasureListener;
import com.example.imagescan.NativeImageLoader.NativeImageCallBack;
import com.nineoldandroids.animation.AnimatorSet;
import com.nineoldandroids.animation.ObjectAnimator;

public class ChildAdapter extends BaseAdapter {
private Point mPoint = new Point(0, 0);//用来封装ImageView的宽和高的对象
/**
* 用来存储图片的选中情况
*/
private HashMap&lt;Integer, Boolean&gt; mSelectMap = new HashMap&lt;Integer, Boolean&gt;();
private GridView mGridView;
private List list;
protected LayoutInflater mInflater;

public ChildAdapter(Context context, List list, GridView mGridView) {
this.list = list;
this.mGridView = mGridView;
mInflater = LayoutInflater.from(context);
}

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

@Override
public Object getItem(int position) {
return list.get(position);
}

@Override
public long getItemId(int position) {
return position;
}

@Override
public View getView(final int position, View convertView, ViewGroup parent) {
final ViewHolder viewHolder;
String path = list.get(position);

if(convertView == null){
convertView = mInflater.inflate(R.layout.grid_child_item, null);
viewHolder = new ViewHolder();
viewHolder.mImageView = (MyImageView) convertView.findViewById(R.id.child_image);
viewHolder.mCheckBox = (CheckBox) convertView.findViewById(R.id.child_checkbox);

//用来监听ImageView的宽和高
viewHolder.mImageView.setOnMeasureListener(new OnMeasureListener() {

@Override
public void onMeasureSize(int width, int height) {
mPoint.set(width, height);
}
});

convertView.setTag(viewHolder);
}else{
viewHolder = (ViewHolder) convertView.getTag();
viewHolder.mImageView.setImageResource(R.drawable.friends_sends_pictures_no);
}
viewHolder.mImageView.setTag(path);
viewHolder.mCheckBox.setOnCheckedChangeListener(new OnCheckedChangeListener() {

@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
//如果是未选中的CheckBox,则添加动画
if(!mSelectMap.containsKey(position) || !mSelectMap.get(position)){
addAnimation(viewHolder.mCheckBox);
}
mSelectMap.put(position, isChecked);
}
});

viewHolder.mCheckBox.setChecked(mSelectMap.containsKey(position) ? mSelectMap.get(position) : false);

//利用NativeImageLoader类加载本地图片
Bitmap bitmap = NativeImageLoader.getInstance().loadNativeImage(path, mPoint, new NativeImageCallBack() {

@Override
public void onImageLoader(Bitmap bitmap, String path) {
ImageView mImageView = (ImageView) mGridView.findViewWithTag(path);
if(bitmap != null &amp;&amp; mImageView != null){
mImageView.setImageBitmap(bitmap);
}
}
});

if(bitmap != null){
viewHolder.mImageView.setImageBitmap(bitmap);
}else{
viewHolder.mImageView.setImageResource(R.drawable.friends_sends_pictures_no);
}

return convertView;
}

/**
* 给CheckBox加点击动画,利用开源库nineoldandroids设置动画
* @param view
*/
private void addAnimation(View view){
float [] vaules = new float[]{0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f, 1.1f, 1.2f, 1.3f, 1.25f, 1.2f, 1.15f, 1.1f, 1.0f};
AnimatorSet set = new AnimatorSet();
set.playTogether(ObjectAnimator.ofFloat(view, "scaleX", vaules),
ObjectAnimator.ofFloat(view, "scaleY", vaules));
set.setDuration(150);
set.start();
}

/**
* 获取选中的Item的position
* @return
*/
public List getSelectItems(){
List list = new ArrayList();
for(Iterator&lt;Map.Entry&lt;Integer, Boolean&gt;&gt; it = mSelectMap.entrySet().iterator(); it.hasNext();){
Map.Entry&lt;Integer, Boolean&gt; entry = it.next();
if(entry.getValue()){
list.add(entry.getKey());
}
}

return list;
}

public static class ViewHolder{
public MyImageView mImageView;
public CheckBox mCheckBox;
}

}

第二个界面的Adapter跟第一个界面差不多,无非多了一个CheckBox用来记录图片选择情况,我们只需要对CheckBox设置 setOnCheckedChangeListener监听,微信的选中之后CheckBox有一个动画效果,所以我利用nineoldAndroids 动画库也给CheckBox加了一个动画效果,直接调用addAnimation()方法就能添加了,getSelectItems()方法就能获取我们 选中的item的position了,知道了选中的position,其他的信息就都知道了,微信有对图片进行预览的功能,我这里就不添加了,如果有这个 需求可以自行添加,给大家推荐一个https://github.com/chrisbanes/PhotoView

 

运行项目,效果如下

 

 

看 起来还不错吧,采用的是异步读取图片,对图片进行了缓存和裁剪,使得在显示本地图片方面比较流畅,GridView滑动也挺流畅的,也有效的避免OOM的 产生,工程中有些东西还没有贴完全,有兴趣的朋友可以下载Demo来运行一下,好了,今天的讲解到这里结束了,感谢大家观看,希望这篇有疑问的朋友可以在 下面留言,我会为大家解答的!

项目源码,点击下载

[转载].net处理JSON简明教程 - 小A的日志 - 网易博客

mikel阅读(1445)

[转载].net处理JSON简明教程 – 小A的日志 – 网易博客.

.net处理JSON简明教程

Json.Net是.net中的一种流行的高性能的JSON框架。

特点

  1. 灵活的JSON序列化转化.net对象为JSON字符串。和把JSON字符串转换为.net对象。
  2. 手动读写JSON的Linq to JSON
  3. 比.net内置的JSON序列化程序更高的性能和速度。
  4. 便于读写的JSON
  5. 从XML中读取或写入JSON
  6. 支持Silverlight和Windows phone.

    当你读写的JSON与.net类紧密关联时,JSON序列化程序是一个不错的选择。JSON序列化程序将自动读写相关类的JSON。

     

    如果你只对JSON里面的数据感兴趣、你没有与JSON相关联的.net类或者JSON数据与你的类没有任何关系,你需要从对象中手动读写数据。以上各种情况下,你可以使用LINQ To JSON. LINQ To JSON 允许你在.net中更容易的读取、写入、修改JSON数据。

     

    Download Json.NET from CodePlex or install using NuGet

    PM> Install-Package Newtonsoft.Json

     

    JSON.net下载地址列表

    http://json.codeplex.com/releases/view/74287

    提供JSON.NET 4.0 Release 3版本地址

    http://json.codeplex.com/releases/view/74287#DownloadId=287841

    更多JSON详细信息,请查看: http://james.newtonking.com/projects/json-net.aspx

     

     

    先构造一个简单的类employee

    Public class employee{

    Public string eid{get;set;}

    Public string ename{get;set;}

    Public string esex{get;set;}

    Public datetime birthday{get;set;}

    }

     

     

    JSON序列化与反序列化的方案

    1. 使用Json.Net 处理JSON序列化与反序列化

序列化方法

private string JsonSerialize(employee emp) {

return Newtonsoft.Json.JsonConvert.SerializeObject(emp);

}

反序列化方法

private employee JsonDeserialize(string json) {

return (employee)(Newtonsoft.Json.JsonConvert.DeserializeObject(json, typeof(employee)));

}

  1. 使用JavaScriptSerializer进行序列化、反序列化

    序列化方法

private string JsonSerialize (employee emp) {

return new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(emp);

}

反序列化

Private string JsonDeserialize (string json){

return (employee)(new System.Web.Script.Serialization.JavaScriptSerializer().Deserialize(json,typeof(employee)));

}

  1. 通过类DataContractJsonSerializer对JSON序列化和反序列化

    序列化方法

private string JsonSerialize (employee emp) {

        System.Runtime.Serialization.Json.DataContractJsonSerializer dcjs = new System.Runtime.Serialization.Json.DataContractJsonSerializer(typeof(employee));

        System.IO.MemoryStream ms = new System.IO.MemoryStream();

        dcjs.WriteObject(ms, emp);

        string json = System.Text.Encoding.UTF8.GetString(ms.ToArray());

        ms.Close();

        return json;

         }

反序列化方法

private employee JsonDeserialize (string json) {

     System.Runtime.Serialization.Json.DataContractJsonSerializer dcjs = new System.Runtime.Serialization.Json.DataContractJsonSerializer(typeof(employee));

    System.IO.MemoryStream ms = new System.IO.MemoryStream(System.Text.Encoding.UTF8.GetBytes(json));

employee obj = (employee)(dcjs.ReadObject(ms));

return obj;

        }

  1. 通过Newtonsoft.Json.Linq.JObject获取JSON数据

private void LinqJson(string json) {

JObject obj = Newtonsoft.Json.Linq.JObject.Parse(json);

//获取全部数据值

foreach (JToken token in obj.Values()) {

Response.Write(token.ToString());

}

//获取唯一值

Response.Write(obj[“eid”].ToString()+“<br />”); }

  1. 5、LINQ to JSON Example

string json = @”{

  “”Name””: “”Apple””,

  “”Expiry””: new Date(1230422400000),

  “”Price””: 3.99,

  “”Sizes””: [

    “”Small””,

    “”Medium””,

    “”Large””

  ]

}”;

JObject o = JObject.Parse(json);

string name = (string)o[“Name”];

// Apple

JArray sizes = (JArray)o[“Sizes”];

string smallest = (string)sizes[0];

 

JSON序列化和反序列化日期时间的处理

JSON格式不直接支持日期和时间。DateTime值值显示为“/Date(700000+0500)/”形式的JSON字符串,其中第一个数字(在提供的示例中为 700000)是 GMT 时区中自 1970 1 1 日午夜以来按正常时间(非夏令时)经过的毫秒数。该数字可以是负数,以表示之前的时间。示例中包括“+0500”的部分可选,它指示该时间属于Local 类型,即它在反序列化时应转换为本地时区。如果没有该部分,则会将时间反序列化为Utc

使用DataContractJsonSerializer的序列化方式对日期格式进行处理,其他的()序列化方案的使用方式是相同的。设计思想是通过正则表达式匹配,替换JSON里面的日期数据为正常的日期格式。

序列化方法

private string JsonSerialize (employee emp) {

System.Runtime.Serialization.Json.DataContractJsonSerializer dcjs = new System.Runtime.Serialization.Json.DataContractJsonSerializer(typeof(employee));

System.IO.MemoryStream ms = new System.IO.MemoryStream();

dcjs.WriteObject(ms, emp);

string json = System.Text.Encoding.UTF8.GetString(ms.ToArray());

ms.Close();

//替换JSON时间为字符串

string p = @”\\/Date\((\d+)\)\\/”;

System.Text.RegularExpressions.MatchEvaluator me = new System.Text.RegularExpressions.MatchEvaluator(ConvertJsonDateToDataString);

System.Text.RegularExpressions.Regex regex = new System.Text.RegularExpressions.Regex(p);

json = regex.Replace(json, me);

return json;

}

 

 

private string ConvertJsonDateToDataString(System.Text.RegularExpressions.Match m) {

string result = string.Empty;

DateTime dt = new DateTime(1970,1,1);

dt = dt.AddMilliseconds(long.Parse(m.Groups[1].Value));

dt = dt.ToLocalTime();

result = dt.ToString(“yyyy-MM-dd HH:mm:ss”);

return result;

}

 

反序列化方法

private employee JsonDeserialize (string json)

{

string p = @”\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}”;

System.Text.RegularExpressions.MatchEvaluator me = new System.Text.RegularExpressions.MatchEvaluator(ConvertDateStringToJsonDate);

System.Text.RegularExpressions.Regex reg = new System.Text.RegularExpressions.Regex(p);

json = reg.Replace(json, me);

 

System.Runtime.Serialization.Json.DataContractJsonSerializer dcjs=new System.Runtime.Serialization.Json.DataContractJsonSerializer(typeof(employee));

System.IO.MemoryStream ms=new System.IO.MemoryStream(System.Text.Encoding.UTF8.GetBytes(json));

employee emp=(employee)dcjs.ReadObject(ms);

return emp;

}

 

private string ConvertDateStringToJsonDate(System.Text.RegularExpressions.Match m)

{

string result = string.Empty;

DateTime dt = DateTime.Parse(m.Groups[0].Value);

dt = dt.ToUniversalTime();

TimeSpan ts = dt – DateTime.Parse(“1970-1-1”);

result = string.Format(“\\/Date({0}+0800)\\/”, ts.TotalMilliseconds);

return result;

}

[转载]android 拍照上传照片

mikel阅读(1075)

[转载]android 拍照上传照片-Android新手入门-eoe Android开发者社区_Android开发论坛 – Powered by Discuz!.

废话不多说,直接进入主题,想要在Android中实现拍照最简单饿方法就是New 一个 Intent 设置Action为Android.media.action.IMAGE_CAPTURE 然后使用startActivityForResult(intent,REQUEST_CODE)方法进入相机。当然还有很多方式可以实现,大家可以在 网上查找。但是要注意的是在进入相机前最好判断下sdcard是否可用,代码如下:

destoryBimap();

String state = Environment.getExternalStorageState();
if (state.equals(Environment.MEDIA_MOUNTED)) {
intent = new Intent("android.media.action.IMAGE_CAPTURE");
startActivityForResult(intent, REQUEST_CODE);
} else {
Toast.makeText(DefectManagerActivity.this,
R.string.common_msg_nosdcard, Toast.LENGTH_LONG).show();

}

当拍照完成以后需要在onActivityResult(int requestCode, int resultCode, Intent data)方法中获取拍摄的图片,Android把拍摄的图片封装到bundle中传递回来,但是根据不同的机器获得相片的方式不太一样,所以会出现某一种方式获取图片为null的想象,解决办法就是做一个判断,当一种方式不能获取,就是用另一种方式,下面是分别获取相片的两种方式:

Uri uri = data.getData();

if (uri != null) {

photo = BitmapFactory.decodeFile(uri.getPath());
}

if (photo == null) {
Bundle bundle = data.getExtras();
if (bundle != null) {
photo = (Bitmap) bundle.get("data");

} else {

Toast.makeText(DefectManagerActivity.this,
getString(R.string.common_msg_get_photo_failure),
Toast.LENGTH_LONG).show();

return;

}

第一种方式是用方法中传回来的intent调用getData();方法获取数据的Uri,然后再根据uri获取数据的路径,然后根据路径封装成一个bitmap就行了.
第二种方式也是用法中传回来的intent对象但是不再是调用getData();方法而是调用getExtras();方法获取intent里面所有参数的一个对象集合bundle,然后是用bundle对象得到键为data的值也就是一个bitmap对象.

通过上面两种方式就能获取相片的bitmap对象,然后就可以在程序中是用,如果你想把相片保存到自己指定的目录可以是用如下步骤即可:
首先bitmap有个一compress(Bitmap.CompressFormat.JPEG, 100, baos)方法,这个方法有三个参数,第一个是指定将要保存的图片的格式,第二个是图片保存的质量,值是0-100,比如像PNG格式的图片这个参数你可以随便设置,因为PNG是无损的格式。第三个参数是你一个缓冲输出流ByteArrayOutputStream();,这个方法的作用就是把 bitmap的图片转换成jpge的格式放入输出流中,然后大家应该明白怎么操作了吧,下面是实例代码:

String pictureDir = "";

FileOutputStream fos = null;
BufferedOutputStream bos = null;

ByteArrayOutputStream baos = null;

try {
baos = new ByteArrayOutputStream();

bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);

byte[] byteArray = baos.toByteArray();
String saveDir = Environment.getExternalStorageDirectory()
+ "/temple";
File dir = new File(saveDir);

if (!dir.exists()) {

dir.mkdir();
}

File file = new File(saveDir, "temp.jpg");

file.delete();
if (!file.exists()) {
file.createNewFile();

}
fos = new FileOutputStream(file);
bos = new BufferedOutputStream(fos);
bos.write(byteArray);

pictureDir = file.getPath();

} catch (Exception e) {
e.printStackTrace();

} finally {
if (baos != null) {
try {

baos.close();
} catch (Exception e) {
e.printStackTrace();

}
}
if (bos != null) {
try {
bos.close();
} catch (Exception e) {
e.printStackTrace();
}

}

if (fos != null) {

try {

fos.close();

} catch (Exception e) {

e.printStackTrace();

}
}
}

然后就是实现图片的上传功能,我这里是是用的apache的HttpClient里面的MultipartEntity实现文件上传具体代码如下:

/**
* 提交参数里有文件的数据
*
* @param url
* 服务器地址
* @param param
* 参数
* <a href="\" target="\">@return</a> 服务器返回结果
* @throws Exception
*/
public static String uploadSubmit(String url, Map&lt;String, String&gt; param,
File file) throws Exception {
HttpPost post = new HttpPost(url);

MultipartEntity entity = new MultipartEntity();
if (param != null &amp;&amp; !param.isEmpty()) {
for (Map.Entry&lt;String, String&gt; entry : param.entrySet()) {
entity.addPart(entry.getKey(), new StringBody(entry.getValue()));
}
}
// 添加文件参数
if (file != null &amp;&amp; file.exists()) {
entity.addPart("file", new FileBody(file));
}
post.setEntity(entity);
HttpResponse response = httpClient.execute(post);
int stateCode = response.getStatusLine().getStatusCode();
StringBuffer sb = new StringBuffer();
if (stateCode == HttpStatus.SC_OK) {
HttpEntity result = response.getEntity();
if (result != null) {
InputStream is = result.getContent();
BufferedReader br = new BufferedReader(
new InputStreamReader(is));
String tempLine;
while ((tempLine = br.readLine()) != null) {
sb.append(tempLine);
}
}
}
post.abort();
return sb.toString();
}

这里就基本上对图片上传就差不多了,但是还有一个问题就是图片上传完以后bitmap还在内存中,而且大家都知道如果,高清的图片比较大,而手机内存本来就有限,如果不进行处理很容易报内存溢出,所以我们应该把处理完的bitmap从内存中释放掉,这时候就需要调用bitmap的recycle();方法,调用这个方法的时候需要注意不能太早也不能太晚,不然会报异常,一般可以放在下一张图片生成前或者没有任何view引用要销毁的图片的时候下面是实例代码:

/**
* 销毁图片文件
*/
private void destoryBimap() {
if (photo != null &amp;&amp; !photo.isRecycled()) {
photo.recycle();
photo = null;
}
}

源码下载地址:http://pan.baidu.com/s/1kT6vzuR

[转载]学习脚步--- HttpClient4.0 - - ITeye技术网站

mikel阅读(1018)

[转载]学习脚步— HttpClient4.0 – – ITeye技术网站.

HttpClient程序包是一个实现了 HTTP 协议的客户端编程工具包,要想熟练的掌握它,必须熟悉 HTTP协议。一个最简单的调用如下:

import java.io.IOException;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.impl.client.DefaultHttpClient;

public class Test {
public static void main(String[] args) {

// 核心应用类
HttpClient httpClient = new DefaultHttpClient();

// HTTP请求
HttpUriRequest request =
new HttpGet("http://localhost/index.html");

// 打印请求信息
System.out.println(request.getRequestLine());
try {
// 发送请求,返回响应
HttpResponse response = httpClient.execute(request);

// 打印响应信息
System.out.println(response.getStatusLine());
} catch (ClientProtocolException e) {
// 协议错误
e.printStackTrace();
} catch (IOException e) {
// 网络异常
e.printStackTrace();
}
}
}

如果HTTP服务器正常并且存在相应的服务,则上例会打印出两行结果:

GET http://localhost/index.html HTTP/1.1
HTTP/1.1 200 OK

核心对象httpClient的调用非常直观,其execute方法传入一个request对象,返回一个response对象。使用httpClient发出HTTP请求时,系统可能抛出两种异常,分别是ClientProtocolException和IOException。第一种异常的发生通常是协议错误导致,如在构造HttpGet对象时传入的协议不对(例如不小心将”http”写成”htp”),或者服务器端返回的内容不符合HTTP协议要求等;第二种异常一般是由于网络原因引起的异常,如HTTP服务器未启动等。
从实际应用的角度看,HTTP协议由两大部分组成:HTTP请求和HTTP响应。那么HttpClient程序包是如何实现HTTP客户端应用的呢?实现过程中需要注意哪些问题呢?
HTTP请求

HTTP 1.1由以下几种请求组成:GET, HEAD, POST, PUT, DELETE, TRACE and OPTIONS, 程序包中分别用HttpGet, HttpHead, HttpPost, HttpPut, HttpDelete, HttpTrace, and HttpOptions 这几个类创建请求。所有的这些类均实现了HttpUriRequest接口,故可以作为execute的执行参数使用。
所有请求中最常用的是GET与POST两种请求,与创建GET请求的方法相同,可以用如下方法创建一个POST请求:

HttpUriRequest request = new HttpPost(
"http://localhost/index.html");

HTTP请求格式 告诉我们,有两个位置或者说两种方式可以为request提供参数:request-line方式与request-body方式。

request-line

request-line方式是指在请求行上通过URI直接提供参数。
(1)
我们可以在生成request对象时提供带参数的URI,如:

HttpUriRequest request = new HttpGet(
"http://localhost/index.html?param1=value1&amp;param2=value2");

(2)

另外,HttpClient程序包为我们提供了URIUtils工具类,可以通过它生成带参数的URI,如:

URI uri = URIUtils.createURI("http", "localhost", -1, "/index.html",
"param1=value1&amp;param2=value2", null);
HttpUriRequest request = new HttpGet(uri);
System.out.println(request.getURI());

上例的打印结果如下:
http://localhost/index.html?param1=value1&param2=value2
(3)
需要注意的是,如果参数中含有中文,需将参数进行URLEncoding处理,如:

String param = "param1=" + URLEncoder.encode("中国", "UTF-8") + "&amp;param2=value2";
URI uri = URIUtils.createURI("http", "localhost", 8080,
"/sshsky/index.html", param, null);
System.out.println(uri);

上例的打印结果如下:

http://localhost/index.html?param1=%E4%B8%AD%E5%9B%BD&param2=value2

request-body

与request-line方式不同,request-body方式是在request-body中提供参数,此方式只能用于POST请求。在HttpClient程序包中有两个类可以完成此项工作,它们分别是UrlEncodedFormEntity类与MultipartEntity类。这两个类均实现了HttpEntity接口。
(1)
使用最多的是UrlEncodedFormEntity类。通过该类创建的对象可以模拟传统的HTML表单传送POST请求中的参数。如下面的表单:


<form action="http://localhost/index.html" method="POST"><input type="text" name="param1" value="中国" />
<input type="text" name="param2" value="value2" />
</form>

我们可以用下面的代码实现:

List formParams = new ArrayList();
formParams.add(new BasicNameValuePair("param1", "中国"));
formParams.add(new BasicNameValuePair("param2", "value2"));
HttpEntity entity = new UrlEncodedFormEntity(formParams, "UTF-8");

HttpPost request = new HttpPost(“http://localhost/index.html”);
request.setEntity(entity);

当然,如果想查看HTTP数据格式,可以通过HttpEntity对象的各种方法取得。如:

List formParams = new ArrayList();
formParams.add(new BasicNameValuePair("param1", "中国"));
formParams.add(new BasicNameValuePair("param2", "value2"));
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(formParams, "UTF-8");

System.out.println(entity.getContentType());
System.out.println(entity.getContentLength());
System.out.println(EntityUtils.getContentCharSet(entity));
System.out.println(EntityUtils.toString(entity));

上例的打印结果如下:

Content-Type: application/x-www-form-urlencoded; charset=UTF-8
39
UTF-8
param1=%E4%B8%AD%E5%9B%BD&amp;param2=value2

(2)
除了传统的application/x-www-form-urlencoded表单,我们另一个经常用到的是上传文件用的表单,这种表单的类型为multipart/form-data。在HttpClient程序扩展包(HttpMime)中专门有一个类与之对应,那就是MultipartEntity类。此类同样实现了HttpEntity接口。如下面的表单:


<form action="http://localhost/index.html" enctype="multipart/form-data" method="POST"><input type="text" name="param1" value="中国" />
<input type="text" name="param2" value="value2" />
<input type="file" name="param3" />
</form>

我们可以用下面的代码实现:

MultipartEntity entity = new MultipartEntity();
entity.addPart("param1", new StringBody("中国", Charset.forName("UTF-8")));
entity.addPart("param2", new StringBody("value2", Charset.forName("UTF-8")));
entity.addPart("param3", new FileBody(new File("C:\\1.txt")));

HttpPost request = new HttpPost(“http://localhost/index.html”);
request.setEntity(entity);

HTTP响应

HttpClient程序包对于HTTP响应的处理较之HTTP请求来说是简单多了,其过程同样使用了HttpEntity接口。我们可以从HttpEntity对象中取出数据流(InputStream),该数据流就是服务器返回的响应数据。需要注意的是,HttpClient程序包不负责解析数据流中的内容。如:

HttpUriRequest request = ...;
HttpResponse response = httpClient.execute(request);

// 从response中取出HttpEntity对象
HttpEntity entity = response.getEntity();

// 查看entity的各种指标
System.out.println(entity.getContentType());
System.out.println(entity.getContentLength());
System.out.println(EntityUtils.getContentCharSet(entity));

// 取出服务器返回的数据流
InputStream stream = entity.getContent();

// 以任意方式操作数据流stream
// 调用方式 略

附注:

本文说明的是HttpClient 4.0.1 ,该程序包(包括依赖的程序包)由以下几个JAR包组成:

commons-logging-1.1.1.jar
commons-codec-1.4.jar
httpcore-4.0.1.jar
httpclient-4.0.1.jar
apache-mime4j-0.6.jar
httpmime-4.0.1.jar

可以在此处 下载完整的JAR包。

[转载]HttpClient通过HttpPost传递参数上传图片代码 - 我们轻松了,并不是生活越来越容易了,而是我们越来越强 - ITeye技术网站

mikel阅读(1448)

[转载]HttpClient通过HttpPost传递参数 – 我们轻松了,并不是生活越来越容易了,而是我们越来越强 – ITeye技术网站.

HttpClient新版本(新老版本没有做明确界定,Sorry!)

package http;

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

import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;

public class HttpTests {

	/**
	 * @param args
	 * @throws Exception
	 */
	public static void main(String[] args) throws Exception {
		HttpClient httpclient = new DefaultHttpClient();
		HttpPost httpPost = new HttpPost("******/abc");
		List<NameValuePair> nvps = new ArrayList<NameValuePair>();
		nvps.add(new BasicNameValuePair("username", "vip"));
		nvps.add(new BasicNameValuePair("password", "secret"));
		httpPost.setEntity(new UrlEncodedFormEntity(nvps));
		httpclient.execute(httpPost);
		httpclient.getConnectionManager().shutdown();
	}

}

HttpClient 老版本:

package http;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.methods.PostMethod;

public class HttpTests {

	/**
	 * @param args
	 * @throws Exception
	 */
	public static void main(String[] args) throws Exception {
		HttpClient httpclient = new HttpClient();
		PostMethod httpPost =new PostMethod("******/abc");
        NameValuePair[] param = { new NameValuePair("username", "vip")};
        httpPost.setRequestBody(param); 
		httpclient.executeMethod(httpPost);
	}

}

上传图片:

import java.io.File;
import java.io.IOException;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;

public class HttpClientPostMethod {
	
	public static void main(String[] args) throws ClientProtocolException, IOException {
		post();
	}

	public static void post() throws ClientProtocolException, IOException {
		HttpClient httpclient = new DefaultHttpClient();
		HttpPost post = new HttpPost("http://localhost:8080/action.jsp");
		FileBody fileBody = new FileBody(new File("/home/sendpix0.jpg"));
		StringBody stringBody = new StringBody("文件的描述");
		MultipartEntity entity = new MultipartEntity();
		entity.addPart("file", fileBody);
		entity.addPart("desc", stringBody);
		post.setEntity(entity);
		HttpResponse response = httpclient.execute(post);
		if(HttpStatus.SC_OK==response.getStatusLine().getStatusCode()){  
			
			HttpEntity entitys = response.getEntity();
			if (entity != null) {
				System.out.println(entity.getContentLength());
				System.out.println(EntityUtils.toString(entitys));
			}
        }
		httpclient.getConnectionManager().shutdown();
	}
}

[转载] java模拟form表单提交图片文件

mikel阅读(1047)

[转载]程序开发技术交流分享 » Post Topic » java模拟form表单提交图片文件.
这次要和别人开发的服务器端程序接口对接,之前实现的上传文件的方法对方接口无法接收。他们的接口需要类似这样的form提交数据:

<form enctype="multipart/form-data" action=http://url/path  method="POST">
<input name="filename” type="file" />
<input type="submit" value="test" />
</form> 

解决办法是引入commons-httpclient.jar,下载地址http://hc.apache.org/downloads.cgi,模拟form表单提交数据,代码如下:

    File f = new File("device1.png");
    PostMethod filePost = new PostMethod(
            "http://url/path");
    Part[] parts = { new FilePart("filename", f) };
    filePost.setRequestEntity(new MultipartRequestEntity(parts, filePost
            .getParams()));
    HttpClient clients = new HttpClient();

    int status = clients.executeMethod(filePost);
    try {
        BufferedReader rd = new BufferedReader(new InputStreamReader(
                filePost.getResponseBodyAsStream(), "UTF-8"));
        StringBuffer stringBuffer = new StringBuffer();
        String line;
        while ((line = rd.readLine()) != null) {
            stringBuffer .append(line);
        }
        rd.close();
        System.out.println("接受到的流是:" + stringBuffer + "—-" + status);
    } catch (Exception e) {
        throw new RuntimeException("error”,e);

    }

解释一下

filePost.setRequestEntity(new MultipartRequestEntity(parts, filePost
        .getParams())); 

设置多媒体参数,作用类似form表单中的enctype=”multipart/form-data” ,

Part[] parts = { new FilePart("filename", f) };

设定参数名称和值,类似form表单中的
try catch块主要是打印服务器端回传的数据。

[转载]CSS3+HTML5特效3 - 纵向无缝滚动 - z_gia - 博客园

mikel阅读(1027)

[转载]CSS3+HTML5特效3 – 纵向无缝滚动 – z_gia – 博客园.

老惯例,先看例子。

This is a test 1.
This is a test 2.
This is a test 3.
This is a test 4.
This is a test 5.
This is a test 1.

 

实现原理:

1. 利用CSS3的@keyframes规则创建动画效果;

2. 使用CSS3的animation效果完成滚动切换。

 

CSS代码

@-webkit-keyframes scrollText1 {
    0%{
        -webkit-transform: translateY(0px);
    }
    20%{
        -webkit-transform: translateY(-30px);
    }
    40%{
        -webkit-transform: translateY(-60px);
    }
    60%{
        -webkit-transform: translateY(-90px);
    }
    80%{
        -webkit-transform: translateY(-120px);
    }
    100%{
        -webkit-transform: translateY(-150px);
    }
}

@keyframes scrollText1 {
    0%{
        transform: translateY(0px);
    }
    20%{
        transform: translateY(-30px);
    }
    40%{
        transform: translateY(-60px);
    }
    60%{
        transform: translateY(-90px);
    }
    80%{
        transform: translateY(-120px);
    }
    100%{
        transform: translateY(-150px);
    }
}

.box3{
  position: relative;
  top: 20px;
  left: 20px;
  width: 200px;
  height: 30px;
  overflow: hidden;
  border:1px solid #ccc;
}

.border3{
  top: 0px;
  -webkit-animation:scrollText1 8s infinite  cubic-bezier(1,0,0.5,0) ;
  animation:scrollText1 8s infinite  cubic-bezier(1,0,0.5,0) ;
}

.border3 div{
  height: 30px;
}

.border3:hover{
  animation-play-state:paused;
  -webkit-animation-play-state:paused;
}

CSS代码说明:

@-webkit-keyframes及@keyframes定义了从0% ~ 100%之间,每过20%的时间,向上移动30px,总共有6次移动;
.box3 定义外容器的基本属性
.border3 定义了内容器的属性,-webkit-animation:scrollText1 8s infinite cubic-bezier(1,0,0.5,0) 和 animation:scrollText1 8s infinite cubic-bezier(1,0,0.5,0) 定义了用8s种循环一次,无限循环已经移动是的效果;
.border3 div 定义了纵向滚动内容的基本样式;
.border3:hover 定义了鼠标移入容器是的效果,animation-play-state:paused 及 -webkit-animation-play-state:paused 定义了动画暂停;

HTML代码

<div class="box3">
  <div class="border3">
    <div>This is a test 1.</div>
    <div>This is a test 2.</div>
    <div>This is a test 3.</div>
    <div>This is a test 4.</div>
    <div>This is a test 5.</div>
    <div>This is a test 1.</div>
  </div>
</div>

HTML代码说明:

定义了6条信息可以纵向滚动,其中前5条是真正纵向滚动的信息,第6条和第1条信息是一样的,原因很简单,因为使用了@keyframes方式来实现动画效果,第1条信息的效果是默认为停止的,所以用第6条信息制作一个替代方法,在第一次循环结束后,可以无缝继续滚动,大家可以去掉第6条试一下,就可以看见效果了。

至此,大功告成。

[转载]android开发中监控android软件网络请求的软件Charles使用入门 - 大侠(cer) - 博客园

mikel阅读(903)

[转载]android开发中监控android软件网络请求的软件Charles使用入门 – 大侠(cer) – 博客园.

1.下载并安状软件,官网在此:

http://www.charlesproxy.com/

2.前题条件,电脑和手机必须在同一网段

3.在Charles界面选择菜单

proxy->proxy settings

勾选”Enable transparent HTTP proxying”确定代理端口,默认”8888″就可以了

4.在手机的wifi节点上长按,然后在跳出的框选”修改网络”,如图:

5.然后勾选”显示高级选项”,在出现的内容填入代理主机的IP(也就是你装了Charles的机器),端口框填入刚才填的”8888″,保存如图:

 

6.这时Charles客户端会跳一个框问你什么,你通过就可以了

[转载]C#外挂QQ找茬辅助源码,早期开发 - Kovin - 博客园

mikel阅读(1147)

[转载]C#外挂QQ找茬辅助源码,早期开发 – Kovin – 博客园.

这是一款几年前开发的工具,当年作为一民IT纯屌,为了当年自己心目中的一位女神熬夜开发完成。女神使用后找茬等级瞬间从眼明手快升级为三只眼。。。每次看到这个就会想起那段屌丝与女神的回忆。今天特地把代码更新了一下,支持最新版的《大家来找茬》。下面上运行的截图,源码在本文最后(对不起了,与我对战的那位玩家)

这个工具的主要运行流程很简单:游戏截图-》比较图片-》标记图片不同点
记得当时处理程序截图和比较图片的时候比较麻烦,下面是截图的处理类ScreenCapture:

///
/// 提供全屏和指定窗口的截图 以及保存为文件的类
///

public class ScreenCapture
{
///
/// 全屏截图
///

///
public Image CaptureScreen()
{
return CaptureWindow(User32.GetDesktopWindow());
}
///
/// 指定窗口截图
///

///窗口句柄. (在windows应用程序中, 从Handle属性获得) ///
public Image CaptureWindow(IntPtr handle)
{
IntPtr hdcSrc = User32.GetWindowDC(handle);
User32.RECT windowRect = new User32.RECT();
User32.GetWindowRect(handle, ref windowRect);
int width = windowRect.right - windowRect.left;
int height = windowRect.bottom - windowRect.top;
IntPtr hdcDest = GDI32.CreateCompatibleDC(hdcSrc);
IntPtr hBitmap = GDI32.CreateCompatibleBitmap(hdcSrc, width, height);
IntPtr hOld = GDI32.SelectObject(hdcDest, hBitmap);
GDI32.BitBlt(hdcDest, 0, 0, width, height, hdcSrc, 0, 0, GDI32.SRCCOPY);
GDI32.SelectObject(hdcDest, hOld);
GDI32.DeleteDC(hdcDest);
User32.ReleaseDC(handle, hdcSrc);
Image img = Image.FromHbitmap(hBitmap);
GDI32.DeleteObject(hBitmap);
return img;
}
///
/// 指定窗口截图 保存为图片文件
///

/////////public void CaptureWindowToFile(IntPtr handle, string filename, ImageFormat format)
{
Image img = CaptureWindow(handle);
img.Save(filename, format);
}
///
/// 全屏截图 保存为文件
///

//////public void CaptureScreenToFile(string filename, ImageFormat format)
{
Image img = CaptureScreen();
img.Save(filename, format);
}

///
/// 辅助类 定义 Gdi32 API 函数
///

private class GDI32
{

public const int SRCCOPY = 0x00CC0020;
[DllImport("gdi32.dll")]
public static extern bool BitBlt(IntPtr hObject, int nXDest, int nYDest,
int nWidth, int nHeight, IntPtr hObjectSource,
int nXSrc, int nYSrc, int dwRop);
[DllImport("gdi32.dll")]
public static extern IntPtr CreateCompatibleBitmap(IntPtr hDC, int nWidth,
int nHeight);
[DllImport("gdi32.dll")]
public static extern IntPtr CreateCompatibleDC(IntPtr hDC);
[DllImport("gdi32.dll")]
public static extern bool DeleteDC(IntPtr hDC);
[DllImport("gdi32.dll")]
public static extern bool DeleteObject(IntPtr hObject);
[DllImport("gdi32.dll")]
public static extern IntPtr SelectObject(IntPtr hDC, IntPtr hObject);
}

///
/// 辅助类 定义User32 API函数
///

private class User32
{
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
}
[DllImport("user32.dll")]
public static extern IntPtr GetDesktopWindow();
[DllImport("user32.dll")]
public static extern IntPtr GetWindowDC(IntPtr hWnd);
[DllImport("user32.dll")]
public static extern IntPtr ReleaseDC(IntPtr hWnd, IntPtr hDC);
[DllImport("user32.dll")]
public static extern IntPtr GetWindowRect(IntPtr hWnd, ref RECT rect);
}
}

图片比较类ImageComparer:

///
/// 图像比较.用于找出两副图片之间的差异位置
///

public class ImageComparer
{
///
/// 图像颜色
///

[StructLayout(LayoutKind.Explicit)]
private struct ICColor
{
[FieldOffset(0)]
public byte B;
[FieldOffset(1)]
public byte G;
[FieldOffset(2)]
public byte R;
}

///
/// 按5*5大小进行分块比较两个图像.
///

/////////
public static List Compare(Bitmap bmp1, Bitmap bmp2)
{
return Compare(bmp1, bmp2, new Size(5, 5));
}
///
/// 比较两个图像
///

////////////
public static List Compare(Bitmap bmp1, Bitmap bmp2, Size block)
{
List rects = new List();
PixelFormat pf = PixelFormat.Format24bppRgb;//5+1+a+s+p+x

BitmapData bd1 = bmp1.LockBits(new Rectangle(0, 0, bmp1.Width, bmp1.Height), ImageLockMode.ReadOnly, pf);
BitmapData bd2 = bmp2.LockBits(new Rectangle(0, 0, bmp2.Width, bmp2.Height), ImageLockMode.ReadOnly, pf);

try
{
unsafe
{
int w = 0, h = 0;

while (h &lt; bd1.Height &amp;&amp; h &lt; bd2.Height)
{
byte* p1 = (byte*)bd1.Scan0 + h * bd1.Stride;
byte* p2 = (byte*)bd2.Scan0 + h * bd2.Stride;

w = 0;
while (w &lt; bd1.Width &amp;&amp; w &lt; bd2.Width)
{
//按块大小进行扫描
for (int i = 0; i &lt; block.Width; i++) { int wi = w + i; if (wi &gt;= bd1.Width || wi &gt;= bd2.Width) break;

for (int j = 0; j &lt; block.Height; j++) { int hj = h + j; if (hj &gt;= bd1.Height || hj &gt;= bd2.Height) break;

ICColor* pc1 = (ICColor*)(p1 + wi * 3 + bd1.Stride * j);
ICColor* pc2 = (ICColor*)(p2 + wi * 3 + bd2.Stride * j);

if (pc1-&gt;R != pc2-&gt;R || pc1-&gt;G != pc2-&gt;G || pc1-&gt;B != pc2-&gt;B)
{
//当前块有某个象素点颜色值不相同.也就是有差异.

int bw = Math.Min(block.Width, bd1.Width - w);
int bh = Math.Min(block.Height, bd1.Height - h);
rects.Add(new Rectangle(w, h, bw, bh));

goto E;
}
}
}
E:
w += block.Width;
}

h += block.Height;
}
}
}
finally
{
bmp1.UnlockBits(bd1);
bmp2.UnlockBits(bd2);
}

return rects;
}
}

QQ找茬辅助源码下载:http://www.fangsi.net/archives/742.html