首次进入片段ListView时AsyncTask无法更新progressBar的进度,然后滚动ListView后就可以了

Fail to AsyncTask update progressBar's progress when first enter the fragment ListView, then okay after scroll ListView

如果不向下滚动并返回同一位置再次访问,进度条将无法显示进度,详情请查看此演示:

https://www.youtube.com/watch?v=wGu8MyUHidQ&feature=youtu.be

没有异常或错误,可能是 ListView 错误或逻辑错误,有人知道吗?

下载信息class:

private final static String TAG = DownloadInfo.class.getSimpleName();
public enum DownloadState {
    NOT_STARTED,
    QUEUED,
    DOWNLOADING,
    COMPLETE
}
private volatile DownloadState mDownloadState = DownloadState.NOT_STARTED;
private final String mFilename;
private volatile Integer mProgress;
private final Integer mFileSize;
private volatile ProgressBar mProgressBar;

public DownloadInfo(String filename, Integer size) {
    mFilename = filename;
    mProgress = 0;
    mFileSize = size;
    mProgressBar = null;
}
//Follow by getters & setters

DownloadInfoArrayAdapter Class:

public class DownloadInfoArrayAdapter extends ArrayAdapter<DownloadInfo> {
private static class ViewHolder {
    TextView textView;
    ProgressBar progressBar;
    Button button;
    DownloadInfo info;
}

public DownloadInfoArrayAdapter(Context context, List<DownloadInfo> objects) {
    super(context, objects);
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    View row = convertView;
    final DownloadInfo info = getItem(position);

    ViewHolder holder = null;

    if (null == row) {
        LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        row = inflater.inflate(R.layout.file_download_row, parent, false);

        holder = new ViewHolder();
        holder.textView = (TextView) row.findViewById(R.id.downloadFileName);
        holder.progressBar = (ProgressBar) row.findViewById(R.id.downloadProgressBar);
        holder.button = (Button) row.findViewById(R.id.downloadButton);
        holder.info = info;
        row.setTag(holder);
    } else {
        holder = (ViewHolder) row.getTag();
        holder.info.setProgressBar(null);
        holder.info = info;
        holder.info.setProgressBar(holder.progressBar);
    }

    holder.textView.setText(info.getFilename());
    holder.progressBar.setProgress(info.getProgress());
    holder.progressBar.setMax(info.getFileSize());
    info.setProgressBar(holder.progressBar);

    holder.button.setEnabled(info.getDownloadState() == DownloadState.NOT_STARTED);
    final Button button = holder.button;
    holder.button.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
            info.setDownloadState(DownloadState.QUEUED);
            button.setEnabled(false);
            button.invalidate();
            FileDownloadTask task = new FileDownloadTask(info);
            task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
        }
    });
    return row;
}
}

文件下载任务class:

@Override
protected void onProgressUpdate(Integer... values) {
    mInfo.setProgress(values[0]);
    ProgressBar bar = mInfo.getProgressBar();
    if (bar != null) {
        bar.setProgress(mInfo.getProgress());
        bar.invalidate();
    }
}

@Override
protected Void doInBackground(Void... params) {
    Log.d(TAG, "Starting download for " + mInfo.getFilename());
    mInfo.setDownloadState(DownloadState.DOWNLOADING);
    for (int i = 0; i <= mInfo.getFileSize(); ++i) {
        try {
            Thread.sleep(16);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        publishProgress(i);
    }
    mInfo.setDownloadState(DownloadState.COMPLETE);
    return null;
}

@Override
protected void onPostExecute(Void result) {
    mInfo.setDownloadState(DownloadState.COMPLETE);
}

@Override
protected void onPreExecute() {
    mInfo.setDownloadState(DownloadState.DOWNLOADING);
}

在片段中添加点击监听器

lvStickerGroup = (ListView) activity.findViewById(R.id.lvStickerGroup);
    List<DownloadInfo> downloadInfo = new ArrayList<DownloadInfo>();
    for (int i = 0; i < 50; ++i) {
        downloadInfo.add(new DownloadInfo("File " + i, 1000));
    }

    adapter = new DownloadInfoArrayAdapter(activity, downloadInfo);
    lvStickerGroup.setAdapter(adapter); 
    lvStickerGroup.setOnItemClickListener(new AdapterView.OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
            Toast.makeText(activity, "bla" + i, Toast.LENGTH_SHORT).show();
        }
    });

    //Testing all below, no luck
    ((BaseAdapter) adapter).notifyDataSetChanged();
    lvStickerGroup.invalidate();
    lvStickerGroup.invalidateViews();
    lvStickerGroup.refreshDrawableState();

    lvStickerGroup.post(new Runnable() {
        public void run() {
            for (int a = 0; a < lvStickerGroup.getCount(); a++) {
                lvStickerGroup.setSelection(a);
            }
            for (int a = lvStickerGroup.getCount() - 1; a >= 0; a--) {
                lvStickerGroup.setSelection(a);
            }
        }
    });

我尝试以编程方式滚动到底部并返回到顶部,同样没有运气,除了以编程方式滚动到最初输入片段时不会显示在第一页的项目位置。

此外,我尝试在适配器上使用 invalidate()、invalidateView() notifyDataSetChanged,出现同样的问题,可能是 ListView 错误?

在此先致谢。

上面的代码没问题,功能齐全。我在 Google ListView IO 会议

中找到了线索
https://www.youtube.com/watch?v=wDBM6wVEO70

ListView 不能包裹内容,否则会出现错误。这就是为什么我遇到这样的问题。