第一次进入片段ListView时AsyncTask更新progressBar的进度失败,滚动ListView后就ok了

Posted

技术标签:

【中文标题】第一次进入片段ListView时AsyncTask更新progressBar的进度失败,滚动ListView后就ok了【英文标题】:Fail to AsyncTask update progressBar's progress when first enter the fragment ListView, then okay after scroll ListView 【发布时间】:2017-02-02 09:57:50 【问题描述】:

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

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

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

DownloadInfo 类:

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

下载InfoArrayAdapter 类:

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;


FileDownloadTask 类:

@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 bug?

提前致谢。

【问题讨论】:

你的视频有什么奇怪的地方?请具体。 第一次进入显示ListView的fragment在触发按钮后不会更新进度条,只有向下滚动回到同一个item只有进度条才会显示进度。进度条只是使用一些简单的增量进行测试,睡眠时间为 16 毫秒,它从 ayncTask 更新回 UI... 访问minimal reproducible example并按比例编辑您的问题。 对不起,我知道我的问题太宽泛了,我已经尽力了,无法记录任何异常...我尝试了几天在 ListView 中实现平滑的进度条,最后我找到了代码github,但真的不知道为什么不能在片段中实现,在活动中按预期工作......:/ 这是很多代码,没有解释你正在尝试什么或你正面临的问题。请添加一些文本来解释您期望什么以及运行代码时发生的情况。您可能想显示一些屏幕截图以帮助我们更好地解释。 【参考方案1】:

上面的代码没有错,功能齐全。我在 Google ListView IO 大会上找到了线索

https://www.youtube.com/watch?v=wDBM6wVEO70

ListView 不能包装内容,否则会出现错误。这就是我遇到此类问题的原因。

【讨论】:

以上是关于第一次进入片段ListView时AsyncTask更新progressBar的进度失败,滚动ListView后就ok了的主要内容,如果未能解决你的问题,请参考以下文章

使用 AsyncTask 从 JSON 中获取数据

在滚动侦听器上调用 asynctask 三次或多次在 listview 上滚动一次

使用 asynctask 在所有 Fragment 中的 Activity 中显示 ListView

带有 ListView Asynctask 的多下载器

Android如何在数据进入后设置listview适配器

ArrayList.add 不适用于 AsyncTask