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);
// }
}