复习:红孩子应用客户端学习(4)
这次分析的主要是界面的生成 ,其实也就是adapter的显示
1.计时器
首先做了一个Data格式转换,就是在list中显示的倒计时
simpleDateFormat = new SimpleDateFormat("dd 天 HH:mm:ss");
然后在把从服务器获取的时间戳和当前的时间戳对比计算出剩余的时间
long v = item.getLefttime() - System.currentTimeMillis(); Date date = new Date(v); holderView.textProductCommentNum.setText(simpleDateFormat.format(date));
这里有一个问题是:
如果用户手机的时间不是准确的时间会报错,在实际项目开发的时候我们使用的是从服务器获取的时间戳,然后进行的计算
如何更新呢?
private Runnable runnable = new Runnable() { @Override public void run() { if (!isPlay) return; handler.postDelayed(this, 1000); notifyDataSetChanged(); } }; private Handler handler = new Handler(); //在外部控制计时器的开始和结束 public void start() { isPlay = true; runnable.run(); } public void stop() { isPlay = false; }
2.图片异步加载的实现
这次感觉实现的异步加载比较麻烦 先来分析一下:
在执行到
loadImage(position, list.get(position).getPic());
方法的时候 执行的是父类的这个方法
父类的方法是这样的:
public void loadImage(Integer t, String imageUrl) {
syncImageLoader.loadImage(t, imageUrl, imageLoadListener);
}
调用了syncImageLoader的loadImage(t, imageUrl, imageLoadListener)方法
想看看imageLoadListener:
AbsListView.OnScrollListener onScrollListener = new AbsListView.OnScrollListener() { @Override public void onScrollStateChanged(AbsListView view, int scrollState) { switch (scrollState) { case AbsListView.OnScrollListener.SCROLL_STATE_FLING: // Logger.d(TAG, "SCROLL_STATE_FLING"); syncImageLoader.lock(); break; case AbsListView.OnScrollListener.SCROLL_STATE_IDLE: // Logger.d(TAG, "SCROLL_STATE_IDLE"); loadImage(); break; case AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL: syncImageLoader.lock(); break; } } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { } };
这是用来让syncImageLoader在执行完了之后调用的 这里开了线程来处理数据的 这样可以实现异步更新 具体看http://rayleung.iteye.com/blog/435147
public void loadImage(Integer position, String imageUrl, OnImageLoadListener listener) { final OnImageLoadListener mListener = listener; final String mImageUrl = imageUrl; final Integer mt = position; threadPool.addTask(new Runnable() { @Override public void run() { if (!mAllowLoad) { // Log.d(TAG, "prepare to load"); synchronized (lock) { try { lock.wait(); } catch (InterruptedException e) { } } } if (mAllowLoad && firstLoad) { loadImage(mImageUrl, mt, mListener); } else if (mAllowLoad && mt <= mStopLoadLimit && mt >= mStartLoadLimit) { loadImage(mImageUrl, mt, mListener); } } }); }
好吧继续看loadImage的方法把
private void loadImage(final String mImageUrl, final Integer mt, final OnImageLoadListener mListener) { if (imageCache.containsKey(mImageUrl)) { SoftReference<Drawable> softReference = imageCache.get(mImageUrl); final Drawable d = softReference.get(); if (d != null) { handler.post(new Runnable() { @Override public void run() { if (mAllowLoad) { mListener.onImageLoad(mt, d); } } }); return; } } try { final Drawable d = loadImageFromUrl(mImageUrl); if (d != null) { imageCache.put(mImageUrl, new SoftReference<Drawable>(d)); } handler.post(new Runnable() { @Override public void run() { if (mAllowLoad) { mListener.onImageLoad(mt, d); } } }); } catch (IOException e) { handler.post(new Runnable() { @Override public void run() { mListener.onError(mt); } }); Log.e(TAG, e.toString()); } }
终于返回了..
返回之前中间还有个正在获取图片的方法:如果本地缓存有图片加载本地图片如果没有那从网络下载 再执行这个方法加载本地图片
public static Drawable loadImageFromUrl(String url) throws IOException { InputStream in = null; OutputStream out = null; try { File f = new File(ECApplication.getCacheDirPath(), MD5.digest(url)); if (f.exists()) { Log.d(TAG, "缓存 " + f.getAbsolutePath()); return Drawable.createFromPath(f.getAbsolutePath()); } Log.d(TAG, "网络 " + url); URL m = new URL(url); in = new BufferedInputStream((InputStream) m.getContent(), BUFFER_SIZE); out = new BufferedOutputStream(new FileOutputStream(f), BUFFER_SIZE); byte[] buffer = new byte[BUFFER_SIZE]; int len = 0; while ((len = in.read(buffer)) != -1) { out.write(buffer, 0, len); } } finally { StreamUtil.Release(in, out); } return loadImageFromUrl(url); }
然后ImageAsyncLoaderAdpter调用LimitbuyAdapter的onImageLoadFinish
drawables[position] = drawable;
然后执行
holderView.goodsIconIv.setBackgroundDrawable(d);
进行更新
这里用到了软引用
private Map<String, SoftReference<Drawable>> imageCache = new ConcurrentHashMap<String, SoftReference<Drawable>>();
然后
if (imageCache.containsKey(mImageUrl)) {//如果软引用中有相关数据那就直接调用 SoftReference<Drawable> softReference = imageCache.get(mImageUrl); final Drawable d = softReference.get(); if (d != null) { handler.post(new Runnable() { @Override public void run() { if (mAllowLoad) { mListener.onImageLoad(mt, d); } } }); return; } } try { final Drawable d = loadImageFromUrl(mImageUrl); if (d != null) { imageCache.put(mImageUrl, new SoftReference<Drawable>(d));//否则获取并将其放入缓存中 } handler.post(new Runnable() { @Override public void run() { if (mAllowLoad) { mListener.onImageLoad(mt, d); } } }); } catch (IOException e) { handler.post(new Runnable() { @Override public void run() { mListener.onError(mt); } });
补充一个知识点
private ThreadPoolManager threadPool = ThreadPoolManager.getInstance();
老师用了线程池来做线程执行
package com.su.timelimit; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class ThreadPoolManager { private ExecutorService service; private ThreadPoolManager() { int num = Runtime.getRuntime().availableProcessors(); service = Executors.newFixedThreadPool(num * 4); } private static final ThreadPoolManager manager = new ThreadPoolManager(); public static ThreadPoolManager getInstance() { return manager; } public void addTask(Runnable runnable) { service.execute(runnable); } }