JAVA-ANDROID

package com.cpm.demo.meilishuo.app.views.PhotoViewGroup;

import java.io.InputStream;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import com.cpm.demo.meilishuo.R;
import com.cpm.demo.meilishuo.SimulateData;
import com.cpm.demo.meilishuo.app.views.PhotoScrollView;
import com.cpm.demo.meilishuo.app.views.eClass;
import com.cpm.demo.meilishuo.app.views.gClass;
import com.cpm.demo.meilishuo.app.views.iClass;
import com.cpm.demo.meilishuo.app.views.q_Interface;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;

/**
 * @作者:陈培敏
 * @创建时间:2012-8-28 下午11:56:20 (1)四个方法中用到:Rect.intersects
 */
public class PhotoViewGroup extends ViewGroup {//com.meilishuo.app.views.b
	private static boolean  isShowLog=false;
	String TAG = PhotoViewGroup.class.getName();
	String TAG2 = PhotoViewGroup.class.getName()+"2";
	String TAG3 = PhotoViewGroup.class.getName()+"3";
	private Context context;// a
	private int imageWidth;// 固定的图片宽度,b
	private ExecutorService executorService;// d
	private List<ImageInfo> list = new ArrayList();// e,要显示的ImageInfo列表,跟map的区别是,(1)list中数据可能有重复;(2)list直接放入内存中;(3)map采用软引用
	private Map<Integer, SoftReference> map = new HashMap();// f,
	private ReferenceQueue refQueue = new ReferenceQueue();
	/** 三张图片top位置 **/
	private int[] tops = new int[3];// h
	/** 三张图片left位置 **/
	private int[] lefts = new int[3];// i
	private PhotoScrollView photoScriollView;// j
	private Paint paint;// 作用是什么呢?k
	private final int imageSpace = 10;// 图片之间的间隔
//		  private int l;
//		  private final int m = 0;
//		  private final int n = 1;
		  private int o_datatype;
//		  private boolean p = false;
//		  private View.OnClickListener q;
	/**点击的效果**/
	private View.OnClickListener r = new ImageDataViewClickListener(this);

	/***   **/
	public PhotoViewGroup(Context context) {
		super(context);
		this.context = context;
		if(isShowLog)if(isShowLog) Log.d(TAG, "PhotoShowView=>宽度" + getWidth());
	}

	/*** 测试数据 **/
	public void test_SimulateData() {
		this.setBackgroundColor(Color.GREEN);
		ImageInfo pi = new ImageInfo();
		pi.rect = new Rect(10, 10, 100, 120);
		pi.width = 20;
		pi.height = 20;
		//
		ImageDataView imageData = new ImageDataView(context);
		imageData.setBitmap(SimulateData.getImageRefBitmap(context));
		imageData.setTag(pi);
		pi.imageData = imageData;
		/** 以下如果没有图片,讲通过http获取,所以才需要post线程获取 **/
		post(new ImageAddRunnable(this, pi));
	}

	/***   **/
	@Override
	protected void onLayout(boolean changed, int l, int t, int r, int b) {
		if(isShowLog) if(isShowLog) Log.d(TAG, "=>onLayout=>getChildCount():" + getChildCount());
		for (int i = 0; i < getChildCount(); ++i) {
			View childView = getChildAt(i);
			Rect rect = ((ImageInfo) childView.getTag()).rect;
			childView.layout(rect.left, rect.top, rect.right, rect.bottom);
		}
	}

	/***   **/
	@Override
	protected final void onMeasure(int paramInt1, int paramInt2) {
		if(isShowLog) if(isShowLog) Log.d(TAG,"onMeasure=>传递过参数:" + paramInt1 + "-" + paramInt2+ "=>getChildCount():" + getChildCount() + ";屏幕宽度"+ this.getWidth());
		super.onMeasure(paramInt1, paramInt2);
		for (int i2 = 0; i2 < getChildCount(); ++i2) {
			View localView = getChildAt(i2);
			ImageInfo localba = (ImageInfo) localView.getTag();
			localView.measure(View.MeasureSpec.makeMeasureSpec(0,
					View.MeasureSpec.EXACTLY), View.MeasureSpec
					.makeMeasureSpec(0, View.MeasureSpec.EXACTLY));
			System.out.println("onMeasure=>childView参数:" + localba.width + "-"
					+ localba.height);
		}
		int i4 = 0;//获取top最大值
		for (int i = 0; i < this.tops.length; ++i) {
			if (i4 < this.tops[i]) {
				i4 = this.tops[i];
			} else {
				
			}
		}
		System.out.println("onMeasure=>setMeasuredDimension参数:"
				+ View.MeasureSpec.getSize(paramInt1) + "-" + i4);
		// 指定该控件在屏幕上的大小
		super.setMeasuredDimension(View.MeasureSpec.getSize(paramInt1), i4);
	}
	/**初始化PhotoScriollView、list以及各个变量值<br/>
	 * (1)在MainHotActivity的a()调用到<br/>
	 * (2)在加入数据前,一定要执行此方法*/
	public final void intiDefaultData() {// public final void a()
		if(isShowLog) if(isShowLog) Log.d(TAG, "================================获取不到宽度,我手动添加!测试长高=>width:" + this.getWidth() + ",height:"+ this.getHeight());
		q_Interface localq = this.photoScriollView.a();
		this.photoScriollView.a(null);
		this.photoScriollView.scrollTo(0, 0);
		//this.list.clear();
		//if(isShowLog) if(isShowLog) Log.d(TAG3, "this.list.clear()");
		//initVariable(getWidth());//为什么获取不到width
		
		initVariable(540);
		if (this.executorService != null) {
			this.executorService.shutdownNow();
			this.executorService = Executors.newFixedThreadPool(5);
		}
		removeAllViews();
		// this.p = false;
		this.photoScriollView.a(localq);
	}

	private void initVariable(int screenWidth) {// private void b(int paramInt)
		this.imageWidth = ((screenWidth - imageSpace * 4) / 3);
		for (int i = 0; i < this.tops.length; ++i)
			this.tops[i] = 0;// 初始化,不固定的
		for (int i = 0; i < this.lefts.length; ++i)
			this.lefts[i] = (imageSpace * (i + 1) + i * this.imageWidth);// 初始化left位置,固定的
		if (true) {
			this.paint = new Paint();
			this.paint.setColor(-2236963);
			this.paint.setStyle(Paint.Style.STROKE);
			this.paint.setStrokeWidth(1.0F);
			return;
		}
	}
	/***
	 * (1)在滚动时候,要加载数据,会报错:java.util.ConcurrentModificationException
	 * 		如果方法加入synchronized,就不会报错,但view空出一个区域出来(滚动速度稍微快点)。
	 * (2)
	 * @param imageInfos
	 */
	public final  void loadList(List<ImageInfo> imageInfos) {// public final void  a(List paramList)
		if(isShowLog) if(isShowLog) Log.d(TAG, "loadList,start=>图片列表大小:" + imageInfos.size() + "=>getChildCount:"+ this.getChildCount() + "=>屏幕宽度:" + this.getWidth());
		this.o_datatype = 30020;
		
		// this.o = 30020;
		Iterator localIterator = imageInfos.iterator();
		ImageInfo imageInfo = null;
		while (localIterator.hasNext()) {
			imageInfo = (ImageInfo) localIterator.next();
			Rect localRect = new Rect();
			// 找出top最小值和位置
			int minTopValue = this.tops[0];
			int minPos = 0;
			for (int i3 = 1; i3 < this.tops.length; i3++) {
				if(isShowLog) if(isShowLog) Log.d(TAG, "loadList,比较tops:"+i3+"=>minTopValue:"+minTopValue+"=>tops["+i3+"]:"+this.tops[i3]);
				if (minTopValue <= this.tops[i3])
					continue;
				else {
					minTopValue = this.tops[i3];
					minPos = i3;
				}
			}
			if(isShowLog) if(isShowLog) Log.d(TAG, "loadList,最低位置:"+minPos+"=>对于的值:"+tops[minPos]);
			
			{
				// 自己添加的缩放比例;或放在加载时间时候判断;甚至也放在服务器上。
				imageInfo.height = this.imageWidth * imageInfo.height / imageInfo.width;
				imageInfo.width = this.imageWidth;
			}
			this.tops[minPos] = (imageSpace + this.tops[minPos]);//

			localRect.left = this.lefts[minPos];
			localRect.top = this.tops[minPos];
			localRect.right = (imageInfo.width + this.lefts[minPos]);
			localRect.bottom = (this.tops[minPos] + imageInfo.height);
			// 赋值布局区域
			imageInfo.rect = localRect;
			// 因为添加一张图片,所以tops[minPos]变高了
			this.tops[minPos] += imageInfo.height;
			// 加入列表
			this.list.add(imageInfo);
			if(isShowLog) if(isShowLog) Log.d(TAG3, "this.list.add(imageInfo);");
			if(isShowLog) if(isShowLog) Log.d(TAG, "loadList=>返回imageInfo.rect值:" + localRect.left + "-"
					+ localRect.top + "-" + localRect.right + "-"
					+ localRect.bottom);
			// 判断两个rect是否相交,有的话就显示处理
			// if
			// ((Rect.intersects(getCanLookRect(this.photoScriollView.getScrollY()),
			// imageInfo.rect))){
			// // 注意下反编译代码
			// loadImage(imageInfo, true);
			// //return; or continue;
			// }else{
			// if(isShowLog) if(isShowLog) Log.d(TAG, "loadList=>区域是没有交叉,未执行加载图片");
			// continue;
			// }
			loadImage(imageInfo, true);
		}
	}
	/**
	 * 加载数据
	 * @param paramList
	 * @param paramInt
	 */
	public final void loadList(List paramList, int paramInt){//public final void a(List paramList, int paramInt)
		this.o_datatype = paramInt;
		loadList(paramList);
	}
	/***
	 * 在屏幕上能看到的区域<br/>
	 * 终于搞懂了!!必须要知道:
	 * (1)getTop的含义(相对父View)
	 * (2)getScrollY()的含义
	 * (3)PhotoViewGroup放在PhotoScrollView里面,所以产生滚动条是PhotoScrollView。
	 *   滚动条在最下面的时候,会往PhotoViewGroup自动加入数据,所以PhotoViewGroup会变得原来越长了,
	 *   而PhotoViewGroup看不到的数据,在PhotoScrollView最上面,那哪些数据能看到呢?此方法就是计算能看到的区域
	 * (4)通过允许,就可以看到区域left肯定0,right就是宽度,top通过_top判断的,bottom通过top和height判断的
	 * @param _top   意思是PhotoViewGroup头部距离PhotoScrollView头部的距离
	 * @return
	 */
	private Rect getCanLookRect(int _top) {// private Rect c(int paramInt)
		// if(isShowLog) Log.d(TAG,
		// "了解getTop与getScrollY的=>getTop:"+this.getTop()+"--getScrollY:"+this.getScrollY());
		int height = this.photoScriollView.getHeight();// 注意这个是photoScriollView高度,而不是调用this.getHeight()
		int i3 = 0;
		;
		if (_top < getTop()) {// 这时候PhotoShowView头部都可以在屏幕上看到,出现这样子原因是photoScriollView还有其他view在PhotoShowView上面
			int i4 = height - (getTop() - _top);
			if(isShowLog) Log.d(TAG2, "getCanLookRect=>返回Rect值1:" + getLeft() + "-" + i3 + "-"+ getRight() + "-" + i4 + "=>宽度:" + this.getWidth()
					+ "=>高度:" + this.getHeight()+"=>"+_top);
			return new Rect(getLeft(), i3, getRight(), i4);// getLeft()、getRight()固定,所以只关心上和下
		} else {// 这时候PhotoShowView头部都在屏幕上看不到
			i3 = _top - getTop();
			int i4 = i3 + height;// 放在这边,还是上面那句呢?
			if(isShowLog) Log.d(TAG2, "getCanLookRect=>返回Rect值2:" + getLeft() + "-" + i3 + "-"+ getRight() + "-" + i4 + "=>宽度:" + this.getWidth()
					+ "=>高度:" + this.getHeight()+"=>"+_top);
			return new Rect(getLeft(), i3, getRight(), i4);
		}
	}

	private void loadImage(ImageInfo imageInfo, boolean isGetFromHttp) {// private void a(ba paramba, boolean paramBoolean)
		if(isShowLog) Log.d(TAG, "执行方法loadImage----------------开始------------");
		if (imageInfo.imageData == null) {
			// 首次运行的时候,每一张图片信息的imageData都为空的。则要实例下(没有图片数据呢,先占用图片空间,然后图片再从http下载或从SD中加载)
			if(isShowLog) Log.d(TAG, "执行方法loadImage,构建空的图片");
			ImageDataView imageData = new ImageDataView(this.context);
			imageData.setTag(imageInfo);
			imageInfo.imageData = imageData;
			imageData.setOnClickListener(this.r);// 点击的操作,暂时不设置吧
			post(new ImageAddRunnable(this, imageInfo));
		}
		if(!isGetFromHttp)return;
		imageInfo.hasLoaded=true;
		if (true) {
			Bitmap localBitmap1 = null;
			if (this.map.get(Integer.valueOf(imageInfo.id)) != null) {
				localBitmap1 = (Bitmap) ((SoftReference) this.map.get(Integer.valueOf(imageInfo.id))).get();
				if(isShowLog) Log.d(TAG, "执行方法loadImage,成功从map获取数据,这次没通过SD卡或HTTP获取数据");
			}
			if (localBitmap1 == null) {
				/**
				 * 根据反编译信息,可以看出原理(设计太多类,不用了): (1)通过imageInfo.url获取MD5唯一数据标志
				 * =>e.java (2)定义图片的字节数组imgByte
				 * (3)从缓存(其实是从SD卡获取之前保持的数据)中获取数据赋值给imgByte =>i.java
				 * (4)获取没有缓存,则只能从http获取了 => 本类a(imageInfo)方法
				 **/
				String md5Url = null;// 获取MD5唯一数据标志
				byte[] arrayOfByte = null;
				// 从SD卡获取图片数据=>什么时候存储SD数据呢,答案是在下载的时候,存储SD卡中
				// if (iClass.a(md5Url)) {//如果文件存在
				// arrayOfByte = iClass.b(md5Url);//从SD卡获取之前保持的数据
				// if ((arrayOfByte == null) || (arrayOfByte.length ==
				// 0))//如果获取的数据位空
				// iClass.c(str);//删除该文件
				// }
				if ((arrayOfByte == null) || (arrayOfByte.length == 0)) {
					downImageByHttp(imageInfo);// 图片为空启动下载,第一次加载都会首先执行这个
				} else {// 没从SD卡获取,所以这里都还没执行
					Bitmap localBitmap2 = createScaledBitmapByByte(arrayOfByte,
							this.imageWidth);// 根据图片字节 伸缩图片
					if (localBitmap2 == null) {
						// i.c(new String(e.a(paramba.e.getBytes())));
						// //删除SD中的文件。paramba.e是ImageInfo.url
						downImageByHttp(imageInfo);// 找不到图片,则启动下载
					}
					if(isShowLog) Log.d(TAG, "loadImage=>addMap=>" + localBitmap2);
					addMap(imageInfo.id, localBitmap2);
					imageInfo.imageData.setBitmap(localBitmap2);
				}
			} else {
				imageInfo.imageData.setBitmap(localBitmap1);
			}
		}
	}

	/** 通过字节转换Bitmap,且固定width高度自动伸缩。注意这个方法是static **/
	private static Bitmap createScaledBitmapByByte(byte[] paramArrayOfByte,
			int width) {// private static Bitmap b(byte[] paramArrayOfByte, int
						// paramInt)
		Bitmap localBitmap1 = BitmapFactory.decodeByteArray(paramArrayOfByte,
				0, paramArrayOfByte.length);
		if(isShowLog) Log.d("com.cpm.demo.meilishuo.myview.PhotoShowView",
				"createBitmapByByte1=>要显示的width:" + width + "=>图片高度:"
						+ localBitmap1.getHeight() + "=>图片宽度:"
						+ localBitmap1.getWidth() + "=>" + localBitmap1);
		Bitmap localBitmap2 = null;
		if (localBitmap1 != null) {
			localBitmap2 = Bitmap.createScaledBitmap(localBitmap1, width, width
					* localBitmap1.getHeight() / localBitmap1.getWidth(), true);
			localBitmap1.recycle();
		}
		if(isShowLog) Log.d("com.cpm.demo.meilishuo.myview.PhotoShowView",
				"createBitmapByByte2=>要显示的width:" + width + "=>图片高度:"
						+ localBitmap2.getHeight() + "=>图片宽度:"
						+ localBitmap2.getWidth() + "=>" + localBitmap2);
		return localBitmap2;
	}

	/** 往map加入图片源,map格式是SoftReference **/
	protected void addMap(int id, Bitmap bitmap) {// private void a(int
													// paramInt, Bitmap
													// paramBitmap)
		synchronized (this.map) {
			if (this.map.containsKey(Integer.valueOf(id))) {
				return;
			}
			this.map.put(Integer.valueOf(id), new SoftReference(bitmap,
					this.refQueue));
			checkMap();
		}
	}

	/** 通过http下载图片 **/
	private void downImageByHttp(ImageInfo paramba) {// private void a(ba
														// paramba)
		if(isShowLog) Log.d(TAG, "执行方法downImageByHttp");
		// 反编译认真看下
		if (paramba.httpCilent == null) {
			ImageDownloadRunnable localay = new ImageDownloadRunnable(this,
					paramba);
			if (this.executorService == null)
				this.executorService = Executors.newFixedThreadPool(5);
			this.executorService.execute(localay);
		}
	}

	/* 作用? */
	private void checkMap() {// b();
		/**
		 * SoftReference localSoftReference = (SoftReference)
		 * this.refQueue.poll(); Map.Entry localEntry = null; if
		 * (localSoftReference != null) { Iterator iterator =
		 * this.map.entrySet().iterator(); while(iterator.hasNext()){ localEntry
		 * = (Map.Entry) iterator.next(); if (localEntry!=null ) { int value =
		 * ((Integer) localEntry.getKey()).intValue(); if (value == -1)
		 * this.map.remove(Integer.valueOf(value)); return; } } }
		 **/
		label0: {
			if(isShowLog) Log.d(TAG, "checkMap()=>作用待确定");
			SoftReference localSoftReference = (SoftReference) this.refQueue
					.poll();
			Map.Entry localEntry = null;
			if (localSoftReference != null) {
				Iterator localIterator = this.map.entrySet().iterator();
				do {
					if (!(localIterator.hasNext()))
						break;
					localEntry = (Map.Entry) localIterator.next();
				} while (localEntry.getValue() != localSoftReference);
			}
			if (localEntry != null)
				for (int i1 = ((Integer) localEntry.getKey()).intValue();; i1 = -1) {
					if (i1 != -1)
						;
					this.map.remove(Integer.valueOf(i1));
					break label0;
				}
		}
	}

	private Rect getRect(int paramInt) {
		return new Rect(getLeft(), 0, getRight(), 100);
	}

	public final void setPhotoScrollView(PhotoScrollView paramPhotoScrollView) {
		this.photoScriollView = paramPhotoScrollView;
	}
	/** 
	 * 滚动条变化的时候,判断list
	 * (1)滚动条是在PhotoScrollView产生的,所以这个方法专门给PhotoScrollView的onScrollChanged方法调用
	 */
	public final  void a_optimizeListData(int paramInt) {// bClass=> public final void a(int paramInt)
		if(isShowLog) Log.d(TAG2, "方法a(int)=>list大小:"+this.list.size()+"=>宽度:"+this.getWidth()+"=>参数:"+paramInt);
		Rect localRect = this.getCanLookRect(paramInt);
		Iterator localIterator = this.list.iterator();
		if(isShowLog) Log.d(TAG3, "this.list.iterator()");
		while (localIterator.hasNext()) {
			ImageInfo localba = (ImageInfo) localIterator.next();//会报错: java.util.ConcurrentModificationException,为什么呢?原因用iterator遍历集合时要注意的地方:不可以对iterator相关的地方做添加或删除操作。  但是我在哪里操作了呢?滚动条滚动时候,此方法未执行完,再执行一次了?
			if(isShowLog) Log.d(TAG2, "方法a(int)=>id:"+localba.id+"=>是否交叉:"+Rect.intersects(localRect, localba.rect)+"=>localba.是否已加载:"+localba.hasLoaded+"---------->"+(Rect.intersects(localRect, localba.rect)?"":"-----------------------有看不见了"));
			if (localba.hasLoaded && !Rect.intersects(localRect, localba.rect)) {//已加载,且没有交叉,图片设空,节约内存吧?
				localba.hasLoaded = false;//从list获取出来对象,再对对象修改属性,这个时候list对象也会修改的。
				if (localba.httpCilent != null) {
					ImageDownloadRunnable.HttpCilent(localba.httpCilent);//作用?
					localba.httpCilent = null;
				}
				localba.imageData.setBitmap(null);
			}
//			if ((localba.isGetFromHttp) || (!(Rect.intersects(localRect, localba.rect))))
//				continue;
//			this.loadImage(localba, true);
			//改成下面:
			if (!localba.hasLoaded && Rect.intersects(localRect, localba.rect) )
				this.loadImage(localba, true);
		}
	}
	/**给每一张图片,画边框。其实这里可以放在ImageDataView了,没必要在这里设置,因为ImageDataView已经有实现此功能=》红边**/
	protected final boolean drawChild(Canvas paramCanvas, View paramView,
			long paramLong) {
		Rect localRect = new Rect();
		paramView.getHitRect(localRect);
		int i1 = Math.max(0, 1);
		localRect.top -= i1;
		localRect.left -= i1;
		paramCanvas.drawRect(localRect, this.paint);
		return super.drawChild(paramCanvas, paramView, paramLong);
	}
//	  protected final void onSizeChanged(int paramInt1, int paramInt2, int paramInt3, int paramInt4)
//	  {
//	    super.onSizeChanged(paramInt1, paramInt2, paramInt3, paramInt4);
//	    if (paramInt1 == paramInt3)
//	      return;
//	    b(paramInt1);
//	  }
}

 

你可能感兴趣的:(android)