2011年6月28日星期二

  ListView异步加载图片

【部分转】

异步加载类

package com.hecx.util;

import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.SoftReference;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;

import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Message;
import android.util.Log;

/*
* 异步加载图片类
*/
public class AsyncImageLoader {
    //SoftReference软引用 ,表示对象通常不会能gc回收内存,则只有在内存短缺的时候才会被回收
    private HashMap > imageCache;

    public AsyncImageLoader() {
        imageCache = new HashMap >();
    }

    public Drawable loadDrawable(final String imageUrl, final String srcName, final ImageCallback imageCallback) {
        if (imageCache.containsKey(imageUrl)) {
            SoftReference softReference = imageCache.get(imageUrl);
            Drawable drawable = softReference.get();
            if (drawable != null) {
                return drawable;
            }
        }
        //在主线程中处理消息
        // 当创建一个新的Handler实例时, 它会绑定到当前线程和消息的队列中,开始分发数据
        //另外一个种方式是handler = new Handler(this);this要实现CallBack
        final Handler handler = new Handler() {
            @Override
            public void handleMessage(Message message) {
                //表示在主线程加载完后的处理,可以 在这里更新UI
                imageCallback.imageLoaded((Drawable) message.obj, imageUrl);
            }
        };
       
        //这是子线程,在子线程中发送消息
        new Thread() {
            @Override
            public void run() {
                final Drawable drawable = loadImageFromUrl(imageUrl, srcName);
                imageCache.put(imageUrl, new SoftReference (drawable));
                Message message = handler.obtainMessage(0, drawable);
                handler.sendMessage(message);
            }
        }.start();
        return null;
    }

    public static Drawable loadImageFromUrl(String _url, String srcName) {
        // ...
        Log.v("TAG", "loadImageFromUrl...");
        Drawable drawable = null;
        InputStream is = null;
        try {
            /*
             * URL url = new URL(_url); URLConnection conn =
             * url.openConnection(); conn.setConnectTimeout(500);
             *
             * is = conn.getInputStream();
             */

            URL url = new URL(_url);
            is = (InputStream) url.getContent();
            drawable = Drawable.createFromStream(is, srcName);

            is.close();
        } catch (MalformedURLException e) {
            // TODO Auto-generated catch block
            Log.v("TAG", "。。。" + e.getMessage());
            e.printStackTrace();
        } catch (IOException e) {
            Log.v("TAG", "。。。" + e.getMessage());
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return drawable;
    }

    public interface ImageCallback {
        public void imageLoaded(Drawable imageDrawable, String imageUrl);
    }
}

 

自定义adapter

package com.hecx.scrollView;

import java.util.List;

import android.content.Context;
import android.graphics.drawable.Drawable;
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.RelativeLayout;
import android.widget.TextView;

import com.hecx.common.ImageInfo;
import com.hecx.util.AsyncImageLoader;
import com.hecx.util.AsyncImageLoader.ImageCallback;
import com.hecx.zine.R;

/*
* 自定义一个ArrayAdapter
*/
@SuppressWarnings("hiding")
public class ImageInfoAdapter extends ArrayAdapter {

    /*
     * 一般需要定义以下两个变量来存放传入的值
     */
    private int resource;
    private List list;
    private AsyncImageLoader asyncImageLoader;
    private Context context;
    private ListView listView;

    /*
     * 三个参数,一个是context,一个是item布局文件,一个是对象list或对象数组
     */
    public ImageInfoAdapter(Context context, int textViewResourceId, List objects, ListView listView) {
        super(context, textViewResourceId, objects);
        this.context = context;
        resource = textViewResourceId;
        list = objects;
        asyncImageLoader = new AsyncImageLoader();
        this.listView = listView;
        Log.v("TAG", "list.size()=" + list.size());
    }

    public int getCount() {
        return list.size();
    }

    // 这个方法其实也没什么用,可以随意返回
    public long getItemId(int position) {
        return position;
    }

    // 重写getItem方法返回对象
    public ImageInfo getItem(int position) {
        return (ImageInfo) list.get(position);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        Log.v("TAG", "getView...position=" + position);

        ImageInfo imageItem = getItem(position);

        View rowView = convertView;

        ViewHolder viewCache;// = (ViewHolder)convertView.getTag();

        if (rowView == null) {
            Log.v("TAG", "rowView == null...position=" + position);
            LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            rowView = inflater.inflate(resource, null);
            viewCache = new ViewHolder(rowView);
            rowView.setTag(viewCache);

        } else {
            viewCache = (ViewHolder) rowView.getTag();
        }

        ImageView imageView = viewCache.getImageView();
        imageView.setTag(imageItem.getImageUrl());
        Drawable cachedImage = asyncImageLoader.loadDrawable(imageItem.getImageUrl(), imageItem.getImageUrl(), new ImageCallback() {
            public void imageLoaded(Drawable imageDrawable, String imageUrl) {
                ImageView imageViewByTag = (ImageView) listView.findViewWithTag(imageUrl);
                if (imageViewByTag != null) {
                    imageViewByTag.setImageDrawable(imageDrawable);
                }
            }
        });

        if (cachedImage == null) {

        } else {
            imageView.setImageDrawable(cachedImage);
        }

        viewCache.getTitleView().setText(imageItem.getImageTitle());
        viewCache.getUrlView().setText(imageItem.getImageUrl());
        viewCache.getDescView().setText(imageItem.getImageDesc());

        return rowView;
    }

    public class ViewHolder {

        View view;

        TextView titleView;
        TextView urlView;
        TextView descView;
        ImageView imageView;
        ImageView downloaded_view;

        public ViewHolder(View view) {
            super();
            this.view = view;
        }

        public TextView getTitleView() {
            if (titleView == null) {
                titleView = (TextView) view.findViewById(com.hecx.zine.R.id.image_title);
            }
            return titleView;
        }

        public TextView getUrlView() {
            if (urlView == null) {
                urlView = (TextView) view.findViewById(com.hecx.zine.R.id.image_url);
            }
            return urlView;
        }

        public TextView getDescView() {
            if (descView == null) {
                descView = (TextView) view.findViewById(com.hecx.zine.R.id.image_desc);
            }
            return descView;
        }

        public ImageView getImageView() {
            if (imageView == null) {
                imageView = (ImageView) view.findViewById(com.hecx.zine.R.id.image_id);
            }
            return imageView;
        }

        public ImageView getDownloaded_view() {
            if (downloaded_view == null) {
                downloaded_view = (ImageView) view.findViewById(com.hecx.zine.R.id.downloaded_id);
            }
            return downloaded_view;
        }
    }

}

 

异步加载ListView中的每页

package com.hecx.zine.scrollView;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import android.app.ListActivity;
import android.content.Context;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.View;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.ListView;
import android.widget.Toast;

import com.hecx.common.ImageInfo;
import com.hecx.scrollView.ImageDbAdapter;
import com.hecx.scrollView.ImageInfoAdapter;
import com.hecx.util.JsonUtils;
import com.hecx.util.Tools;
import com.hecx.zine.ZineDetailActivity;

public class ScrollActivity extends ListActivity implements OnScrollListener {

    private View footer;// 滑动到底部时显示的图
    private List imageList;
    private ImageInfoAdapter imageAdapter;
    private ListView listView;// ListActivity中的ListView
   
    private int currStartPos = 0;//当前开始查询记录的位置,第加载一次currStartPos就会初始化一次
    private int pageCount = 5;//每页大小
   
    //private int allCountd = 0;//当前已经加载的所有大小
   
    private int scrollState;

    private boolean loading = false;
   
    private ImageDbAdapter dbAdapter;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(com.hecx.zine.R.layout.list_activity);
       
        dbAdapter = new ImageDbAdapter(this);

        // 1.初始化ListView及其事件
        initListView();

        // NetTools.isActiveNetworkConnected(MainActivity.this);
    }

    // 1.初始化ListView及其事件
    private void initListView() {

        LayoutInflater localLayoutInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        footer = View.inflate(ScrollActivity.this, com.hecx.zine.R.layout.loading_more_footer, null);
        listView = (ListView) this.getListView();// 获取ListActivity下的ListView
       
        imageList = new LinkedList ();
       
       
        Log.v("TAG", "imageList.size()=" + imageList.size());
       
        imageAdapter = new ImageInfoAdapter(this, com.hecx.zine.R.layout.item_image, imageList,listView);
        //listView.setScrollbarFadingEnabled(false);
        listView.addFooterView(footer);
        listView.setAdapter(imageAdapter);
        listView.setOnScrollListener(this);
       
        DataLoadTask task = new DataLoadTask();
        task.execute(null);

    }

    // OnScrollListener中的方法
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
        // TODO Auto-generated method stub
        //Log.v("TAG", "onScroll...");
        /*if ((!this.loading) && (firstVisibleItem + visibleItemCount == totalItemCount)){
            Log.v("TAG", "if onScroll...");
        }*/
        /*在onScroll和onScrollStateChanged中都用了下这段代码。但是在onScroll中增加了totalItemCount<=5条件,是为了第一次滚动状态没有改变时默认用 这个来加载数据
        if ((!this.loading) && (view.getLastVisiblePosition() == view.getCount() - 1) && (totalItemCount<=5) ) {
            Log.v("TAG", "if onScrollStateChanged...");
            // imageAdapter.notifyDataSetChanged();
            DataLoadTask task = new DataLoadTask();
            Log.v("TAG", "task="+task);
            task.execute(null);
            Log.v("TAG", "view.getLastVisiblePosition()=" + view.getLastVisiblePosition());
           
        }
        */
       
    }

    // OnScrollListener中的方法
    public void onScrollStateChanged(AbsListView view, int scrollState) {
        Log.v("TAG", "onScrollStateChanged.........scrollState="+scrollState);
        if ((!this.loading) && (view.getLastVisiblePosition() == view.getCount() - 1) ) {
            Log.v("TAG", "if onScrollStateChanged...");
            // imageAdapter.notifyDataSetChanged();
            DataLoadTask task = new DataLoadTask();
            Log.v("TAG", "task="+task);
            task.execute(null);
            Log.v("TAG", "view.getLastVisiblePosition()=" + view.getLastVisiblePosition());
        }
        this.scrollState = scrollState;
    }

    @Override
    public boolean onKeyUp(int keyCode, KeyEvent event) {
        // TODO Auto-generated method stub
        if(keyCode==KeyEvent.KEYCODE_BACK){
            finish();
            return true;
        }
        return super.onKeyUp(keyCode, event);
    }

    private void appendMoreData(List paramList) {
        if (paramList != null) {
            imageList.addAll(paramList);
            this.imageAdapter.notifyDataSetChanged();
        }
        // 判断是否显示"正在加载..."的进度条(如果新获取的数据为空,或得到的是否还有更多的标识是false,就移动footer,并取消滚动监听器)
        //if ((paramList == null) || (!hasMore)) {
        if ((paramList == null) || (paramList.size()             listView.removeFooterView(footer);
            this.footer = null;
            listView.setOnScrollListener(null);
        }
    }
   
    private void saveImageInfos(List _list){
        dbAdapter.open();
        for(ImageInfo item : _list){
            Log.v("TAG", ""+item.getImageId());
            dbAdapter.insertData(item.getImageId(), item.getImageTitle(), item.getImageUrl(), item.getImageDesc());
        }
        dbAdapter.close();
    }
   
   
    @Override
    public void onContextMenuClosed(Menu menu) {
        // TODO Auto-generated method stub
        super.onContextMenuClosed(menu);
    }

    @Override
    protected void onListItemClick(ListView l, View v, int position, long id) {
        // TODO Auto-generated method stub
        /*
         * 下面两句是通过ListView来取位置为position的apapter对应的对象
        String imageTitle = ((ImageInfo)l.getItemAtPosition(position)).getImageTitle();
        Toast.makeText(this, "选择了"+imageTitle, Toast.LENGTH_SHORT).show();
        */
        //让footer点击无效
        if(v == footer ){
            return;
        }
       
        Bundle bundle = new Bundle();
        bundle.putSerializable("imageInfo",(ImageInfo)l.getItemAtPosition(position));
       
        Intent intent = new Intent(this,ZineDetailActivity.class);
        intent.putExtras(bundle);
       
        startActivity(intent);
        //super.onListItemClick(l, v, position, id);
    }
   
   
    @Override
    protected void onSaveInstanceState(Bundle outState) {
        // TODO Auto-generated method stub
        Log.v("TAG", "onSaveInstanceState...");
        super.onSaveInstanceState(outState);
    }
/*
* 至于onRestoreInstanceState方法,需要注意的是,
* onSaveInstanceState方法和onRestoreInstanceState方法“不一定”是成对的被调用的,
* onRestoreInstanceState被调用的前提是,activity A“确实”被系统销毁了,
* 而如果仅仅是停留在有这种可能性的情况下,则该方法不会被调用,例如,当正在显示activity A的时候,
* 用户按下HOME键回到主界面,然后用户紧接着又返回到activity A,这种情况下activity A一般不会因为内存的原因被系统销毁,
* 故activity A的onRestoreInstanceState方法不会被执行
* onRestoreInstanceState的bundle参数也会传递到onCreate方法中,你也可以选择在onCreate方法中做数据还原
*/
   
    @Override
    protected void onRestoreInstanceState(Bundle state) {
        // TODO Auto-generated method stub
        Log.v("TAG", "onRestoreInstanceState...");
        super.onRestoreInstanceState(state);
    }

    @Override
    protected void onResume() {
        Log.v("TAG", "onResume...");
        // TODO Auto-generated method stub
        super.onResume();
    }

    //异步加载数据start
    public class DataLoadTask extends AsyncTask {

        List listMore = null;

        @Override
        protected void onPreExecute() {
            ScrollActivity.this.loading = true;
        }

        @Override
        protected Integer doInBackground(Integer... params) {
            // TODO Auto-generated method stub
            Log.v("TAG", "doInBackground...");
           
            Map paramMap = new HashMap();
            paramMap.put("startPos", ""+ScrollActivity.this.currStartPos);
            paramMap.put("pageCount", ""+ScrollActivity.this.pageCount);
            List _imageList = (List ) JsonUtils.fromJsonToList(Tools.getJsonFromService("findImagesByPos", paramMap));
            listMore = Tools.tranList(_imageList);
            saveImageInfos(listMore);
            return null;
        }

        @Override
        protected void onPostExecute(Integer paramInteger) {
            ScrollActivity.this.appendMoreData(listMore);
            Log.v("TAG", "onPostExecute->MainActivity.this.currStartPos="+ScrollActivity.this.currStartPos);
            //listView.setSelection(MainActivity.this.currStartPos-MainActivity.this.pageCount);
            if(listView.getCount()<=5){
                //这一段是为了防止第一次加载时出现定位不对的情况
                listView.setSelection(0);
            }
            ScrollActivity.this.loading = false;
            ScrollActivity.this.currStartPos = ScrollActivity.this.currStartPos+ScrollActivity.this.pageCount;
        }
    }
    //异步加载数据end
}

没有评论:

发表评论