今天做了一个简单的应用,大致是向服务器请求一张图片,然后点击跳转到另外一个界面上使得这张图片可以自由伸缩。
首先是在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); } }
bitmap使用全程记录