问题描述
系统似乎是回收视图,直到它在我的列表视图中加载正确的位置的视图,导致几秒钟的复制图像和文本.任何人都可以帮助吗?
@Override public View getView(final int position, View convertView, ViewGroup parent) { View v = convertView; Log.d("position",""+position); if(v==null){ LayoutInflater inflater = LayoutInflater.from(mContext); v = inflater.inflate(R.layout.layout_appinfo, null); holder = new ViewHolder(); holder.ivAppIcon = (ImageView)v.findViewById(R.id.ivIconApp); holder.tvAppName = (TextView)v.findViewById(R.id.tvNameApp); holder.progress = (ProgressBar)v.findViewById(R.id.progress_spinner); v.setTag(holder); } else { holder = (ViewHolder) v.getTag(); } holder.ivAppIcon.setImageDrawable(null); holder.tvAppName.setText(null); holder.progress.setVisibility(View.VISIBLE); holder.ivAppIcon.setVisibility(View.GONE); // Using an AsyncTask to load the slow images in a background thread new AsyncTask<ViewHolder, Void, Drawable>() { private ViewHolder v; private ResolveInfo entry = (ResolveInfo) mListAppInfo.get(position); @Override protected Drawable doInBackground(ViewHolder... params) { v = params[0]; return entry.loadIcon(mPackManager); } @Override protected void onPostExecute(Drawable result) { super.onPostExecute(result); // If this item hasn't been recycled already, hide the // progress and set and show the image v.progress.setVisibility(View.GONE); v.ivAppIcon.setVisibility(View.VISIBLE); v.ivAppIcon.setImageDrawable(result); v.tvAppName.setText(entry.loadLabel(mPackManager)); } }.execute(holder); return v; } static class ViewHolder { TextView tvAppName; ImageView ivAppIcon; ProgressBar progress; //int position; }
几乎就像该位置被设置错误几秒钟.
推荐答案
您可以让视人持有对ASYNCTASK的引用.当convertView != null时,您可以在视图持有的ASYNCTASK上调用cancel(),因为您知道它正在加载的图像对此新行不会正确.在doInBackgrond()和onPostExecute()中,先检查if(!isCancelled()).
static class ViewHolder { TextView tvAppName; ImageView ivAppIcon; ProgressBar progress; AsyncTask task; } public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder; if (convertView == null) { /* inflate new view, make new ViewHolder, etc. */ ... } else { holder = (ViewHolder) convertView.getTag(); holder.task.cancel(); } // always make a new AsyncTask, they cannot be reused holder.task = new AsyncTask ... holder.execute(...); ... }
其他推荐答案
Android的Developer文档有一个很好的部分:
http://developer.android.com/training/displaying- Bitmaps/process-bitmap.html
如上所述,您的ASYNCTASK正在对已经回收的视图保持了难以参考.
其他推荐答案
您可以通过适配器提供视图时将当前项图像视图设置为标准的加载图像,或者无法立即开始.这将始终"重置"图像,同时加载到异步任务上.这可能是保持回收意见性能效益的最佳方法.对于文本来说也是如此.
问题描述
The system seems to be recycling views until it loads the correct position's view in my listview, resulting in duplicated images and text for a few seconds. Can anyone help?
@Override public View getView(final int position, View convertView, ViewGroup parent) { View v = convertView; Log.d("position",""+position); if(v==null){ LayoutInflater inflater = LayoutInflater.from(mContext); v = inflater.inflate(R.layout.layout_appinfo, null); holder = new ViewHolder(); holder.ivAppIcon = (ImageView)v.findViewById(R.id.ivIconApp); holder.tvAppName = (TextView)v.findViewById(R.id.tvNameApp); holder.progress = (ProgressBar)v.findViewById(R.id.progress_spinner); v.setTag(holder); } else { holder = (ViewHolder) v.getTag(); } holder.ivAppIcon.setImageDrawable(null); holder.tvAppName.setText(null); holder.progress.setVisibility(View.VISIBLE); holder.ivAppIcon.setVisibility(View.GONE); // Using an AsyncTask to load the slow images in a background thread new AsyncTask<ViewHolder, Void, Drawable>() { private ViewHolder v; private ResolveInfo entry = (ResolveInfo) mListAppInfo.get(position); @Override protected Drawable doInBackground(ViewHolder... params) { v = params[0]; return entry.loadIcon(mPackManager); } @Override protected void onPostExecute(Drawable result) { super.onPostExecute(result); // If this item hasn't been recycled already, hide the // progress and set and show the image v.progress.setVisibility(View.GONE); v.ivAppIcon.setVisibility(View.VISIBLE); v.ivAppIcon.setImageDrawable(result); v.tvAppName.setText(entry.loadLabel(mPackManager)); } }.execute(holder); return v; } static class ViewHolder { TextView tvAppName; ImageView ivAppIcon; ProgressBar progress; //int position; }
It is almost as if the position is being set wrong for a few seconds.
推荐答案
You can let the ViewHolder hold a reference to the AsyncTask. When convertView != null, you can call cancel() on the AsyncTask held by the ViewHolder since you know the image it is loading will not be correct for this new row. In doInBackgrond() and onPostExecute(), first check if(!isCancelled()) before doing anything.
static class ViewHolder { TextView tvAppName; ImageView ivAppIcon; ProgressBar progress; AsyncTask task; } public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder; if (convertView == null) { /* inflate new view, make new ViewHolder, etc. */ ... } else { holder = (ViewHolder) convertView.getTag(); holder.task.cancel(); } // always make a new AsyncTask, they cannot be reused holder.task = new AsyncTask ... holder.execute(...); ... }
其他推荐答案
Android's developer documentation has a great section on this:
http://developer.android.com/training/displaying-bitmaps/process-bitmap.html
This issue, as stated above, is that your AsyncTask is keeping a hard reference to a view that's already been recycled.
其他推荐答案
You could set the current items image view to a standard loading image or nothing right away when you provide the view via the adapter. This will always "reset" the image, while it is loaded on your async task. This is probably the best approach to keep the performance benefits of the recycled views. Same goes for the text.