【问题标题】:How to present a progress screen before/while a long running operation starts?如何在长时间运行的操作开始之前/期间显示进度屏幕?
【发布时间】:2014-07-04 07:05:55
【问题描述】:

我很清楚,阻止 UI 通常不是一个好主意,但在某些情况下,我的应用在某些长时间运行的操作(例如从服务器加载数据)完成之前无法执行任何其他工作。

假设用户点击了“加载数据”按钮。为了表明在加载数据之前无法进行 UI 交互,我想将屏幕变灰并显示某种活动指示器。这完全没问题,我只是在屏幕上覆盖了一个新的 Fragment。

问题是:如何呈现这个叠加片段?

public void onLoadDataClick() {
    // grey out the screen by simple showing a new Fragment
    showActivityIndicatorOverlay();

    // Start the long running opeartion
    doVeryMuchWork();

    dismissActivityIndicatorOverlay();
}

public void showActivityIndicatorOverlay() {
    FragmentTransaction ft = context.getSupportFragmentManager().beginTransaction();
    ActivityIndicatorOverlayFragment overlayFragment = ActivityIndicatorOverlayFragment.newInstance("Loading Data");        
    overlayFragment.show(ft, "activityIndicator");
} 

这不起作用。叠加层不显示。如果我删除 dismissActivityIndicatorOverlay() 覆盖显示长时间运行的操作完成。这并不太令人惊讶:我假设显示新片段是在当前运行循环结束或下一个循环开始时处理的。当然,长时间运行的操作必须在运行循环结束之前完成,因此覆盖显示得太晚了......

显而易见的解决方案当然是使用AsyncTask 在后台线程中运行操作:

public void onLoadDataClick() {
    LoadDataTask loadTask = new LoadDataTask();
    loadTask.execute();
}

private class LoadDataTask extends AsyncTask<Void, Void, Void> {
    @Override
    protected void onPreExecute() {
        showActivityIndicatorOverlay();
    }

    @Override
    protected Void doInBackground(Void... params) {
        doVeryMuchWork();
    }

    @Override
    protected void onPostExecute() {
        dismissActivityIndicatorOverlay();
    }
}

我很惊讶,这个解决方案也不起作用。它的行为与第一种方法完全一样:没有出现覆盖。当onPostExecute() 被移除时,覆盖会在操作完成后出现。这是为什么呢?

呈现这种活动指标的正确解决方案是什么?

【问题讨论】:

  • 我认为最好的方法是使用 ProgressBar 来满足您的要求。

标签: java android multithreading android-fragments android-asynctask


【解决方案1】:

我建议使用ProgessDialog

将 ProgressDialog 声明为实例变量。比如:ProgressDialog pDialog;

然后在 onCreate() 内部:

pDialog = new ProgressDialog(this);
//The next two methods will ensure that the user is unable to 
//cancel the Progress Dialog unless you explicitly 
//do so by calling `pDialog.dismiss();`
pDialog.setCancelable(false);
pDialog.setCanceledOnTouchOutside(false);

修改 AsyncTask 有点像这样:

private class LoadDataTask extends AsyncTask<Void, Void, Void> {
    @Override
    protected void onPreExecute() {
        pDialog.setMessage("Loading Data.. Please Wait.");
        pDialog.show();
    }

    @Override
    protected Void doInBackground(Void... params) {
        doVeryMuchWork();
    }

    @Override
    protected void onPostExecute() {
        pDialog.dismiss();
    }
}

【讨论】:

  • 非常感谢!我的覆盖片段似乎存在某种问题。当使用 ProgressDialog 时,一切正常。这个答案很好,但 Aniruddha 有点快,所以我接受了他的...
  • @AndreiHerford 我想这并不重要,但是查看 Aniruddha 帖子中的编辑历史记录。他基本上回答了完全不同的东西,然后改变了答案。不过,Shivam 仍然比我快半分钟 :)
  • 好的,好的。我更改了已接受的答案,希望每个人都能接受 :-) 非常感谢!
  • @matiash 半分钟! :D
  • 虽然我没有任何赞成票 :D @matiash 我也解释了如何调用 AsyncTask 以及关于 context,你没有。!
【解决方案2】:

ProgressDialog 是这些情况的典型解决方案...

private class LoadDataTask extends AsyncTask<Void, Void, Void> {
    private ProgressDialog mProgress;

    @Override
    protected void onPreExecute() {
        mProgress = new ProgressDialog(context);
        mProgress.setTitle("So much to do");
        mProgress.setMessage("Doing very much work");
        mProgress.setIndeterminate(true);
        mProgress.setCancelable(false);
        mProgress.show();
    }

    @Override
    protected Void doInBackground(Void... params) {
        doVeryMuchWork();
    }

    @Override
    protected void onPostExecute() {
        mProgress.dismiss();
    }
}   

至于您尝试的解决方案,由于您所说的原因,第一个方法不起作用。不过,第二个应该

【讨论】:

  • 非常感谢!我的覆盖片段似乎存在某种问题。当使用 ProgressDialog 时,一切正常。这个答案很好,但 Aniruddha 有点快,所以我接受了他的...
【解决方案3】:

如果你不是在 setContentView(R.layout.main) 上做繁重的工作,你可以这样做

public void onCreate(Bundle savedInstanceState){
    super.onCreate(savedInstanceState);
    setContentView(R.layout.splash);

    handler = new Handler();

    new AsyncTask<Void, Void, Void>() {

    @Override
    protected Void doInBackground(Void... params) {
            //Do some heavy stuff
            return null;
        } 

        @Override
        public void onPostExecute(Void result){
            handler.post(new Runnable(){
                 @Override
                 public void run(){
                     setContentView(R.layout.main);
                 }
            });
        }
   }.execute();
}

或者您可以使用进度对话框

private class LongTask extends AsyncTask<Void, Void, Void> {
private ProgressDialog pd;
Context context;

public LongTask(Context c)
{

     this.context = c;
}

@Override
protected void onPreExecute() {
    pd = new ProgressDialog(context);
    pd.setTitle("Please wait...!");
    pd.setMessage("Loding the information");
    pd.setIndeterminate(true);
    pd.setCancelable(false);
    pd.show();
}

@Override
protected Void doInBackground(Void... params) {
    // do your heavy tasks here
}

@Override
protected void onPostExecute() {
    if (pd.isShowing())
     pd.dismiss();
}

}

像这样调用 AsyncTask

new LongTask(your_activity.this).execute();

【讨论】:

  • 多次使用setContentView() 不是最好的主意,但是android 不会阻止你这样做;)
  • 非常感谢!我的覆盖片段似乎存在某种问题。当使用ProgressDialog 时,一切正常...
猜你喜欢
  • 1970-01-01
  • 2011-05-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多