如果异步任务被解除,则重新显示进度对话框

Posted

技术标签:

【中文标题】如果异步任务被解除,则重新显示进度对话框【英文标题】:Reshow a progress dialog from Async Task if it gets dismissed 【发布时间】:2021-06-22 07:26:35 【问题描述】:

我有一个进度对话框,显示在我的异步任务中还有多少文件要上传,如果用户愿意,可以关闭此对话框。但是我想要一个按钮,它能够在当前阶段再次显示该进度对话框,我不知道该怎么做,因为我不能只在异步任务中创建一个函数并从不同的活动。有什么想法吗?

【问题讨论】:

【参考方案1】:

您可以创建一个单例类来处理仅包含一个侦听器(想要侦听 AsyncTask 进度的 Activity)的异步任务进度。 您的 Singleton 类可以如下所示:

public class ProgressDialogUtil 

    public interface ProgressDialogUtilListener
        void showProgressDialog();
        void dismissProgressDialog();
        void updateProgressDialog(int value);
        void setProgressDialogMessage(String message);
    

    private ProgressDialogUtilListener listener;
    private static ProgressDialogUtil mInstance;
    public static ProgressDialogUtil getInstance() 
        if (mInstance == null) 
            synchronized (ProgressDialogUtil.class) 
                if (mInstance == null) 
                    mInstance = new ProgressDialogUtil();
                
            
        
        return mInstance;
    

    public void setListener(ProgressDialogUtilListener listener) 
        this.listener = listener;
    

    public void showProgressDialog()
        if(listener!=null)
            listener.showProgressDialog();
    

    public void dismissProgressDialog()
        if(listener!=null)
            listener.dismissProgressDialog();
    

    public void updateProgressDialog(int value)
        setProgressDialogMessage("Files Downloaded: "+ value);
        if(listener!=null)
            listener.updateProgressDialog(value);
    

    public void setProgressDialogMessage(String message)
        if(listener!=null)
            listener.setProgressDialogMessage(message);
    

然后你可以在你的 AsyncTask 中使用这个 Singleton 类 (ProgressDialogUtil) 来通知发生的任何更新:

public class MyAsyncTask extends AsyncTask<Void, Integer, Boolean> 

    public final ProgressDialogUtil progressDialogUtil;

    public MyAsyncTask(ProgressDialogUtil progressDialogUtil)
       this.progressDialogUtil = progressDialogUtil;
    

    @MainThread
    @Override
    protected void onPreExecute() 
        super.onPreExecute();
        progressDialogUtil.setProgressDialogMessage("Start Download files..");
        progressDialogUtil.showProgressDialog();
    

    @WorkerThread
    @Override
    protected Boolean doInBackground(Void... params) 
        //download your files here in the Background Thread...
        //below is a sample loop
        for (int i=0; i <= 50; i++) 
            try 
                Thread.sleep(1000);
                publishProgress(i);
             catch (InterruptedException e) 
                e.printStackTrace();
                return false;
            
        
        return true;
    

    @MainThread
    @Override
    protected void onProgressUpdate(Integer... values) 
        super.onProgressUpdate(values);
        progressDialogUtil.updateProgressDialog(values[0]);
    

    @MainThread
    @Override
    protected void onPostExecute(Boolean result) 
        super.onPostExecute(result);
        progressDialogUtil.setProgressDialogMessage("Finished Download!");
        progressDialogUtil.dismissProgressDialog();
    

然后在您启动 AsyncTask 的第一个 Activity 中,您可以创建进度对话框的新实例并设置监听器 ProgressDialogUtilListener 来监听任何 AsyncTask 进度以显示/隐藏/更新进度对话框如下:

ProgressDialog pd = new ProgressDialog(this);
ProgressDialogUtil progressDialogUtil = ProgressDialogUtil.getInstance();
progressDialogUtil.setListener(new ProgressDialogUtil.ProgressDialogUtilListener()

    @Override
    public void showProgressDialog() 
       if (!pd.isShowing())
          pd.show();
    
    @Override
    public void dismissProgressDialog() 
        if (pd.isShowing())
            pd.dismiss();
    
    @Override
    public void updateProgressDialog(int value) 
       pd.setProgress(value);
    
    @Override
    public void setProgressDialogMessage(String message) 
       pd.setMessage(message);
    
);
new MyAsyncTask(progressDialogUtil).execute();

最后,当您导航到新 Activity 时,您可以使用相同的单例实例 ProgressDialogUtil 并将侦听器更改为新 Activity 现在所有 AsyncTask 事件都将被处理到新 Activity 并且对话框可以通过这个单例类通过按钮打开/关闭,如下所示:

ProgressDialog pd = new ProgressDialog(this);
ProgressDialogUtil progressDialogUtil = ProgressDialogUtil.getInstance();
progressDialogUtil.setListener(new ProgressDialogUtil.ProgressDialogUtilListener()

   @Override
   public void showProgressDialog() 
       if (!pd.isShowing())
           pd.show();
   
   @Override
   public void dismissProgressDialog() 
       if (pd.isShowing())
           pd.dismiss();
   
   @Override
   public void updateProgressDialog(int value) 
          pd.setProgress(value);
   
   @Override
   public void setProgressDialogMessage(String message) 
         pd.setMessage(message);
   
 );

 //Show Progress Dialog from a Button Click
 showButton.setOnClickListener(new View.OnClickListener() 
    @Override
    public void onClick(View v) 
        progressDialogUtil.showProgressDialog();
    
);

//Dismiss Progress Dialog from a Button Click
dismissButton.setOnClickListener(new View.OnClickListener() 
    @Override
    public void onClick(View v) 
       progressDialogUtil.dismissProgressDialog();
    
);

【讨论】:

非常感谢!!这实际上看起来可以解决我所有的问题,甚至解决在不同活动中出现进度对话框的问题。尝试后我会将其标记为解决方案! 总是不鼓励使用 Singleton....我更喜欢使用 ViewModel 和 LiveData 来获得更好、更简洁的代码。 en.m.wikipedia.org/wiki/Singleton_pattern#Drawbacks 和code.google.com/p/google-singleton-detector/wiki/… 基本上单例刹车面向对象机制,被过度使用(尤其是新手程序员),就像一个全局变量(全局变量总是不好的),很难测试一个类使用Singletons的,访问Singleton的Resources应该在多线程环境下序列化等等。Java中Singletons的Cons/drawss有很多文章。 @cylegend 不要忘记在活动onDestroy()回调中调用progressDialogUtil.setListener(null),否则当用户导航到另一个活动时可能会导致内存泄漏。 @cylegend 在活动之间共享进度值的唯一可能方法是使用单例模式,或者使用监听器或 LiveData。 AsyncTask 只知道一个实例来发送进度,并且任何 Activity 都可以观察或侦听此进度。 Rajesh.k 他在 onDestroy() 回调中是正确的,您必须设置 progressDialogUtil.setListener(null) 以避免内存泄漏。 Rajesh.k 的答案也是正确的,这是您可以在 Singleton 类中使用 LiveData 的方式。【参考方案2】:

您可以在任何单例类中拥有实时数据,如下所示,以共享活动之间的进度。

object ProgressHelper 
val progress = MutableLiveData<Int>()

然后从 AsyncTask 更新进度值,如下所示:

  override fun onProgressUpdate(vararg values: Int?) 
      super.onProgressUpdate(*values)
       ProgressHelper.progress.value = 100
  
 

在您的活动中,您可以观察如下进度:

  ProgressHelper.progress.observe(this, Observer  
     val progress = it
 )

【讨论】:

以上是关于如果异步任务被解除,则重新显示进度对话框的主要内容,如果未能解决你的问题,请参考以下文章

异步任务进度对话框需要很长时间才能完成 android 中的简单任务

使用异步任务制作进度对话框

在异步任务中给出异常的进度对话框[重复]

异步任务的进度对话框

如何关闭带有异步任务的进度对话框并避免“您的活动是不是运行错误?”

在 AsyncTask 中显示进度对话框