UI 尝试在列表视图中显示每个文件上传的进度时卡住了

UI stuck while trying to show progress of each file upload in listview

我试图在将多个文件上传到 ListView 中的 Box.com 时显示它们的进度。我正在使用从 link https://github.com/lzyzsd/CircleProgress 中找到的甜甜圈进度条来显示列表中每个项目的进度。

但是,我在上传时似乎无法更新 UI。 UI 卡住,甚至不响应用户的点击。每个项目的进度条从 0% 开始,只有在每次上传完成后才会变为 100%。由于 UI 被卡住,因此未显示中间的所有百分比。

我目前正在为列表视图中的每个项目使用自定义视图。我这样做是因为我希望每个视图都实现一个进度侦听器。然后我将每个视图添加到它们各自的异步任务中并从那里更新进度。

以下是我的代码:

我为 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){

    }
}
}

我创建的自定义视图:

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

我创建的进度监听器界面

public interface BoxUploadProgressListener {
    void onProgressUpdate(int progress);
}

这是我的布局的样子

请帮助正确更新 UI 每次上传的进度。我已经在这里待了两天了。

可能的原因:

  1. 避免从异步任务

  2. 更改Ui
  3. 避免在每个持有者实例中添加新线程,这会增加 RAM 消耗,因为应用程序没有响应。

在主线程中创建接口并更新 UI。

我发现了问题。它是我放在执行程序之后的 while 循环。它一直在 运行 直到所有任务都完成。