今天做了一个简单的应用,大致是向服务器请求一张图片,然后点击跳转到另外一个界面上使得这张图片可以自由伸缩。
首先是在ActivityA中请求图片,使用Ajax请求,代码如下所示。
// 2014.5.12晚
AQuery aq = new AQuery(RepairInfoDetail.this);
mViewPhotoText = (TextView) findViewById(R.id.photoText);
mViewPhotoText.setText("现场照片:拍摄于" + map.get("reportTime").toString().substring(0, 10));
aq.id(R.id.inspectionPhoto).image(map.get("inspectionPhoto").toString(), true, true, 200, 0);
而后手机上会显示一个小图片,给用户看的时候反馈这个图片有点小,应该有放大功能,根据需求最终决定跳转到另一个ActivityB中。这里问题出来了:在新的界面上再次请求图片,会导致图片的重复下载,加载过程还特别慢;如果可以将bitmap这个对象直接通过bundle存储、传到另一个界面,就省了之前的问题。
之前用的方法并不是AQuery,而是流和多线程操作的方法(上一篇文章应该写过),因此bitmap可以轻松获得。但在传递bitmap的时候,发现Activity无论如何传递,都很容易报OOP的错误(Out of Memory,内存溢出),图片文件过大,即便整成流还是整成全局变量都容易出错。因此Activity传递bitmap对象这种思路被彻底否定。
通过查Android文档,AQuery已经给好了很完整有效的缓存机制,大致意思如下:如果某次请求服务器已经根据某url请求了对应的图片资源,那么在下次请求这个图片资源时,该url会自动被AQuery识别并从缓存中读取,而不是再次请求服务器。这样就不存在图片重复下载、加载过程慢的问题了。
OK,这样Activity跳转过程结束,新的Activity也同样通过AQuery得到图片并加载到了layout中的imageview控件中。问题是,如何获得bitmap对象以进一步适用图片伸缩等操作的代码?
从AQuery那段代码可以看到aq方法直接将url对应的图片文件加载到了R.id.inspectionPhoto对应的控件当中,并没有显示出现bitmap对象。找了很多种方法,最后发现aq这个方法竟然有callback!而callback恰好是bitmapAjaxCallback!好吧,复写callback函数,就可以对bitmap做任何事情了。
两段完整代码如下:
package ouc.sei.civil_defend.ui;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import com.androidquery.AQuery;
import ouc.sei.civil_defend.R;
import android.app.Activity;
import android.app.DownloadManager.Query;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
/**
* 某条维修信息细节查看
*
* @author GloryZSG
*
*/
public class RepairInfoDetail extends Activity {
private TextView repairname;
private TextView repairtype;
private TextView repairlevel;
private TextView repairtime;
private TextView districtName;
private ImageView mImgViewPhoto;
private Bitmap mybitmap;
private TextView mViewAppearance;
private TextView mViewElectricity;
private TextView mViewSound;
private TextView mViewWorkState;
private TextView mViewPhotoText;
private Handler handler;
private Bitmap bm;
private HashMap<String,Object> map;
//----------------------
private Button imageButton;
@SuppressWarnings("unchecked")
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setContentView(R.layout.repairinfodetail);
handler = new Handler();
map = new HashMap<String,Object>();
try {
Bundle bundle = getIntent().getExtras();
Serializable data = bundle.getSerializable("repairinfo");
if (data != null) {
map = (HashMap<String, Object>)data;
} else {
return;
}
} catch (Exception e) {
e.printStackTrace();
}
//final String checkid= map.get("id").toString();
// 设备名称
repairname = (TextView) findViewById(R.id.repairname);
repairname.setText("设备名称:" + map.get("equipmentName").toString());
// 设备类型
repairtype = (TextView) findViewById(R.id.repairtype);
repairtype.setText("设备类型:" + map.get("regionalType").toString());
districtName = (TextView) findViewById(R.id.districtName);
districtName.setText("所在区域:" + map.get("districtName").toString());
repairlevel=(TextView) findViewById(R.id.repairlevel);
repairlevel.setText("故障级别:"+map.get("faultLevel").toString());
repairtime=(TextView) findViewById(R.id.inspector);
repairtime.setText("巡查人员:"+map.get("inspector").toString());
repairtime=(TextView) findViewById(R.id.repairtime);
repairtime.setText("巡查时间:"+map.get("reportTime").toString());
mViewAppearance = (TextView) findViewById(R.id.appearance);
mViewAppearance.setText("外观状况:" + map.get("appearance").toString());
mViewElectricity = (TextView) findViewById(R.id.electricity);
mViewElectricity.setText("通电情况:" + map.get("electricity").toString());
mViewSound=(TextView) findViewById(R.id.sound);
mViewSound.setText("声音测试:" + map.get("sound").toString());
mViewWorkState=(TextView) findViewById(R.id.workState);
mViewWorkState.setText("运转状态:" + map.get("workState").toString());
// 好开心啊,又学新知识了! 2014.5.12晚
AQuery aq = new AQuery(RepairInfoDetail.this);
mViewPhotoText = (TextView) findViewById(R.id.photoText);
mViewPhotoText.setText("现场照片:拍摄于" + map.get("reportTime").toString().substring(0, 10));
aq.id(R.id.inspectionPhoto).image(map.get("inspectionPhoto").toString(), true, true, 200, 0);
// if(bm != null) {
// mViewPhotoText.setText("现场照片:拍摄于" + map.get("reportTime").toString().substring(0, 10));
// imageButton.setVisibility(View.VISIBLE);
// }
// else {
// mViewPhotoText.setText("现场照片:暂无");
// }
// // 关联布局控件,加载到布局文件中
// mImgViewPhoto = (ImageView) findViewById(R.id.inspectionPhoto);
// mImgViewPhoto.setImageBitmap(bm);
// new Thread() {
// public void run() {
(2014.5.1第一种方法)通过服务器返回的图片url,再次向服务器请求,添加动态新闻图片
读取Bitmap图片
// try {
// AQuery aq = new AQuery(RepairInfoDetail.this);
// URL url;
// url = new URL(map.get("inspectionPhoto").toString());
// HttpURLConnection conn = (HttpURLConnection) url.openConnection();
// // aq.id(R.id.inspectionPhoto).image(map.get("inspectionPhoto").toString(), true, true, 200, 0);
// InputStream is = conn.getInputStream();
// bm = BitmapFactory.decodeStream(is);
//
// } catch (MalformedURLException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// } catch (IOException e) {
// e.printStackTrace();
// }
// handler.post(runnableUI);
// }
// }.start();
//
//
// imageButton.setVisibility(View.VISIBLE);
imageButton = (Button) findViewById(R.id.imageButton);
imageButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
Intent intent = new Intent();
intent.setClass(RepairInfoDetail.this, RepairImage.class);
intent.putExtra("bitmap", map.get("inspectionPhoto").toString());
startActivity(intent);
}
});
}
//
// /**
// * 读取图片的线程
// *
// * @author GloryZSG
// */
// Runnable runnableUI = new Runnable() {
// public void run() {
// // (2014.5.1第一种方法)通过服务器返回的图片url,再次向服务器请求,添加动态新闻图片
// // 读取Bitmap图片
// // 加载到布局文件中
// // 调整现场照片信息
// mViewPhotoText = (TextView) findViewById(R.id.photoText);
// if(bm != null) {
// mViewPhotoText.setText("现场照片:拍摄于" + map.get("reportTime").toString().substring(0, 10));
// imageButton.setVisibility(View.VISIBLE);
// }
// else {
// mViewPhotoText.setText("现场照片:暂无");
// }
// // // 关联布局控件,加载到布局文件中
// mImgViewPhoto = (ImageView) findViewById(R.id.inspectionPhoto);
// mImgViewPhoto.setImageBitmap(bm);
//
// }
// };
@Override
public void onDestroy() {
if(mybitmap!=null && !mybitmap.isRecycled())
mybitmap.recycle();
super.onDestroy();
}
}
以上这段中屏蔽的关于多线程和流请求的代码没有删,这只是另外一种方法。
以下是另外一个Activity。
package ouc.sei.civil_defend.ui;
import com.androidquery.AQuery;
import com.androidquery.callback.BitmapAjaxCallback;
import com.androidquery.callback.AjaxStatus;
import ouc.sei.civil_defend.R;
import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.graphics.RectF;
import android.util.DisplayMetrics;
import android.util.FloatMath;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.ImageView;
public class RepairImage extends Activity implements OnTouchListener{
public static final int RESULT_CODE_NOFOUND = 200;
Matrix matrix = new Matrix();
Matrix savedMatrix = new Matrix();
DisplayMetrics dm;
ImageView imgView;
Bitmap bitmap;
/** 最小缩放比例*/
float minScaleR = 1.0f;
/** 最大缩放比例*/
static final float MAX_SCALE = 10f;
/** 初始状态*/
static final int NONE = 0;
/** 拖动*/
static final int DRAG = 1;
/** 缩放*/
static final int ZOOM = 2;
/** 当前模式*/
int mode = NONE;
PointF prev = new PointF();
PointF mid = new PointF();
float dist = 1f;
private String url;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.repairimage);
// 获取图片资源
Intent intent = getIntent();
url = intent.getStringExtra("bitmap");
imgView= (ImageView) findViewById(R.id.repairImageView);
AQuery aq = new AQuery(RepairImage.this);
aq.id(R.id.repairImageView).image(url, true, true, 400, 0,new BitmapAjaxCallback(){
@Override
public void callback(String url, ImageView iv, Bitmap bm, AjaxStatus status){
bitmap=bm;
imgView.setImageBitmap(bitmap);
imgView.setOnTouchListener(RepairImage.this);// 设置触屏监听
dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);// 获取分辨率
minZoom();
center();
System.out.println(matrix.toString());
imgView.setImageMatrix(matrix);
}
});
}
public void SureOnClick(View v)
{
}
/**
* 触屏监听
*/
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction() & MotionEvent.ACTION_MASK) {
// 主点按下
case MotionEvent.ACTION_DOWN:
savedMatrix.set(matrix);
prev.set(event.getX(), event.getY());
mode = DRAG;
break;
// 副点按下
case MotionEvent.ACTION_POINTER_DOWN:
dist = spacing(event);
// 如果连续两点距离大于10,则判定为多点模式
if (spacing(event) > 10f) {
savedMatrix.set(matrix);
midPoint(mid, event);
mode = ZOOM;
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
//savedMatrix.set(matrix);
break;
case MotionEvent.ACTION_MOVE:
if (mode == DRAG) {
matrix.set(savedMatrix);
matrix.postTranslate(event.getX() - prev.x, event.getY()
- prev.y);
} else if (mode == ZOOM) {
float newDist = spacing(event);
if (newDist > 10f) {
matrix.set(savedMatrix);
float tScale = newDist / dist;
matrix.postScale(tScale, tScale, mid.x, mid.y);
}
}
break;
}
//if(imgView)
imgView.setImageMatrix(matrix);
CheckView();
return true;
}
/**
* 限制最大最小缩放比例,自动居中
*/
private void CheckView() {
float p[] = new float[9];
matrix.getValues(p);
if (mode == ZOOM) {
if (p[0] < minScaleR) {
//Log.d("", "当前缩放级别:"+p[0]+",最小缩放级别:"+minScaleR);
matrix.setScale(minScaleR, minScaleR);
}
if (p[0] > MAX_SCALE) {
//Log.d("", "当前缩放级别:"+p[0]+",最大缩放级别:"+MAX_SCALE);
matrix.set(savedMatrix);
}
}
center();
}
/**
* 最小缩放比例,最大为100%
*/
private void minZoom() {
minScaleR = Math.min(
(float) dm.widthPixels / (float) bitmap.getWidth(),
(float) dm.heightPixels / (float) bitmap.getHeight());
System.out.println(minScaleR);
if (minScaleR < 1.0) {
matrix.postScale(minScaleR, minScaleR);
}
}
private void center() {
center(true, true);
}
/**
* 横向、纵向居中
*/
protected void center(boolean horizontal, boolean vertical) {
Matrix m = new Matrix();
m.set(matrix);
RectF rect = new RectF(0, 0, bitmap.getWidth(), bitmap.getHeight());
m.mapRect(rect);
float height = rect.height();
float width = rect.width();
float deltaX = 0, deltaY = 0;
if (vertical) {
// 图片小于屏幕大小,则居中显示。大于屏幕,上方留空则往上移,下方留空则往下移
int screenHeight = dm.heightPixels;
if (height < screenHeight) {
deltaY = (screenHeight - height) / 2 - rect.top;
} else if (rect.top > 0) {
deltaY = -rect.top;
} else if (rect.bottom < screenHeight) {
deltaY = imgView.getHeight() - rect.bottom;
}
}
if (horizontal) {
int screenWidth = dm.widthPixels;
if (width < screenWidth) {
deltaX = (screenWidth - width) / 2 - rect.left;
} else if (rect.left > 0) {
deltaX = -rect.left;
} else if (rect.right < screenWidth) {
deltaX = screenWidth - rect.right;
}
}
matrix.postTranslate(deltaX, deltaY);
}
/**
* 两点的距离
*/
private float spacing(MotionEvent event) {
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
return FloatMath.sqrt(x * x + y * y);
}
/**
* 两点的中点
*/
private void midPoint(PointF point, MotionEvent event) {
float x = event.getX(0) + event.getX(1);
float y = event.getY(0) + event.getY(1);
point.set(x / 2, y / 2);
}
}