使用 ProgressDialog 和 AsyncTask 避免样板?

Posted

技术标签:

【中文标题】使用 ProgressDialog 和 AsyncTask 避免样板?【英文标题】:Avoiding boilerplate with ProgressDialog and AsyncTask? 【发布时间】:2019-02-25 09:41:11 【问题描述】:

我有一个包含许多活动的应用程序,其中许多活动使用各种 json Web API 来加载和显示数据。一个常见的模式类似于:

public class MyActivity extends Activity 
    public void OnCreate(Bundle savedInstanceState) 
        ...
        ProgressDialog pd = ProgressDialog.show( ... );

        // This is a custom API which wraps AsynkTask and calls my callback in onPostExecute
        DoWebThing(url, new Callback() 
            public void onSuccess(String json) 
                pd.dismiss();
                // Do other UI stuff with the json data
            
        );
    

这很好用,并且类似于您在 SO 和教程中找到的许多代码 sn-ps。问题是用户可以在后台进程运行时离开页面。在这种情况下,我收到有关泄漏视图(ProgressDialog)的 logcat 错误,然后当我关闭它或执行其他 UI 操作时我会崩溃。

我已尝试在 onSuccess 添加提前签入:

if (!pd.isShowing()) 
    return;

这修复了某些设备上的崩溃问题,但没有解决其他设备上的崩溃问题,我们仍然会收到有关泄漏视图的 logcat 错误。

我尝试用MyActivity.this.isFinishing() 替换pd.isShowing() 检查,这对任何事情都没有帮助(在我目前正在测试的设备上)。仍然得到 logcat 错误并崩溃。

我尝试了MyActivity.this.isDestroyed(),它修复了崩溃,但仅适用于 SDK 17+ 并且仍然出现 logcat 错误。

真正解决这个问题的唯一选择是让我的进度对话框成为成员变量并覆盖OnDestroy()

ProgressDialog mPd;
@Override
protected void onDestroy() 
    super.onDestroy();
    if (mProgressDialog != null) 
        mProgressDialog.dismiss();
        mProgressDialog = null;
    

现在在我的回调中我可以检查mProgressDialog == null

这很好用。没有崩溃,也没有关于泄漏视图的 logcat 错误。但这感觉像是很多样板——我必须将进度对话框设为成员变量,并在我所有(许多)执行后台操作的活动中覆盖 OnDestroy()

我没有看到更好的选择,但在我开始更新大量活动之前想征求第二意见。

【问题讨论】:

仅供参考 ProgressDialog is deprecated 最好继续使用实时数据和架构组件 【参考方案1】:

创建一个 Activity,比如 NetworkBaseActivity。在此活动中创建 ProgressDialog 并处理 onDestroy。还要创建一个名为showMyDialog()hideMyDialog() 的方法来显示和隐藏对话框(来自子类)。现在你所有的后台活动只需要扩展这个活动。显示对话框调用showMyDialog() 并隐藏它调用hideMyDialog()

类似这样的:

public class NetworkBaseActivity extends AppCompatActivity
    ProgressDialog myDialog;
    onCreate(Bundle bundle)
        // initialize myDialog
    

    public void showDialog()
       // show myDialog if not shown
    
    public void hideDialog()
      // hide myDialog if already shown
    
    @Override
    protected void onDestroy() 
        super.onDestroy();
        if (mProgressDialog != null) 
        mProgressDialog.dismiss();
        mProgressDialog = null;
    


public class YourActivity extends NetworkBaseActivity


我将代码直接输入到 *** 中,请原谅我的拼写错误,但你明白了。

【讨论】:

谢谢,我希望避免更改所有活动的基类,但我同意这似乎是最好的选择。

以上是关于使用 ProgressDialog 和 AsyncTask 避免样板?的主要内容,如果未能解决你的问题,请参考以下文章

带有 ProgressDialog 和进度条的 AsyncTask

打开新的 Fragment 和 AsyncTask 时显示 ProgressDialog

Asynctask 和 RecyclerView 适配器中的 Android ProgressDialog

转Android ProgressDialog的使用

Android入门——AlertDialog和ProgressDialog总结

ProgressDialog的详细使用总结