zoukankan      html  css  js  c++  java
  • AsyncTask Missteps

    What's the Problem?

    QA raise an incident, through the stack trace I know it's Dialog.show() called after Activity being destoryed. Specific to the code, we new a LoginTask in LoginActivity, if failed, we will show a dialog in onPostExecute(), crash happens when the Activity is destoryed but we still call the dialog.show() function.

    So I solve this incident by surround the dialog.show() with an if block:

    1 if(!isFinishing()) {
    2     dialog.show();
    3 }

    Everything seems to be fine, problem solved and minimum code changed. But ** point out two issues after review the submission:

    1.. "If isFinishing is true, we probably don’t want to do any UI work." Except for dialog.show(), we also do many other UI work in onPostExcute().

    2.. There may be same issue in other activities where an AsyncTask is used.

    For the first question, indeed, the UI work is useless if Activity isFinishing, but as it also do no harm, so we can let them go. But for the second question, I do find a similar question in AccountSignupActivity.java  , in SignupTask's onPostExecute() we also call dialog.show().

    So the question is, how to use AsyncTask properly?

    Is AsyncTask Really Entirely Flawed?

    There is an interesting question in StackOverflow  which pinpoint the problem:

    1.. AsyncTask "allows to perform background operations and publish results on the UI thread without having to manipulate threads and/or handlers.";

    2.. But when we call dialog.show() in onPostExecute() it may cause a crash.

    3.. Solve this problem we can use a Handler.

    4.. But AsyncTask's role is to help us get rid of handler.

    There are many answers under this question, but I'm not satisfied or not understood until I found this blog  .

    AsyncTask Missteps

    This blog(http://www.shanekirk.com/2012/04/asynctask‑missteps/ ) is really worth reading, it draws the problems and the solutions step by step. I'll quote the "One For All" solution here, but firstly let's summarize the problem:

    1.. Dialog.show() crash happens when we reference a destroyed Activity, so maybe we can't reference the Activity in AsyncTask;

    2.. But if we can't reference to an Activity, how can we update the UI?

    3.. What will happen if the Activity destroyed but re‑create again? Further more, what will happen if the AsyncTask is running or after the AsyncTask has completed?

    4.. There is concurrent AsyncTask limitations  .

    Here goes the solution:

    复制代码
     1 public class MyActivity extends Activity
     2 {
     3     @Override
     4     public void onCreate(Bundle savedInstanceState)
     5     {
     6         super.onCreate(savedInstanceState);
     7         setContentView(R.layout.main);
     8  
     9         // Find views and assign them to member variables.
    10  
    11         m_task = (MyTask) getLastNonConfigurationInstance();
    12         if (m_task != null)
    13         {
    14             m_task.m_activity = this;
    15             if (m_task.m_isFinished)
    16                 m_task.updateUI();
    17         }
    18         else
    19         {
    20             m_task = new MyTask();
    21             m_task.m_activity = this;
    22             m_task.execute();
    23         }
    24     }
    25  
    26     @Override
    27     public void onDestroy()
    28     {
    29         super.onDestroy();
    30  
    31         m_task.m_activity = null;
    32  
    33         if (this.isFinishing())
    34             m_task.cancel(false);
    35     }
    36  
    37     @Override
    38     public Object onRetainNonConfigurationInstance()
    39     {
    40         return m_task;
    41     }
    42  
    43  
    44     static class MyTask extends AsyncTask<Void, Void, String>
    45     {
    46         @Override
    47         protected String doInBackground(Void... params)
    48         {
    49             // Do some long running task. We need to make sure
    50             // we peridically check the return value of isCancelled().
    51             return result;
    52         }
    53  
    54         @Override
    55         protected void onPostExecute(String result)
    56         {
    57             m_result = result;
    58             m_isFinished = true;
    59             updateUI();
    60         }
    61  
    62         public void updateUI()
    63         {
    64             if (m_activity != null)
    65             {
    66                 // Update UI using m_result
    67             }           
    68         }
    69  
    70         // These should never be accessed from within doInBackground()
    71         MyActivity m_activity = null;
    72         boolean m_isFinished  = false;
    73         String m_result = null;
    74     }
    75  
    76     private MyTask m_task = null;
    77  
    78     // Various View member variables.
    79 
    80 }
    复制代码

    The problem solved by:

    1.. Remove the implicit pointer by make the AsyncTask static

    2.. Give an explicit Activity reference back to AsyncTask to direct control their relationships.

    3.. Use a so called "connect/disconnect" pattern to handle the destroyed then re‑create problem.

    4.. Cancel the AsyncTask in onDestory().

    Keep in Mind

    Maybe there is no "One For All" solution, but there is one thing we must keep in mind: Never ever call dialog.show() or that kind of function without a check.
     I still don't know the full function list that will cause a crash except for dialog.show(), maybe we need not do any UI work if the Activity isFinishing, as **suggested.

    Reference

    • Incident: https://engtools.engba.symantec.com/Etrack/readonly_inc.php?incident=3028953

    • AsyncTask: https://developer.android.com/reference/android/os/AsyncTask.html

    • Is AsyncTask really conceptually flawed or am I just missing something?: http://stackoverflow.com/q/3357477/1203241

    • Android AsyncTask threads limits?: http://stackoverflow.com/a/9654445/1203241

    • AsyncTask Missteps: http://www.shanekirk.com/2012/04/asynctask‑missteps/

    • Proper use of AsyncTask: https://blogactivity.wordpress.com/2011/09/01/proper‑use‑of‑asynctask/

     
     
    分类: Android
  • 相关阅读:
    RPC和Socket
    监控与管理dubbo服务
    系统架构
    Spring Web工程web.xml零配置即使用Java Config + Annotation
    Spring Boot 整合 Elasticsearch,实现 function score query 权重分查询
    Zxing 的集成 ---- Maven 对应 Gradle 的写法
    Android SpannableString与SpannableStringBuilder
    Android 仿微信朋友圈9宫格图片展示&多选图片
    AndroidRichText 让Textview轻松的支持富文本(图像ImageSpan、点击效果等等类似QQ微信聊天)
    Android 清除canvas 笔迹代码
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/2852014.html
Copyright © 2011-2022 走看看