Androi手動でリストビュー+ ImagLoader機能を実装

 
Androiを手動でリストビューImagLoader機能+実装 
 :3つの遅い概念
 キャッシュ:メモリキャッシュ、ビットマップオブジェクト、地図<文字列、ビットマップ>構造に保存し、URLを指定できます
 ローカル(SDカード)キャッシュ、キャッシュイメージファイル/ストレージ:二次キャッシュ/ SDカード/アンドロイド/のpackageName /ファイル / .pngを、
 3レベルのキャッシュ:1、2ので、サーバーからのフェッチではありません

 3つのキャッシュ疑似コード:
   1. URLキーローカルビットマップからオブジェクトを見つけるために
        、その表示をする場合が
        そうでない場合は、その後、2を入力します。

   2.二次キャッシュ、取得したビットマップSDカード見つけ
       た場合は、ディスプレイには、キャッシュバッファが
       入らない3

   今、画像のロードがある3.、サブスレッド要求ビットマップネットワーキング開始し
        ない場合は、エラー画像を
        お持ちの場合:ディスプレイ
        バッファをキャッシュに、L2キャッシュ

  
  問題:三つの画像点滅バグを使用してバッファListVieロード画像が存在する 
  理由:conterViewは、画像Aをロードするために、今、conterView Aピクチャを多重化
  、画像Bのロードに多重化されconterView B摺動後
  conterViewが多重化されていない後のスライドCが、負荷イメージにC、
  ネットワーク上の理由から、ディスプレイBに起因する、C表示、エラー表示される場合があり
  ソリューション:行くためにロード時にCを、ロードするために行っていない、Bは、現実がロードされていない場合でも、あなたはキャッシュでき
  
  
   、問題をコード解析: 

  // 1.ListView 复用,每次滑动重新绘制item都会执行
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            if(convertView==null) {
                convertView = View.inflate(MainActivity.this, R.layout.item_main, null);
            }
            imageLoader.loadImage(imagePath, imageView);
         }
         //2.Item复用以后为了可以以后  为了区分该item是否已经复用,使用保存tag方法,A用的保存A,那么B用的时候保存B
             public void loadImage(String imagePath, ImageView imageView) {
                   //将需要显示的图片url保存到视图上
              imageView.setTag(imagePath);
          }
              
             // 3.网络加载前:如果 A item被A 占据,但是此时滑动 Item已经B复用 【imageView.setTag(imagePath);】,那么不要去加载网络去图片了
                String newImagePath = (String) imageView.getTag();
                    if(newImagePath!=imagePath) {//视图已经被复用了 【imagePath 还是A的、tag是比的,这里把1,2级别缓存都可以单做综合耗时】
                        return null;
                    }
                    
                    // 4. 网络加载后,如果A item之前被A分配,网络延迟才执行完毕对于A[newImagePath], 此时已经被E复用,Tag已经E了,那么不显示A图片,把A图片缓存即可
                        String newImagePath = (String) imageView.getTag();
                if(newImagePath!=imagePath) {//视图已经被复用了
                    return;
                }

    直接地図上に: 

コードの実装: 

<uses-permission android:name="android.permission.INTERNET"></uses-permission>

データエンティティクラスのセーブ1. ShopInfo

package com.example.listimageloader;

/*
 * 商品的信息
 */
public class ShopInfo {

	private int id;
	private String name;
	private String imagepath;
	private double price;

	public ShopInfo() {
		super();
	}

	public ShopInfo(int id, String name, String imagepath, double price) {
		super();
		this.id = id;
		this.name = name;
		this.imagepath = imagepath;
		this.price = price;
	}

	public double getPrice() {
		return price;
	}

	public void setPrice(double price) {
		this.price = price;
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getImagepath() {
		return imagepath;
	}

	public void setImagepath(String imagepath) {
		this.imagepath = imagepath;
	}

	@Override
	public String toString() {
		return "ShopInfo [id=" + id + ", name=" + name + ", imagepath="
				+ imagepath + ", price=" + price + "]";
	}

}


 2. ImageLoaderフレームパッケージ

package com.example.listimageloader;

import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.SystemClock;
import android.util.Log;
import android.widget.ImageView;

/**
 * 用于加载图片并显示的类
 * @author 张晓飞
 *
 */
/*
	String iamgePath = http://192.168.10.165:8080//L05_Web/images/f10.jpg和ImageView对象
	1). 根据url从一级缓存中取对应的bitmap对象
		如果有, 显示(结束)
		如果没有, 进入2)
	2). 从二级缓存中查找: 得到文件名并在sd卡的缓存目录下加载对应的图片得到Bitmap对象
		如果有: 显示, 缓存到一级缓存中(结束)
		如果没有, 进入3)
	3). 显示代表提示正在加载的图片, 启动分线程联网请求得到Bitmap对象
			如果没有: 显示提示错误的图片(结束)
			如果有: 
				显示
				缓存到一级缓存
				缓存到二级缓存
 */
public class ImageLoader {
	
	private Context context;
	private int loadingImageRes;
	private int errorImageRes;

	public ImageLoader(Context context, int loadingImageRes, int errorImageRes) {
		super();
		this.context = context;
		this.loadingImageRes = loadingImageRes;
		this.errorImageRes = errorImageRes;
	}

	//用于缓存bitmap的容器对象
	private Map<String, Bitmap> cacheMap = new HashMap<String, Bitmap>();
	
	/**
	 * 加载图片并显示
	 * @param imagePath
	 * @param imageView
	 */
	public void loadImage(String imagePath, ImageView imageView) {
		
		//将需要显示的图片url保存到视图上
		imageView.setTag(imagePath);
		
		/*
		 1). 根据url从一级缓存中取对应的bitmap对象
			如果有, 显示(结束)
			如果没有, 进入2)
		 */
		Bitmap bitmap = getFromFirstCache(imagePath);
		if(bitmap!=null) {
			imageView.setImageBitmap(bitmap);
			return;
		}
		/*
		2). 从二级缓存中查找: 得到文件名并在sd卡的缓存目录下加载对应的图片得到Bitmap对象
				如果有: 显示, 缓存到一级缓存中(结束)
				如果没有, 进入3)
			
			/storage/sdcard/Android/data/packageName/files/图片文件名(xxx.jpg)
		 */
		bitmap = getFromSecondCache(imagePath);
		if(bitmap!=null) {
			imageView.setImageBitmap(bitmap);
			cacheMap.put(imagePath, bitmap);
			return;
		}
		
		/*
		 3). 显示代表提示正在加载的图片, 启动分线程联网请求得到Bitmap对象
			如果没有: 显示提示错误的图片(结束)
			如果有: 
				缓存到一级缓存(分线程)
				缓存到二级缓存(分线程)
				显示(主线程)
				
		 */

		loadBitmapFromThirdCache(imagePath, imageView);
	}

	/**
	 * 根据图片url从三级缓存中取对应的bitmap对象并显示
	 * @param imagePath
	 * @param imageView
	 * AsyncTask
	 * loadBitmapFromThirdCache("../b.jpg", imageView)
	 * loadBitmapFromThirdCache("../f.jpg", imageView)--->imageView.setTag("../f.jpg")
	 */
	private void loadBitmapFromThirdCache(final String imagePath, final ImageView imageView) {
		new AsyncTask<Void, Void, Bitmap>() {
			protected void onPreExecute() {
				imageView.setImageResource(loadingImageRes);
			}
			
			//联网请求得到bitmap对象
			@Override
			protected Bitmap doInBackground(Void... params) {
				//在分线程执行, 可能需要等待一定时间才会执行
				//在等待的过程中imageView中的tag值就有可能改变了
				//如果改变了, 就不应该再去加载图片(此图片此时不需要显示)
				
				Bitmap bitmap = null;
				try {
					
					//在准备请求服务器图片之前, 判断是否需要加载
					String newImagePath = (String) imageView.getTag();
					if(newImagePath!=imagePath) {//视图已经被复用了
						return null;
					}

					SystemClock.sleep(100);

					//得到连接
					URL url = new URL(imagePath);
					HttpURLConnection connection = (HttpURLConnection) url.openConnection();
					//设置
					connection.setConnectTimeout(5000);
					connection.setReadTimeout(5000);
					//连接
					connection.connect();
					//发请求读取返回的数据并封装为bitmap
					int responseCode = connection.getResponseCode();
					if(responseCode==200) {
						InputStream is = connection.getInputStream();//图片文件流
						//将is封装为bitmap
						bitmap = BitmapFactory.decodeStream(is);
						is.close();
						
						if(bitmap!=null) {
							//缓存到一级缓存(分线程)
							cacheMap.put(imagePath, bitmap);
							//缓存到二级缓存(分线程)
							// /storage/sdcard/Android/data/packageName/files/
							String filesPath = context.getExternalFilesDir(null).getAbsolutePath();
							// http://192.168.10.165:8080//L05_Web/images/f10.jpg
							String fileName = imagePath.substring(imagePath.lastIndexOf("/")+1);//  f10.jpg
							String filePath = filesPath+"/"+fileName;
							Log.e("denganzhi","filePath:"+filePath);
							// 格式
							// 透明度 jpg 没有透明度 png 有透明度
							// 质量0-100   50 压缩比例50%
							bitmap.compress(CompressFormat.JPEG, 100, new FileOutputStream(filePath));
						}
					}
					connection.disconnect();
				} catch (Exception e) {
					e.printStackTrace();
				}
				
				
				return bitmap;
			}
			
			protected void onPostExecute(Bitmap bitmap) {//从联网请求图片到得到图片对象需要一定的时间, 视图可能被复用了,不需要显示
				//在主线程准备显示图片之前, 需要判断是否需要显示
				String newImagePath = (String) imageView.getTag();
				if(newImagePath!=imagePath) {//视图已经被复用了
					return;
				}
						
				//如果没有: 显示提示错误的图片(结束)
				if(bitmap==null) {
					imageView.setImageResource(errorImageRes);
				} else {//如果有, 显示
					imageView.setImageBitmap(bitmap);
				}
			}
		}.execute();
	}

	/**
	 * 根据图片url从二级缓存中取对应的bitmap对象
	 * @param imagePath
	 * @return
	 */
	private Bitmap getFromSecondCache(String imagePath) {
		
		// /storage/sdcard/Android/data/packageName/files/
		String filesPath = context.getExternalFilesDir(null).getAbsolutePath();
		// http://192.168.10.165:8080//L05_Web/images/f10.jpg
		String fileName = imagePath.substring(imagePath.lastIndexOf("/")+1);//  f10.jpg
		String filePath = filesPath+"/"+fileName;
		
		return BitmapFactory.decodeFile(filePath);
	}

	/**
	 * 根据图片url从一级缓存中取对应的bitmap对象
	 * @param imagePath
	 * @return
	 */
	private Bitmap getFromFirstCache(String imagePath) {
		return cacheMap.get(imagePath);
	}
}


データローディングアダプタ、表示データを設定3. MainActivity

package com.example.listimageloader;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;

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

public class MainActivity extends AppCompatActivity {
    List<ShopInfo> datas=new ArrayList<>();

    private ShopInfoAdapter adapter;
    ListView lv_main;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        List<ShopInfo> list=getAllShops();
        Log.e("denganzhi",list.toString());
        adapter = new ShopInfoAdapter();
        lv_main = (ListView)findViewById(R.id.lv_main);
        lv_main.setAdapter(adapter);
    }

    /*
 * 得到所有商品信息对象的集合
 */
    private List<ShopInfo> getAllShops() {
        // 准备一个空集合
        datas= new ArrayList<ShopInfo>();
        // 得到images文件夹的真实路径
      //  String imagesPath = getServletContext().getRealPath("/images");
        String imagesPath = "http://192.168.2.110:8080/Web001/images";
        // 创建images文件夹File对象
        // 遍历
        for (int i = 1; i < 31; i++) {
            // 得到商品的相关信息
            int id = i + 1;

            String name = "f"+i + "的商品名称";
            String imagePath =imagesPath + "/f"+i+"."+"jpg";
            float price = new Random().nextInt(20) + 20;
            // 封装成对象
            ShopInfo info = new ShopInfo(id, name, imagePath, price);
            // 添加到集合中
            datas.add(info);
        }
        return datas;
    }
    class ShopInfoAdapter extends BaseAdapter {

        private ImageLoader imageLoader;

        public ShopInfoAdapter() {
            imageLoader = new ImageLoader(MainActivity.this, R.drawable.loading, R.drawable.error);
        }
        @Override
        public int getCount() {
            return datas.size();
        }

        @Override
        public Object getItem(int position) {
            return datas.get(position);
        }

        @Override
        public long getItemId(int position) {
            return 0;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            if(convertView==null) {
                convertView = View.inflate(MainActivity.this, R.layout.item_main, null);
            }
            //得到当前行的数据对象
            ShopInfo shopInfo = datas.get(position);
            //得到当前行的子View
            TextView nameTV = (TextView) convertView.findViewById(R.id.tv_item_name);
            TextView priceTV = (TextView) convertView.findViewById(R.id.tv_item_price);
            ImageView imageView = (ImageView) convertView.findViewById(R.id.iv_item_icon);
            //设置数据
            nameTV.setText(shopInfo.getName());
            priceTV.setText(shopInfo.getPrice()+"元");
            String imagePath = shopInfo.getImagepath();
            //根据图片路径启动分线程动态请求服务加载图片并显示
            imageLoader.loadImage(imagePath, imageView);
            return convertView;
        }

    }

}

 

公開された75元の記事 ウォン称賛68 ビュー110 000 +

おすすめ

転載: blog.csdn.net/dreams_deng/article/details/104727866