程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> 為何ListView中getView被重復調用

為何ListView中getView被重復調用

編輯:關於.NET

我用ListView顯示數據時,自定義了一個適配器(extends ArrayAdapter),然後重寫了getView方法 ,現在出現一個問題,就是這個getView()方法被重復調用了,比如我的_data中有兩條數據,但是 log.i("show",house.toString());這句卻被執行了4次甚至更多,請問各位這是神馬情況?

方法代碼如下:

這是自定義的適配器:

package com.hb.puppet.utils;
import java.util.List;
    
import com.hb.puppet.activity.MetaData;
import com.hb.puppet.activity.R;
import com.hb.puppet.entity.House;
    
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
    
public class CustomCollectAdapter extends ArrayAdapter<House> {
    private static final String CLASSTAG = CustomCollectAdapter.class
            .getSimpleName();
    private ListView _listView;
    private int _resource;
    private List<House> _data;
    private LayoutInflater _inflater;
    private AsyncLoadImageTask _asyncloader;
    
    public CustomCollectAdapter(Context context, ListView listView,
            List<House> data) {
            
        super(context, 0, data);
            
        _resource = R.layout.list_item_collect;
        _data = data;
        _inflater = (LayoutInflater) context
                .getSystemService(context.LAYOUT_INFLATER_SERVICE);
        _asyncloader = new AsyncLoadImageTask();
        _listView = listView;
    }
    
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View view = convertView;
        CollectListItemViewCache viewCache = null;
        //
        final int index = position;
        //
        final ViewGroup p = parent;
    
        if (view != null) {
            viewCache = (CollectListItemViewCache) view.getTag();
        } else {
            view = _inflater.inflate(_resource,null);
            viewCache = new CollectListItemViewCache(view);
            view.setTag(viewCache);
        }
        // 房源數據
        House house = _data.get(position);
        System.out.println(house.toString());
            
        if (house != null) {
            //http://www.xxx.com/xxx.jpg
            String imageUrl = MetaData.HOST + house.getTitlePic();
            ImageView imageView = viewCache.getImageView();
            imageView.setTag(imageUrl);
            //異步加載圖片
           new AsyncImageLoaderTask().execute(imageUrl,imageView);
            // 房源標題
            TextView houseTitle = viewCache.getHouseTitle();
            houseTitle.setText(house.getTitle());
            // 房源單價
            TextView housePrice = viewCache.getHousePrice();
            housePrice.setText(house.getSinglePrice() + "元/㎡");
            // 房源面積
            TextView houseArea = viewCache.getHouseArea();
            houseArea.setText(house.getArea() + "㎡");
            // 房源戶型
            TextView houseUnit = viewCache.getHouseUnit();
            houseUnit.setText(house.getUnits());
            // 單項刪除收藏房源
            Button delButton = viewCache.getDelButton();
            delButton.setOnClickListener(new OnClickListener() {
                public void onClick(View v) {
                    System.out.println("clicked");
                }
            });
        }
        return view;
    }
}

異步加載圖片:

package com.hb.puppet.utils;
    
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.SoftReference;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
    
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.util.Log;
import android.widget.ImageView;
    
public class AsyncImageLoaderTask extends AsyncTask<Object, Object, Bitmap>{
    private String classTag = AsyncImageLoaderTask.class.getSimpleName();
    private ImageView _view;
    private HashMap<String, SoftReference<Bitmap>> imageCache;
        
    public AsyncImageLoaderTask() {
        imageCache = new HashMap<String, SoftReference<Bitmap>>();
    }
        
    @Override
    protected Bitmap doInBackground(Object... params) {
        Bitmap bitmap = null;
        String url = (String)params[0];
        _view = (ImageView)params[1];
        if(_view == null){
            Log.e(classTag,classTag + " value of _view is not null");
            return null;
        }
            
        if(url != null){
            //if current url is int imageCache,get this drawable by it,then return the drawable
            if(imageCache.containsKey(url)){
                SoftReference<Bitmap> mapSoft = imageCache.get(url);
                bitmap = mapSoft.get();
                if(bitmap != null){
                    return bitmap;
                }
            }
            //
            URL fromUrl = null;
            try {
                fromUrl = new URL(url);
                HttpURLConnection conn = (HttpURLConnection)fromUrl.openConnection();
                conn.setDoInput(true);
                conn.connect();
                InputStream input = conn.getInputStream();
                bitmap = BitmapFactory.decodeStream(input);
                input.close();
            } catch (MalformedURLException e) {
                Log.e(classTag, classTag + " Method doInBackground -- " +e.getMessage());
            } catch (IOException e) {
                Log.e(classTag, classTag + " Method doInBackground -- " +e.getMessage());
            } catch(Exception e){
                Log.e(classTag, classTag + " Method doInBackground -- " +e.getMessage());
            }
                
            imageCache.put(url, new SoftReference<Bitmap>(bitmap));
        }
            
        return bitmap;
    }
        
    @Override
    protected void onPostExecute(Bitmap bitmap) {
        if(bitmap != null){
            System.out.println("onPostExecute");
            this._view.setImageBitmap(bitmap);
            this._view = null;
        }
    }
}

這是什麼樣的情況了,看了網上的資料以後我知道原來沒有設置器listview 的布局方式不是fill- parent,而是wrap-content,會計算父控件的高度所以造成了一種反復調用情況,從而次數不確定。

更深層次的解釋為:

View在Draw的時候分成兩個階段:measure和layout,在measure階段時主要就是為了計算兩個參數: height和width。而且要注意的是,這是個遞歸的過程,從頂向下,DecorView開始依次調用自己子元素 的measure。計算完成這兩個參數後就開始layout,最後再是draw的調用。

對於ListView,當然每一個Item都會被調用measure方法,而在這個過程中getView和getCount會被調 用,而且看用戶的需求,可能會有很多次調用。

而為什麼會有很多組次調用呢?

問題就在於在layout中的決定ListView或者它的父元素的height和width屬性的定義了。fill_parent 會好一點,計算方法會比較簡單,只要跟父元素的大小相似就行,但是即使是fill_parent,也不能給 View當飯吃,還是要計算出來具體的dip,所以measure還是會被調用,只是可能比wrap_content的少一 點。至於自適應的它會一直考量它的寬和高,根據內容(也就是它的子Item)計算寬高。可能這個 measure過程會反復執行,如果父元素也是wrap_content,這個過程會更加漫長。

所以,解決方法就是盡量避免自適應,除非是萬不得已,固定大小或者填充的效果會比較好一些。

查看本欄目

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved