Hoe Lee Hoe Lee - 2 months ago 10
Android Question

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

The progressbar cannot show progress if without scroll down and back to same position visit again, detail please check this demo:

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


No exception or error, maybe ListView bug or logic error, anyone have any idea?

DownloadInfo 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;
}
}


FileDownloadTask 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);
}


In the fragment add click listener

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);
}
}
});


I tried to programmatically scroll to bottom and back to top, same no luck, except programmatically scroll to the item position will not show in the first page when enter the fragment initially.

Besides, I tried to invalidate(), invalidateView() notifyDataSetChanged on the adapter, same problem occur, it is possible ListView bug?

Thanks in advanced.

Answer

Nothing wrong with the code above, fully functional. I found the clue in Google ListView IO conference

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

ListView cannot wrap content, else will have bugs showing up. That why I experience such issue.