我想要显示包含一些文本和图像的列表视图。当我为listview创建一个视图时,我正在调用我的PictureImageView的方法show,它会下载并显示图像。下载正在AsyncTask中的新线程中运行。但是图像下载时我无法正常滚动列表视图,这是抽搐。 要在新线程中运行AsyncTask,我调用executeOnExecutor方法。我试图调用execute方法,但滚动停止,直到下载结束。
我的班级。
public class PictureImageView extends LinearLayout {
private Drawable image_drawable = null;
private ImageView image = null;
...
protected String getImageURL() {
...
return uri;
}
public void show() {
if (image_drawable != null) {
image.setImageDrawable(image_drawable);
addView(image);
} else {
// target Android API >= 14 so executeOnExecutor works in another thread
new RequestTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, getImageURL());
}
}
protected void onResponse(Drawable image) {
if (image != null) {
image_drawable = image;
show();
}
}
class RequestTask extends AsyncTask<String, String, Drawable> {
@Override
protected Drawable doInBackground(String... urls) {
Drawable image = null;
HttpURLConnection connection = null;
InputStream connection_stream = null;
try {
URL url = new URL(urls[0]);
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setUseCaches(true);
connection.connect();
int response_code = connection.getResponseCode();
//@see http://libs-for-android.googlecode.com/svn/reference/com/google/android/filecache/FileResponseCache.html
if (response_code == HttpURLConnection.HTTP_OK || response_code == -1) {
connection_stream = connection.getInputStream();
image = Drawable.createFromStream(connection_stream, null);
}
} catch (MalformedURLException e) {
} catch (IOException e) {
} finally {
if (connection != null) {
connection.disconnect();
}
if (connection_stream != null) {
try {
connection_stream.close();
} catch (IOException e) {
}
}
}
return image;
}
@Override
protected void onPostExecute(Drawable image) {
PictureImageView.this.onResponse(image);
}
}
}
我该如何解决?我想,问题是没有任何其他线程,但如何检查它?
答案 0 :(得分:1)
我亲自解决了这个确切的问题。每次下载图片时都会更新ListView
。我采取了两种不同的方法来解决这个问题。根据您的项目设置我的工作
方法1:只更新一次
,尽量减少抽搐在我的情况下,我使用AsyncTask
作为单独的类,并回调起始活动。我所做的是使用singleThreadExecutor
,以便下载每个用户的图片的任务被串行执行,并且计数器跟踪有多少踏板被启动/离开 - 每次我向执行器添加一个踏板时递增,每次递减回电被叫了。例如
@Override
public void userPic(Bitmap pic){
if(pic != null){
//use picture
}
taskCounter--
if(taskCounter == 0){
updateUserListView();
}
}
通过更新所有线程完成后,我可以通过仅刷新列表一次来最小化抽搐,从而允许滚动并仅在完成所有图片后跳回到顶部
方法2:使用mem cache消除抽搐
最终我所做的就是使用缓存来存储位图。这种方法完全消除了跳转问题,因为列表不再被刷新,而是适配器仅在视图被回收时才从缓存加载位图。我仍然使用单独的任务回调
@Override
public void userPic(Bitmap pic){
if(pic != null){
memCache.addPicture(pic);
}
}
只是这次而不是直接更新列表,如果下载了图片,我将其存储到缓存中。然后在我的适配器代码中,我将picutre字段设置为从缓存中更新(如果存在)
if(picture_view != null){
if(memCache.contains(u.getId()){
picture_view.setImageBitmap(memCache.getPicture(u.getId()));
} else {
picture_view.setImageBitmap(memCache.getPicture("default"));
}
这种方法优先考虑这样一个事实,即视图在被回收后自动更新为ListView
。滚动并重建视图时,适配器将自动使用新数据填充字段(如果已更改)。
下行 - 列表不会自动升级。如果为当前可见的字段下载图片,则在您从该视图滚动之前不会更新这些图片。此外,在创建缓存时稍微设置一下。我选择使用singelton模式来执行此操作,因为我从多个位置访问缓存(例如,在一个位置添加图片并进入另一个位置)。