网络异步加载图片 ArrayAdapter详解


package cn.wangmeng.test;

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

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;

public class AsyncListImage extends Activity {//入口类添加了一堆图片网址
	private ListView list;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        list=(ListView)findViewById(R.id.list);
        List dataArray=new ArrayList();
        ImageAndText test=new ImageAndText("http://www.wangmeng.cn/images/logo.gif", "test");
        ImageAndText test1=new ImageAndText("http://hiphotos.baidu.com/dawn_and_sunny/pic/item/43ebc4fee8911c285c600888.jpeg", "test1");
        ImageAndText test2=new ImageAndText("http://pic-hzrb.hangzhou.com.cn/0/10/43/41/10434126_126930.jpg", "test2");
        ImageAndText test3=new ImageAndText("http://pic4.nipic.com/20090915/3035279_192853029499_2.jpg", "test2");
        ImageAndText test4=new ImageAndText("http://pica.nipic.com/2007-12-24/20071224161811448_2.jpg", "test2");
        ImageAndText test5=new ImageAndText("http://pic1.ooopic.com/uploadfilepic/sheying/2009-08-23/OOOPIC_huoying2046_200908237775bce5fc051181.jpg", "test2");
        ImageAndText test6=new ImageAndText("http://pica.nipic.com/2007-12-25/20071225135255212_2.jpg", "test2");
        ImageAndText test7=new ImageAndText("http://pic-hzrb.hangzhou.com.cn/0/10/43/41/10434126_126930.jpg", "test2");
        ImageAndText test8=new ImageAndText("http://pic8.nipic.com/20100721/5420964_204951007371_2.jpg", "test2");
        ImageAndText test9=new ImageAndText("http://pica.nipic.com/2008-05-19/200851910567179_2.jpg", "test2");
        ImageAndText test11=new ImageAndText("http://pica.nipic.com/2008-05-01/20085110421925_2.jpg", "test2");
        ImageAndText test12=new ImageAndText("http://pic3.nipic.com/20090608/1359484_170016078_2.jpg", "test2");
        ImageAndText test13=new ImageAndText("http://pic4.nipic.com/20090728/1945064_192614003_2.jpg", "test2");
        dataArray.add(test);
        dataArray.add(test1);
        dataArray.add(test2);
        dataArray.add(test3);
        dataArray.add(test4);
        dataArray.add(test5);
        dataArray.add(test6);
        dataArray.add(test7);
        dataArray.add(test8);
        dataArray.add(test9);
        dataArray.add(test11);
        dataArray.add(test12);
        dataArray.add(test13);
        ImageAndTextListAdapter adapter=new ImageAndTextListAdapter(this, dataArray, list);
        list.setAdapter(adapter);
        list.setOnItemClickListener(new OnItemClickListener() {

			@Override
			public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
					long arg3) {
				Log.e("------------", ""+arg3);
			}
		});
        
    }
}




package cn.wangmeng.test;

public class ImageAndText {//适配累,用于ListView装载内容
	    private String imageUrl;
	    private String text;

	    public ImageAndText(String imageUrl, String text) {
	        this.imageUrl = imageUrl;
	        this.text = text;
	    }
	    public String getImageUrl() {
	        return imageUrl;
	    }
	    public String getText() {
	        return text;
	    }
}




package cn.wangmeng.test;

import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;

public class ImageAndTextListAdapter extends ArrayAdapter {

	private ListView listView;
	List dataArray;
	private LayoutInflater inflater;
	Context context;
	View rowView;
	int index=0;
	Bitmap bt=null;
	public ImageAndTextListAdapter(Context context,List dataArray, ListView listView) {
		super(context, 0, dataArray);//调用父类的构造函数,第一个参数为上下文,第二个参数为每一行布局文件id,第三个参数为所要展示的数组对象
									//第三个参数本人测试--如果需要调用父类的方法才会用到如果不调用可以传空或0
									//比如getCount()调用父类方法则返回所传数组长度
		this.listView = listView;
		this.dataArray = dataArray;
		inflater = ((Activity) context).getLayoutInflater();//根据上下文得到一个LayoutInflater对象用于将布局文件转化为View
		this.context = context;

	}
	@Override
	public int getCount() {//该方法确定了所要加载类容的长度,每次点击或绘制一行系统都会调用一次该方法
		// TODO Auto-generated method stub
		int ss = dataArray.size();
		Log.i("*************:", "-getCount------"+ss);
		Log.i("*************:", "-super.getCount------"+super.getCount());
		return ss;
	}

	@Override
	public ImageAndText getItem(int position) {//本人查阅了api在最顶层的Adapter可以找到该方法,查阅过Gallery的该方法调用,
												//在继承的AdapterView父类中找到了掉用该方法的public Object getItemAtPosition(int position)方法
												//在系统中却没有找到调用public Object getItemAtPosition(int position)方法的地方
					                            //可以推断这个方法单纯是为我们调用的
												
												//在测试中该方法没被调用过因此没再对该方法做深究,相信和gallery的情况相似,不对的地方还请斧正
		// TODO Auto-generated method stub
		Log.i("*************:", "-ImageAndText------");
		return null;
	}

	@Override
	public long getItemId(int position) {		//该方法在图像绘制时调用两次position为0,没做深究原谅,其他当item被点击或
												//长按状态下会被促发,position值为你点击项的ID值也就是下标Index值,如果定式的返回
												//某个值那么在你屏幕上获得的值也会只有该值,猜想OnItemClickListener回调了该方法
		// TODO Auto-generated method stub
		Log.i("*************:", "-getItemId------"+position);
		Log.i("*************:", "-super.getItemId------"+super.getItemId(position));
		return 0;
	}
		//如果构造函数传给了需要填充数据的数组getItem(int position), getItem(int position),getItemId(int position)可以交由
		//父类调用无需在对该方法进行重写
	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		//该方法最为重要,是参与界面绘制的必须方法,首先将引用别人对该方法的解释
		
		
		
		// getView 方法中的第二个参数 convertView 有时候可能会是 null , 在这样的情况下 ,
        // 我们就必须创建一个新的 rowView(ListView 中每一个条目需要用到的 ) 。但是,如果
        // convertView 不为 null 的时候,它是什么呢?它实际上就是前面通过 inflate 方法
        // 得到的 rowView( 见下面代码 ) 。这种情况主要发生在 ListView 滚动的时候:当一个
        // 新的条目 ( 行 ) 出现的时候, Android 首先会试图重复使用被移除屏幕的那些条目所
        // 对应的 rowView 对象。由于每一行都有相同的结构,因此可以通过 findViewById 方法
        // 得到 rowView 中各个对象,根据相关的数据改变这些对象,然后将 contentView 对象
        // 返回,而不需要重新构建一个 rowView 对象。
        // 所以,在这里,我们先检查 convertView 是否为 null ,如果是 null 的,那么我们创建
        // 一个新的 rowView ,否则,我们重用 convertView 。这样做可以大大减少耗时和耗资源
        // 的 inflate 的调用。根据 2010 年 Google I/O 大会,这样做比每次都 inflate 的做法的
        // 性能快出 150% ,如果 rowView 包含的对象很复杂的话,快出 150% 也许都是低估了。

        // 另外, 这样做,还可以节省内存。如果如下面重复利用业已存在的 rowView ,那么
        // 仅需要 6 个 rowView 对象即可 ( 假定屏幕可以显示的行数是 6) ,假定每个 rowView 所占用的
        // 内存是 6kB( 有图像的时候,超过这个数字很容易 ) ,那么一共需要的内存是 36kB 。如果不
        // 采取这种重复利用的方式,在假定有 1000 行,那么所需要的内存就是 6MB 了,而且所需要
        // 的内存和 ListView 中的行数有关,这本身也不符合可扩展性的原则,容易造成性能上
        // 的不稳定。
		
		//相信大家看了已经有所理解,再次我将在对position这个值进行说明,系统每次绘制一行
		//数据时都会记录下该行的下标,如上所说系统并不是将数组所有的对象全部绘制,而是只绘制屏幕所能显示
		//到的类容,那么你能得到的position值也将只有屏幕能显示条目的具体ID,当我们上下拖拽将要
		//绘制上一条或下一条时又会触发getView(int position, View convertView, ViewGroup parent)该方法
		//此时position值为你将要绘制条目的ID值,就像本例网络异步加载图片,所有未见的图像又将重新在网上下载一次
		//然后绘制到界面,本人觉得像大量下载的数据可以开辟一个缓存区来记录下这些类容,当更新界面时判断该类容是否
		//已存在,存在的从缓存区内取,不存在的再从网上下载,以便节省时间可流量。同时根据position值变化动态
		//更新缓存区类容,
		
		
		// TODO Auto-generated method stub
		index=position;
		Log.i("fIndex:", "--"+index);
		ViewHolder holder;
		if (convertView == null) {//如果为空转化布局文件为View,在上面已经介绍了convertView的相关类容
			holder = new ViewHolder();
			convertView = inflater.inflate(R.layout.image_and_text_row, null);
			holder.text = (TextView) convertView.findViewById(R.id.text);
			holder.icon = (ImageView) convertView.findViewById(R.id.image);
			convertView.setTag(holder);//setTag是个好方法,可以记录下你需要存放的类容,也可以根据设置的标记找到该设置标记的类容
		} else {
			holder = (ViewHolder) convertView.getTag();//不为空获取我们设置的标记类容,在java开发中应该尽量避免new对象,new对象性能消耗是很大的
		}
		
		try{
			Bitmap bt = getbitmap(dataArray.get(index).getImageUrl(),index);//调用方法开启线程异步加载,实际开发中应该使用线程池来控制线程的开启和关闭
																		//在查阅资料时有人提出了这样开启线程当数组长度很大时启不是要开启等长数量的线程,
																	 //那不是很耗性能,还可能直接挂掉??相信大家看完上面的解释应该能知道,其实并没有那么夸张
			                                                         //实际上也只开启了屏幕锁能显示条目数量的线程
		}catch (Exception e) {
			// TODO: handle exception
			Log.e("outofIndex", "--"+index);
		}
		holder.icon.setTag("icon" + index);//此句很重要他记标记了我对应下载图片将要显示的ImageView,以便我下载好的图片能能再对应的地方显示
		if (bt == null) {//为空让他显示本地图片
			holder.icon.setImageResource(R.drawable.icon);
			holder.text.setText("蛋疼菊紧");
			holder.text.setTextColor(Color.WHITE);
		} else {//如果网络够快(比系统运算快,我相信此句能执行)
			holder.icon.setImageBitmap(bt);
		}
		return convertView; //返回添加了类容的View
	}

	public Bitmap getbitmap(final String url,final int index){
		
    	new Thread(){
	    	URL m;//java网络这里就不赘述了,如果有朋友不太清楚,请自己下来查找资料,我空间转载了几篇http协议的东东,很详细
	    		public void run(){
	    		InputStream i = null;
	    		try {
	    			m = new URL(url);
				i = (InputStream) m.getContent();
				BitmapFactory.Options options = new BitmapFactory.Options();
				options.inSampleSize = 5;//这里需要强调下,opitons参数设置长宽为原来的5分之1图片大小也就是原来的25分子一
										//如果你不设置,你将要小心outofMemmory的异常哦,图片够大加载类容够多的话你就死翘翘了
				 bt = BitmapFactory.decodeStream(i,null,options);
			} catch (MalformedURLException e1) {
				e1.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
		    	Message ms  =handler.obtainMessage(0, bt);
		    	ms.what = index;
		    	handler.sendMessage(ms);//发送消息给Handler更新主线程,加载下载图片刷新界面,
	    		}
	    	}.start();
		return bt;
	    }
	
	//再次再赘述下异步下载显示图片的原理
	//adapter接受一堆地址,在getView方法中开启对应的线程下载对应的图片,线程将在后台运行,此时界面上显示我们预设的图片
	//当有图片下载完成,线程结束时便发送消息给handler替换我们预设对应的图片,更新主线程,更新界面
	Handler handler = new Handler() {
        public void handleMessage(Message message) {
        	ImageView iv = (ImageView) listView.findViewWithTag("icon"+message.what);//这句就是网络朋友所说的精华所在,找到我们设置标记的ImageView,更新我们下载的图片
        	if(iv!=null){
        		iv.setImageBitmap((Bitmap) message.obj);
        	}
        }
    };
	private class ViewHolder {
		TextView text;
		ImageView icon;
	}
}




本人第一次写东东,本人初学者,不对的地方还请斧正

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值