I am trying to show the progress of multiple files while I upload them to Box.com in a ListView. I am using a Donut Progress bar I found from this link https://github.com/lzyzsd/CircleProgress to show the progress for each item in the list.
However, I can't seem to update the UI while I am uploading. The UI is stuck and does not even respond to clicks by the user. The progress bars for each item starts with 0% and only changes to 100% once every upload has finished. All percentage in between are not shown since the UI is stuck.
I am currently using a custom view for each item in the listview. I did that because I wanted each view to implement a progress listener. Then I added each view to their respective async tasks and update the progress from there.
The following is my code:
Adapter I am using for the ListView
public class SurveyListAdapter extends BaseAdapter {
private LayoutInflater inflater;
private LinkedList<File> files;
private static LinkedList<String> savedIDs;
private ViewHolder holder;
private BoxApiFile mFileApi;
private HomeActivity homeActivity;
private int [] progress;
private int mScrollState = AbsListView.OnScrollListener.SCROLL_STATE_IDLE;
private ListView listView;
private File file;
public class ViewHolder {
TextView fileIDTextView;
TextView dateModifiedTextView;
DonutProgress fileUploadProgress;
CustomSurveyView customSurveyView;
UploadToBoxTask uploadTask;
}
public SurveyListAdapter(HomeActivity homeActivity, LinkedList<File> files, ListView listView) {
this.homeActivity = homeActivity;
inflater = LayoutInflater.from(homeActivity);
this.files = files;
savedIDs = new LinkedList<>();
progress = new int [files.size()];
this.listView = listView;
}
public int getCount() {
return files.size();
}
public File getItem(int position) {
return files.get(position);
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
file = files.get(position);
holder = null;
if(convertView == null) {
holder = new ViewHolder();
convertView = inflater.inflate(R.layout.survey_list_view, null);
holder.customSurveyView = (CustomSurveyView) convertView.findViewById(R.id.customSurveyView);
holder.fileUploadProgress = holder.customSurveyView.getDonutProgress();
holder.fileIDTextView = holder.customSurveyView.getFileIDTextView();
holder.dateModifiedTextView = holder.customSurveyView.getDateModifiedTextView();
holder.uploadTask = new UploadToBoxTask(this, holder.customSurveyView, file);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
String fileName = file.getName();
String fileShouldStartWith = HomeActivity.FILE_SHOULD_START_WITH;
String fileShouldEndWith = HomeActivity.FILE_SHOULD_END_WITH;
String ID = fileName.substring(fileShouldStartWith.length(), fileName.length() - fileShouldEndWith.length()).trim();
savedIDs.add(ID);
SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy hh:mm a");
String lastDateModified = sdf.format(file.lastModified());
holder.fileIDTextView.setText("Subject ID " + ID);
holder.dateModifiedTextView.setText(lastDateModified);
return convertView;
}
public View getViewByPosition(int pos) {
final int firstListItemPosition = listView.getFirstVisiblePosition();
final int lastListItemPosition = firstListItemPosition + listView.getChildCount() - 1;
if (pos < firstListItemPosition || pos > lastListItemPosition ) {
return listView.getAdapter().getView(pos, null, listView);
} else {
final int childIndex = pos - firstListItemPosition;
return listView.getChildAt(childIndex);
}
}
public static LinkedList<String> getSavedIDs() {
return savedIDs;
}
public void syncWithBox(BoxApiFile mFileApi){
this.mFileApi = mFileApi;
ExecutorService executor = Executors.newSingleThreadExecutor();
for (int i = 0; i < files.size(); i++) {
ViewHolder holder = (ViewHolder) getViewByPosition(i).getTag();
holder.fileUploadProgress.setVisibility(View.VISIBLE);
holder.uploadTask.executeOnExecutor(executor);}
executor.shutdown();
while (!executor.isTerminated()) { }
System.out.println("Finished uploading");
}
private class UploadToBoxTask extends AsyncTask<Void, Integer, Void>{
SurveyListAdapter surveyListAdapter;
BoxUploadProgressListener progressListener;
File uploadFile;
public UploadToBoxTask(SurveyListAdapter surveyListAdapter, BoxUploadProgressListener progressListener, File uploadFile){
this.surveyListAdapter = surveyListAdapter;
this.progressListener = progressListener;
this.uploadFile = uploadFile;
}
@Override
protected Void doInBackground(Void... params) {
try {
final BoxRequestsFile.UploadFile request = mFileApi.getUploadRequest(uploadFile, BoxConstants.ROOT_FOLDER_ID);
request.setProgressListener(new ProgressListener() {
@Override
public void onProgressChanged(long numBytes, long totalBytes) {
publishProgress((int) (100 * (numBytes/totalBytes)));
}
});
final BoxFile uploadFileInfo = request.send();
showToast("Uploaded " + uploadFileInfo.getName());
//loadRootFolder();
} catch (BoxException e) {
BoxError error = e.getAsBoxError();
if (error != null && error.getStatus() == HttpURLConnection.HTTP_CONFLICT) {
ArrayList<BoxEntity> conflicts = error.getContextInfo().getConflicts();
if (conflicts != null && conflicts.size() == 1 && conflicts.get(0) instanceof BoxFile) {
//uploadNewVersion((BoxFile) conflicts.get(0), position, adapter);
publishProgress(100);
return null;
}
}
showToast("Upload failed");
e.printStackTrace();
}
return null;
}
@Override
protected void onProgressUpdate(Integer... integers){
progressListener.onProgressUpdate(integers[0]);
showToast(String.valueOf(integers[0]));
}
@Override
protected void onPostExecute(Void param){
}
}
}
The custom view I created:
public class CustomSurveyView extends RelativeLayout implements BoxUploadProgressListener{
View rootView;
LinearLayout linearLayout;
TextView fileIDTextView;
TextView dateModifiedTextView;
DonutProgress donutProgress;
public CustomSurveyView(Context context) {
super(context);
init(context);
}
public CustomSurveyView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
private void init(Context context) {
rootView = inflate(context, R.layout.custom_survey_view, this);
linearLayout = rootView.findViewById(R.id.fileInfoLayout);
fileIDTextView = rootView.findViewById(R.id.fileIDTextView);
dateModifiedTextView = rootView.findViewById(R.id.dateModifiedTextView);
donutProgress = rootView.findViewById(R.id.fileUploadProgressBar);
}
@Override
public void onProgressUpdate(int progress) {
donutProgress.setVisibility(View.VISIBLE);
ObjectAnimator anim = ObjectAnimator.ofInt(donutProgress, "progress", donutProgress.getProgress(), progress);
donutProgress.setProgress(progress);
anim.setInterpolator(new DecelerateInterpolator());
anim.setDuration(500);
anim.start();
invalidate();
}
public LinearLayout getLinearLayout() {
return linearLayout;
}
public TextView getFileIDTextView() {
return fileIDTextView;
}
public TextView getDateModifiedTextView() {
return dateModifiedTextView;
}
public DonutProgress getDonutProgress() {
return donutProgress;
}
}
Progress listener interface I created
public interface BoxUploadProgressListener {
void onProgressUpdate(int progress);
}
This is what my layout looks like
Please help correctly update the UI with the progress of each upload. I've been at this for two days now.
I found the problem. Its the while loop I put after the executor. It kept on running till all tasks were finished.