我用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,這個過程會更加漫長。
所以,解決方法就是盡量避免自適應,除非是萬不得已,固定大小或者填充的效果會比較好一些。
查看本欄目