1.底层网络接口采用apache的httpclient连接池框架;

2.图片缓存采用基于LRU的算法;

3.网络接口采用监听者模式;

4.包含图片的OOM处理(及时回收处理技术的应用);

图片核心处理类:CacheView.java

package xiaogang.enif.image;import java.io.FilterInputStream;import java.io.IOException;import java.io.InputStream;import java.lang.ref.SoftReference;import java.util.HashMap;import java.util.concurrent.RejectedExecutionException;import org.apache.http.HttpEntity;import org.apache.http.HttpResponse;import org.apache.http.HttpStatus;import org.apache.http.client.methods.HttpGet;import xiaogang.enif.utils.HttpManager;import xiaogang.enif.utils.IOUtils;import xiaogang.enif.utils.LogUtils;import xiaogang.enif.utils.LruCache;import android.app.ActivityManager;import android.content.Context;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.BitmapFactory.Options;import android.graphics.Canvas;import android.graphics.drawable.BitmapDrawable;import android.os.AsyncTask;import android.text.TextUtils;import android.util.AttributeSet;import android.widget.ImageView;public class CacheView extends ImageView {    private static final int DEFAULT_RES_ID = 0;    private int mDefaultImage = DEFAULT_RES_ID;    private static LruCache<String, Bitmap> mLruCache;    private static HashMap<Integer, SoftReference<Bitmap>> mResImage;    private Context mContext;    private LogUtils mLog = LogUtils.getLog(CacheView.class);    public CacheView(Context context, AttributeSet attrs, int defStyle) {        super(context, attrs, defStyle);        init(context);    }    public CacheView(Context context, AttributeSet attrs) {        super(context, attrs);        init(context);    }    public CacheView(Context context) {        super(context);        init(context);    }    private void init(Context context) {        mContext = context;        if (mLruCache == null) {            final int cacheSize = getCacheSize(context);            mLruCache = new LruCache<String, Bitmap>(cacheSize) {                @Override                protected int sizeOf(String key, Bitmap bitmap) {                    // The cache size will be measured in bytes rather than                    // number of items.                    return bitmap.getRowBytes() * bitmap.getHeight();                }                @Override                protected void entryRemoved(boolean evicted, String key, Bitmap oldValue,                        Bitmap newValue) {                    if (evicted && oldValue != null && !oldValue.isRecycled()) {                        oldValue.recycle();                        oldValue = null;                    }                }            };        }        if (mResImage == null) {            mResImage = new HashMap<Integer, SoftReference<Bitmap>>();        }    }    @Override    protected void onDraw(Canvas canvas) {        BitmapDrawable drawable = (BitmapDrawable)getDrawable();        if (drawable == null) {            setDefaultImage();        } else {            if (drawable.getBitmap() == null || drawable.getBitmap().isRecycled()) {                setDefaultImage();            }        }        try {            super.onDraw(canvas);        } catch(RuntimeException ex) {        }    }    public void setImageUrl(String url, int resId) {        setTag(url);        Bitmap bitmap = getBitmapFromCache(url);        if (bitmap == null || bitmap.isRecycled()) {            mDefaultImage = resId;            setDefaultImage();            try {                new DownloadTask().execute(url);            } catch (RejectedExecutionException e) {                // do nothing, just keep not crash            }        } else {            setImageBitmap(bitmap);        }    }    private void setDefaultImage() {        if (mDefaultImage != DEFAULT_RES_ID) {            setImageBitmap(getDefaultBitmap(mContext));        }    }    private Bitmap getDefaultBitmap(Context context) {        SoftReference<Bitmap> loading = mResImage.get(mDefaultImage);        if (loading == null || loading.get() == null || loading.get().isRecycled()) {            loading = new SoftReference<Bitmap>(BitmapFactory.decodeResource(                    context.getResources(), mDefaultImage));            mResImage.put(mDefaultImage, loading);        }        return loading.get();    }    private class DownloadTask extends AsyncTask<String, Void, Bitmap> {        private String mParams;        @Override        public Bitmap doInBackground(String... params) {            mParams = params[0];            final Bitmap bm = download(mParams);            addBitmapToCache(mParams, bm);            return bm;        }        @Override        public void onPostExecute(Bitmap bitmap) {            String tag = (String)getTag();            if (!TextUtils.isEmpty(tag) && tag.equals(mParams)) {                if (bitmap != null) {                    setImageBitmap(bitmap);                }            }        }    };    /*     * An InputStream that skips the exact number of bytes provided, unless it     * reaches EOF.     */    static class FlushedInputStream extends FilterInputStream {        public FlushedInputStream(InputStream inputStream) {            super(inputStream);        }        @Override        public long skip(long n) throws IOException {            long totalBytesSkipped = 0L;            while (totalBytesSkipped < n) {                long bytesSkipped = in.skip(n - totalBytesSkipped);                if (bytesSkipped == 0L) {                    int b = read();                    if (b < 0) {                        break; // we reached EOF                    } else {                        bytesSkipped = 1; // we read one byte                    }                }                totalBytesSkipped += bytesSkipped;            }            return totalBytesSkipped;        }    }    private Bitmap download(String url) {        InputStream in = null;        HttpEntity entity = null;        Bitmap bmp = null;        try {            final HttpGet get = new HttpGet(url);            final HttpResponse response = HttpManager.execute(mContext, get);            if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {                entity = response.getEntity();                in = entity.getContent();                try {                    bmp = getDecodeBitmap(in, url);                } catch (OutOfMemoryError err) {                    Runtime.getRuntime().gc();                    bmp = getDecodeBitmap(in, url);                }            } else {                get.abort();                return bmp;            }            addBitmapToCache(url, bmp);        } catch (IOException e) {            return bmp;        } finally {            IOUtils.closeStream(in);        }        return bmp;    }    private final Bitmap getDecodeBitmap(InputStream in, String url) {        Options options = new Options();        options.inPurgeable = true;        options.inInputShareable = true;        return BitmapFactory.decodeStream(new FlushedInputStream(in), null, options);    }    private final void addBitmapToCache(String url, Bitmap bitmap) {        if (bitmap != null) {            mLruCache.put(url, bitmap);            Runtime.getRuntime().gc();        }    }    private final Bitmap getBitmapFromCache(String url) {        return mLruCache.get(url);    }    private int getCacheSize(Context context) {        // According to the phone memory, set a proper cache size for LRU cache        // dynamically.        final ActivityManager am = (ActivityManager)context                .getSystemService(Context.ACTIVITY_SERVICE);        final int memClass = am.getMemoryClass();        int cacheSize;        if (memClass <= 24) {            cacheSize = (memClass << 20) / 24;        } else if (memClass <= 36) {            cacheSize = (memClass << 20) / 18;        } else if (memClass <= 48) {            cacheSize = (memClass << 20) / 12;        } else {            cacheSize = (memClass << 20) >> 3;        }        mLog.debug("cacheSize == "+cacheSize);        System.out.println("cacheSize == "+cacheSize);        return cacheSize;    }    public static void recycle() {        if (mLruCache != null && !mLruCache.isEmpty()) {            mLruCache.evictAll();            mLruCache = null;        }        if (mResImage != null) {            for (SoftReference<Bitmap> reference : mResImage.values()) {                Bitmap bitmap = reference.get();                if (bitmap != null && !bitmap.isRecycled()) {                    bitmap.recycle();                    bitmap = null;                }            }            mResImage = null;        }    }}


说明:

1)entryRemoved在做bitmap recycle的时候的3个条件缺一不可;

2)onDraw里面判断图片是否被回收,如果回收,需要设置默认图片;

3)add bitmap到cache的时候Runtime.getRuntime().gc();的调用;

4)getCacheSize可以根据手机具体的内存来动态设置我们实际需要的缓存大小;

5)退出时,记得调用recycle()方法;

网络接口核心类:WSAPI.java, WSCfg.java, WSTask.java

package xiaogang.enif.net;import java.util.ArrayList;import org.apache.http.message.BasicNameValuePair;/** * web service configuration file * */public class WSCfg {    public static final int USER_LOGIN = 0;//action    public static final int USER_LOGOUT = 1;//action    public static ArrayList<BasicNameValuePair> sValuePairs;//common vps    static {        sValuePairs = new ArrayList<BasicNameValuePair>();        sValuePairs.add(new BasicNameValuePair("v", "1.0"));        sValuePairs.add(new BasicNameValuePair("format", "json"));    }}
package xiaogang.enif.net;import java.util.ArrayList;import java.util.concurrent.RejectedExecutionException;import org.apache.http.message.BasicNameValuePair;import xiaogang.enif.net.WSTask.TaskListener;import android.content.Context;public class WSAPI {    private WSAPI() {    }    public static void execute(Context context, TaskListener listener, int action,            ArrayList<BasicNameValuePair> vp) {        try {            new WSTask(context, listener, action, vp).execute();        } catch (RejectedExecutionException e) {            // do nothing, just keep not crashing.        }    }}

package xiaogang.enif.net;import java.io.IOException;import java.io.InputStream;import java.util.ArrayList;import java.util.HashMap;import java.util.Iterator;import org.apache.http.HttpEntity;import org.apache.http.HttpResponse;import org.apache.http.HttpStatus;import org.apache.http.client.entity.UrlEncodedFormEntity;import org.apache.http.client.methods.HttpPost;import org.apache.http.message.BasicNameValuePair;import org.json.JSONArray;import org.json.JSONException;import org.json.JSONObject;import xiaogang.enif.utils.HttpManager;import xiaogang.enif.utils.IOUtils;import xiaogang.enif.utils.LogUtils;import android.app.Activity;import android.content.Context;import android.os.AsyncTask;import android.text.TextUtils;public class WSTask extends AsyncTask<Void, Void, Object> {    private int mAction;    private String mErrorCode;    private Object mParameter;    private Context mContext;    private TaskListener mTaskListener;    private Exception mReason;    private final LogUtils mLog = LogUtils.getLog(WSTask.class);    public WSTask(Context context, TaskListener listener, int action, Object paramObject) {        mContext = context;        mTaskListener = listener;        mParameter = paramObject;        mAction = action;    }    @Override    public Object doInBackground(Void... arg0) {        Object result = null;        try {            @SuppressWarnings("unchecked")            ArrayList<BasicNameValuePair> vps = (ArrayList<BasicNameValuePair>)mParameter;            final String jsonString = request(mContext, "your url", vps);            mLog.debug(jsonString);            result = parseJson(jsonString);            if (result != null && result instanceof String                    && TextUtils.isDigitsOnly((String)result)) {                mErrorCode = (String)result;                return null;            }        } catch (Exception e) {            mReason = e;            mLog.error(e.getMessage());            return null;        }        return result;    }    @Override    public void onPostExecute(Object result) {        if (mContext== null) {            clearTask();            return;        }        if (mContext instanceof Activity && ((Activity) mContext).isFinishing()) {            clearTask();            return;        }        if (result == null || mReason != null) {            mTaskListener.onFailed(mAction, mErrorCode, mReason);        } else {            mTaskListener.onSuccess(mAction, result);        }        clearTask();    }    private String request(Context context, String url, ArrayList<BasicNameValuePair> vp)            throws IOException {        final HttpPost post = new HttpPost(url);        post.setEntity(new UrlEncodedFormEntity(vp, "UTF_8"));        InputStream in = null;        HttpEntity entity = null;        try {            final HttpResponse response = HttpManager.execute(context, post);            final int statusCode = response.getStatusLine().getStatusCode();            if (statusCode == HttpStatus.SC_OK) {                entity = response.getEntity();                if (entity != null) {                    in = entity.getContent();                    return IOUtils.stream2String(in);                }            } else {                post.abort();                mLog.error("http code: " + response.getStatusLine().getStatusCode());            }            return null;        } catch (IOException ex) {            post.abort();            throw ex;        } catch (RuntimeException ex) {            post.abort();            throw ex;        } finally {            if(entity!=null) {                entity.consumeContent();            }            IOUtils.closeStream(in);        }    }    private Object parseJson(String jsonString) throws IOException {        try {            JSONObject jobj = new JSONObject(jsonString);            if (jobj.has("errorcode")) {                return jobj.optString("errorcode");            }            if (jobj.has("resultlist")) {                ArrayList<HashMap<String, String>> arrList;                arrList = new ArrayList<HashMap<String, String>>();                JSONArray jsonArray = jobj.optJSONArray("resultlist");                final int len = jsonArray.length();                for (int i = 0; i < len; i++) {                    final JSONObject obj = (JSONObject)jsonArray.opt(i);                    arrList.add(parse2Map(obj));                }                return arrList;            } else {                return parse2Map(jobj);            }        } catch (JSONException e) {            IOException ioe = new IOException("Invalid json String...");            ioe.initCause(e);            throw ioe;        }    }    private HashMap<String, String> parse2Map(JSONObject jsonObj) throws IOException {        final HashMap<String, String> hashMap = new HashMap<String, String>();        @SuppressWarnings("unchecked")        final Iterator<String> keyIter = jsonObj.keys();        String key, value;        while (keyIter != null && keyIter.hasNext()) {            key = keyIter.next();            value = jsonObj.optString(key);            hashMap.put(key, value);        }        return hashMap;    }    private void clearTask() {        mTaskListener = null;        mParameter = null;        mContext = null;    }    public interface TaskListener {        public void onSuccess(int action, Object result);        public void onFailed(int action, String errcode, Exception ex);    }}


说明:

1)根据你的服务器接口实际情况,去修改parseJson方法;

2)WSCfg里面可以定义接口的action;

sample:

package xiaogang.enif.ui;import java.util.ArrayList;import org.apache.http.message.BasicNameValuePair;import xiaogang.enif.R;import xiaogang.enif.image.CacheView;import xiaogang.enif.net.WSAPI;import xiaogang.enif.net.WSCfg;import xiaogang.enif.net.WSTask.TaskListener;import xiaogang.enif.widget.ListsApdater;import android.app.Activity;import android.os.Bundle;import android.widget.ListView;public class MainActivity extends Activity implements TaskListener {    ListView mList;    ListsApdater mAdapter;    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.main);        setupViews();    }    private void setupViews() {        mList = (ListView)findViewById(R.id.list);        mAdapter = new ListsApdater(this, mUrls);        mList.setAdapter(mAdapter);        final ArrayList<BasicNameValuePair> vp = new ArrayList<BasicNameValuePair>();        vp.addAll(WSCfg.sValuePairs);        vp.add(new BasicNameValuePair("imei", "123"));        vp.add(new BasicNameValuePair("imsi", "123"));        WSAPI.execute(this, this, WSCfg.USER_LOGIN, vp);    }    @Override    protected void onDestroy() {        super.onDestroy();        mAdapter.recycle();        CacheView.recycle();    }    private String[] mUrls = {            "http://a3.twimg.com/profile_images/670625317/aam-logo-v3-twitter.png",            "http://a3.twimg.com/profile_images/740897825/AndroidCast-350_normal.png",            "http://a3.twimg.com/profile_images/121630227/Droid_normal.jpg",            "http://a1.twimg.com/profile_images/957149154/twitterhalf_normal.jpg",            "http://a1.twimg.com/profile_images/97470808/icon_normal.png",            "http://a3.twimg.com/profile_images/511790713/AG.png",            "http://a3.twimg.com/profile_images/956404323/androinica-avatar_normal.png",            "http://a1.twimg.com/profile_images/909231146/Android_Biz_Man_normal.png",            "http://a3.twimg.com/profile_images/72774055/AndroidHomme-LOGO_normal.jpg",            "http://a1.twimg.com/profile_images/349012784/android_logo_small_normal.jpg",            "http://a1.twimg.com/profile_images/841338368/ea-twitter-icon.png",            "http://a3.twimg.com/profile_images/64827025/android-wallpaper6_2560x160_normal.png",            "http://a3.twimg.com/profile_images/77641093/AndroidPlanet_normal.png",            "http://a1.twimg.com/profile_images/850960042/elandroidelibre-logo_300x300_normal.jpg",            "http://a1.twimg.com/profile_images/655119538/andbook.png",            "http://a3.twimg.com/profile_images/768060227/ap4u_normal.jpg",            "http://a1.twimg.com/profile_images/74724754/android_logo_normal.png",            "http://a3.twimg.com/profile_images/681537837/SmallAvatarx150_normal.png",            "http://a1.twimg.com/profile_images/63737974/2008-11-06_1637_normal.png",            "http://a3.twimg.com/profile_images/548410609/icon_8_73.png",            "http://a1.twimg.com/profile_images/612232882/nexusoneavatar_normal.jpg",            "http://a1.twimg.com/profile_images/213722080/Bugdroid-phone_normal.png",            "http://a1.twimg.com/profile_images/645523828/OT_icon_090918_android_normal.png",            "http://a3.twimg.com/profile_images/64827025/android-wallpaper6_2560x160_normal.png",            "http://a3.twimg.com/profile_images/77641093/AndroidPlanet.png",            "http://a1.twimg.com/profile_images/850960042/elandroidelibre-logo_300x300_normal.jpg",            "http://a1.twimg.com/profile_images/655119538/andbook_normal.png",            "http://a3.twimg.com/profile_images/511790713/AG_normal.png",            "http://a3.twimg.com/profile_images/956404323/androinica-avatar.png",            "http://a1.twimg.com/profile_images/909231146/Android_Biz_Man_normal.png",            "http://a3.twimg.com/profile_images/72774055/AndroidHomme-LOGO_normal.jpg",            "http://a1.twimg.com/profile_images/349012784/android_logo_small_normal.jpg",            "http://a1.twimg.com/profile_images/841338368/ea-twitter-icon_normal.png",            "http://a3.twimg.com/profile_images/64827025/android-wallpaper6_2560x160_normal.png",            "http://a3.twimg.com/profile_images/77641093/AndroidPlanet.png",            "http://a3.twimg.com/profile_images/64827025/android-wallpaper6_2560x160_normal.png",            "http://a1.twimg.com/profile_images/850960042/elandroidelibre-logo_300x300.jpg",            "http://a1.twimg.com/profile_images/655119538/andbook_normal.png",            "http://a3.twimg.com/profile_images/511790713/AG_normal.png",            "http://a3.twimg.com/profile_images/956404323/androinica-avatar_normal.png",            "http://a1.twimg.com/profile_images/909231146/Android_Biz_Man_normal.png",            "http://a3.twimg.com/profile_images/121630227/Droid.jpg",            "http://a1.twimg.com/profile_images/97470808/icon_normal.png",            "http://a3.twimg.com/profile_images/511790713/AG_normal.png",            "http://a3.twimg.com/profile_images/956404323/androinica-avatar_normal.png",            "http://a1.twimg.com/profile_images/909231146/Android_Biz_Man.png",            "http://a3.twimg.com/profile_images/72774055/AndroidHomme-LOGO_normal.jpg",            "http://a1.twimg.com/profile_images/349012784/android_logo_small_normal.jpg",            "http://a1.twimg.com/profile_images/841338368/ea-twitter-icon_normal.png",            "http://a3.twimg.com/profile_images/64827025/android-wallpaper6_2560x160_normal.png",            "http://a3.twimg.com/profile_images/77641093/AndroidPlanet.png",            "http://a3.twimg.com/profile_images/121630227/Droid_normal.jpg",            "http://a1.twimg.com/profile_images/957149154/twitterhalf_normal.jpg",            "http://a1.twimg.com/profile_images/97470808/icon.png",            "http://a3.twimg.com/profile_images/511790713/AG_normal.png",            "http://a1.twimg.com/profile_images/909231146/Android_Biz_Man_normal.png",            "http://a3.twimg.com/profile_images/72774055/AndroidHomme-LOGO_normal.jpg",            "http://a1.twimg.com/profile_images/349012784/android_logo_small_normal.jpg",            "http://a1.twimg.com/profile_images/841338368/ea-twitter-icon.png",            "http://a3.twimg.com/profile_images/64827025/android-wallpaper6_2560x160_normal.png",            "http://a3.twimg.com/profile_images/77641093/AndroidPlanet_normal.png",            "http://a1.twimg.com/profile_images/850960042/elandroidelibre-logo_300x300_normal.jpg",            "http://a1.twimg.com/profile_images/655119538/andbook_normal.png",            "http://a3.twimg.com/profile_images/768060227/ap4u_normal.jpg",            "http://a1.twimg.com/profile_images/74724754/android_logo.png",            "http://a3.twimg.com/profile_images/681537837/SmallAvatarx150_normal.png",            "http://a1.twimg.com/profile_images/63737974/2008-11-06_1637_normal.png",            "http://a3.twimg.com/profile_images/548410609/icon_8_73_normal.png",            "http://a1.twimg.com/profile_images/612232882/nexusoneavatar_normal.jpg",            "http://a1.twimg.com/profile_images/213722080/Bugdroid-phone_normal.png",            "http://a1.twimg.com/profile_images/645523828/OT_icon_090918_android.png",            "http://a3.twimg.com/profile_images/64827025/android-wallpaper6_2560x160_normal.png",            "http://a3.twimg.com/profile_images/77641093/AndroidPlanet_normal.png",            "http://a1.twimg.com/profile_images/850960042/elandroidelibre-logo_300x300_normal.jpg",            "http://a1.twimg.com/profile_images/655119538/andbook.png",            "http://a3.twimg.com/profile_images/956404323/androinica-avatar_normal.png",            "http://a1.twimg.com/profile_images/909231146/Android_Biz_Man_normal.png",            "http://a3.twimg.com/profile_images/72774055/AndroidHomme-LOGO_normal.jpg",            "http://a1.twimg.com/profile_images/349012784/android_logo_small_normal.jpg",            "http://a1.twimg.com/profile_images/841338368/ea-twitter-icon.png",            "http://a3.twimg.com/profile_images/64827025/android-wallpaper6_2560x160_normal.png",            "http://a3.twimg.com/profile_images/77641093/AndroidPlanet_normal.png",            "http://a3.twimg.com/profile_images/64827025/android-wallpaper6_2560x160_normal.png",            "http://a1.twimg.com/profile_images/850960042/elandroidelibre-logo_300x300_normal.jpg",            "http://a1.twimg.com/profile_images/655119538/andbook_normal.png",            "http://a3.twimg.com/profile_images/511790713/AG_normal.png",            "http://a3.twimg.com/profile_images/956404323/androinica-avatar_normal.png",            "http://a1.twimg.com/profile_images/909231146/Android_Biz_Man_normal.png",            "http://a3.twimg.com/profile_images/121630227/Droid_normal.jpg",            "http://a1.twimg.com/profile_images/957149154/twitterhalf.jpg",            "http://a1.twimg.com/profile_images/97470808/icon_normal.png",            "http://a3.twimg.com/profile_images/511790713/AG_normal.png",            "http://a1.twimg.com/profile_images/909231146/Android_Biz_Man_normal.png",            "http://a3.twimg.com/profile_images/72774055/AndroidHomme-LOGO_normal.jpg",            "http://a1.twimg.com/profile_images/841338368/ea-twitter-icon_normal.png",            "http://a3.twimg.com/profile_images/64827025/android-wallpaper6_2560x160_normal.png",            "http://a3.twimg.com/profile_images/77641093/AndroidPlanet_normal.png"    };    @Override    public void onSuccess(int action, Object result) {        switch (action) {            case WSCfg.USER_LOGIN:                break;            case WSCfg.USER_LOGOUT:                break;        }    }    @Override    public void onFailed(int action, String errcode, Exception ex) {        switch (action) {            case WSCfg.USER_LOGIN:                break;            case WSCfg.USER_LOGOUT:                break;        }    }}

package xiaogang.enif.widget;import xiaogang.enif.R;import xiaogang.enif.image.CacheView;import android.content.Context;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.BaseAdapter;import android.widget.TextView;public class ListsApdater extends BaseAdapter {    private String[] mUrls;    private LayoutInflater mInflater;    public ListsApdater(Context context, String[] urls) {        mUrls = urls;        mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);    }    @Override    public int getCount() {        return mUrls.length;    }    @Override    public Object getItem(int position) {        return position;    }    @Override    public long getItemId(int position) {        return position;    }    @Override    public View getView(int position, View convertView, ViewGroup parent) {        ViewHolder holder = null;        if (null == convertView) {            holder = new ViewHolder();            convertView = mInflater.inflate(R.layout.item, null);            holder.view = (CacheView)convertView.findViewById(R.id.image);            holder.text = (TextView)convertView.findViewById(R.id.text);            convertView.setTag(holder);        } else {            holder = (ViewHolder)convertView.getTag();        }        holder.text.setText("item "+position);        holder.view.setImageUrl(mUrls[position], R.drawable.stub);        return convertView;    }    public void recycle() {        mUrls = null;        mInflater = null;    }    private class ViewHolder {        CacheView view;        TextView text;    }}


main.xml和item.xml

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="fill_parent"    android:layout_height="fill_parent"    android:orientation="vertical" >    <ListView        android:id="@+id/list"        android:layout_width="fill_parent"        android:layout_height="0dip"        android:layout_weight="1" /></LinearLayout>

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="fill_parent"    android:layout_height="wrap_content" >    <xiaogang.enif.image.CacheView        android:id="@+id/image"        android:layout_width="50dip"        android:layout_height="50dip"        android:scaleType="centerCrop"        android:src="@drawable/stub" />    <TextView        android:id="@+id/text"        android:layout_width="0dip"        android:layout_height="wrap_content"        android:layout_gravity="left|center_vertical"        android:layout_marginLeft="10dip"        android:layout_weight="1"        android:textSize="20dip" /></LinearLayout>

例子的效果图如下:





完整例子代码详见:http://code.google.com/p/enif/

或者 http://download.csdn.net/detail/androidzhaoxiaogang/4797109

更多相关文章

  1. Android(安卓)指南针
  2. Android睡眠唤醒机制--系统架构
  3. Android中利用OnTouchListener在ImageView中框选显示图片
  4. android ImageView实现上面圆角下面直角(xml实现方法)
  5. android 自定义view实现图形移动
  6. android关于内存溢出的异常
  7. 【推荐收藏】2017年最新的分类Android项目源码免费一次性打包下
  8. Android如何获取视频首帧图片
  9. android常用的API接口调用

随机推荐

  1. [对android程序作代码混淆]
  2. Android屏幕适配全攻略(最权威的官方适配
  3. android去掉button默认的点击阴影
  4. Android(安卓)事件分发详解及示例代码
  5. [Android] ubuntu 下不识别 Android(安卓
  6. Android(安卓)Log详解!
  7. View视图——TextView、EditText、Button
  8. android进程间共享简单数据
  9. 在Ubuntu中和Android中添加开机自启动的
  10. Android应用程序防止被LMK干掉