Android 中的AsyncTask的简单使用心得

举报
ShaderJoy 发表于 2021/12/30 00:11:57 2021/12/30
【摘要】 在android程序中一定不能阻塞UI线程,否则很容易就会弹出no respond 的对话框,导致程序退出。为了避免这种情况,一般需要较长时间执行的任务都放在线程中去执行,如从网上下载图片在界面的某个区域显示。但是使用线程回导致cpu开销过大,并且当线程管理不好时也会弹出no respond框。android提供了AsyncTask类...

在android程序中一定不能阻塞UI线程,否则很容易就会弹出no respond 的对话框,导致程序退出。为了避免这种情况,一般需要较长时间执行的任务都放在线程中去执行,如从网上下载图片在界面的某个区域显示。但是使用线程回导致cpu开销过大,并且当线程管理不好时也会弹出no respond框。android提供了AsyncTask类用来处理这种情况;例如需要下载图片,然后在songImagButton中显示,下载的逻辑在songImageButton的initImage方法中


  
  1. private class DrawImageTask extends AsyncTask<Void, Integer, Void>
  2. {
  3. // 更新图片显示区域,显示图片
  4. @Override
  5. protected void onPostExecute(Void params)
  6. {
  7. // TODO Auto-generated method stub
  8. songImageButton.invalidate();
  9. this.cancel(false);
  10. }
  11. // 下载图片
  12. @Override
  13. protected Void doInBackground(Void... params)
  14. {
  15. // TODO Auto-generated method stub
  16. songImageButton.initImage();
  17. return null;
  18. }
  19. }


一般在doInBackground中执行后台的逻辑,如下载图片或其他需要耗时长的任务,onPostExecute方法用来对界面进行操作。如果后台的逻辑有返回值,则由doInBackground返回然后传入onPostExecute方法,然后更新界面。doInBackground方法和onPostExecute的参数必须对应,这两个参数在AsyncTask声明的泛型参数列表中指定,第一个为doInBackground接受的参数第二个为显示进度的参数第三个为doInBackground返回和onPostExecute传入的参数

当然我个人认为AsyncTask不能完全取代线程,在一些逻辑较为复杂或者需要在后台反复执行的逻辑就可能需要线程来实现了。

怎样停止AsyncTask和Thread

在java的线程中,没有办法停止一个正在运行中的线程。在Android的AsyncTask中也是一样的。如果必须要停止一个线程,可以采用这个线程中设置一个标志位,然后在线程run方法或AsyncTask的doInBackground方法中的关键步骤判断这个标志位以决定是否继续执行。然后在需要终止此线程的地方改变这个标志位以达到停止线程的目的

从外部调用AsyncTask的cancel方法并不能停止一个已经启动的AsyncTask。这个cancel方法的作用与线程的interrupt方法相似,调用了一个线程的interrupt方法之后线程仍然运行,但是如果该线程的run方法里面调用过sleep的或者wait方法后,处于sleep或wait状态,则sleep和wait立即结束并且抛出InterruptedException异常。AsyncTask的cancel方法也一样,如果在这个Task的doInBackground方法中调用了sleep或wait方法,当在UI线程中调用了这个Task实例的cancel方法之后,sleep或wait立即结束并且抛出InterruptedException异常,但是如果捕获该异常的代码后面还有其他代码,则这些代码还会继续执行。

具体示例代码如下:


  
  1. public class AsyncTaskTest extends Activity
  2. {
  3. /** Called when the activity is first created. */
  4. @Override
  5. public void onCreate(Bundle savedInstanceState)
  6. {
  7. super.onCreate(savedInstanceState);
  8. setContentView(R.layout.main);
  9. // set the six buttons listener
  10. Button startButton = (Button) this.findViewById(R.id.StartTask);
  11. final TestAsyncTask task = new TestAsyncTask(0);
  12. startButton.setOnClickListener(new OnClickListener()
  13. {
  14. public void onClick(View v)
  15. {
  16. task.execute("str1", "str2");
  17. }
  18. });
  19. Button endButton = (Button) this.findViewById(R.id.StopTask);
  20. endButton.setOnClickListener(new OnClickListener()
  21. {
  22. public void onClick(View v)
  23. {
  24. task.cancel(false);
  25. }
  26. });
  27. Button startSleepButton = (Button) this
  28. .findViewById(R.id.StartThread_sleep);
  29. final ThreadForTestSleep threadForTestSleep = new ThreadForTestSleep();
  30. startSleepButton.setOnClickListener(new OnClickListener()
  31. {
  32. public void onClick(View v)
  33. {
  34. threadForTestSleep.start();
  35. }
  36. });
  37. Button endSleepButton = (Button) this
  38. .findViewById(R.id.StopThread_sleep);
  39. endSleepButton.setOnClickListener(new OnClickListener()
  40. {
  41. public void onClick(View v)
  42. {
  43. threadForTestSleep.interrupt();
  44. }
  45. });
  46. Button startWaitButton = (Button) this
  47. .findViewById(R.id.StartThread_wait);
  48. final ThreadForTestWait threadForTestWait = new ThreadForTestWait();
  49. startWaitButton.setOnClickListener(new OnClickListener()
  50. {
  51. public void onClick(View v)
  52. {
  53. threadForTestWait.start();
  54. }
  55. });
  56. Button endWaitButton = (Button) this.findViewById(R.id.StopThread_wait);
  57. endWaitButton.setOnClickListener(new OnClickListener()
  58. {
  59. public void onClick(View v)
  60. {
  61. threadForTestWait.interrupt();
  62. }
  63. });
  64. }
  65. private class TestAsyncTask extends AsyncTask<String, Integer, Double>
  66. {
  67. double a;
  68. public TestAsyncTask(double a)
  69. {
  70. this.a = a;
  71. }
  72. @Override
  73. protected Double doInBackground(String... params)
  74. {
  75. for (String param : params)
  76. {
  77. Log.i("TestAsyncTask", "param:" + param);
  78. }
  79. Log.i("TestAsyncTask", "doInBackground is start");
  80. for (int i = 0; i < 10000000; i++)
  81. {
  82. a = i * i + i;
  83. Log.d("-----", "a:" + a);
  84. }
  85. Log.i("TestAsyncTask", "sleep 1 is end");
  86. try
  87. {
  88. Thread.sleep(30000);
  89. } catch (InterruptedException e)
  90. {
  91. // TODO Auto-generated catch block
  92. e.printStackTrace();
  93. }
  94. Log.i("TestAsyncTask", "sleep 2 is end and continue execute");
  95. return a;
  96. }
  97. protected void onPostExecute(Double result)
  98. {
  99. Log.i("last a value is", "" + result);
  100. }
  101. }
  102. /**
  103. * test sleep
  104. *
  105. */
  106. private class ThreadForTestSleep extends Thread
  107. {
  108. public void run()
  109. {
  110. Log.i("ThreadForTestSleep", "sleep start");
  111. try
  112. {
  113. sleep(30000);
  114. } catch (InterruptedException e)
  115. {
  116. // TODO Auto-generated catch block
  117. e.printStackTrace();
  118. }
  119. double a;
  120. for (int i = 0; i < 10000000; i++)
  121. {
  122. a = i * i + i;
  123. Log.d("-----", "a:" + a);
  124. }
  125. Log.i("ThreadForTestSleep", "sleep end");
  126. }
  127. }
  128. /**
  129. * test wait
  130. *
  131. */
  132. private class ThreadForTestWait extends Thread
  133. {
  134. public void run()
  135. {
  136. Log.i("ThreadForTestWait", "wait start");
  137. try
  138. {
  139. synchronized (this)
  140. {
  141. wait();
  142. }
  143. } catch (InterruptedException e)
  144. {
  145. // TODO Auto-generated catch block
  146. e.printStackTrace();
  147. }
  148. Log.i("ThreadForTestWait", "wait end");
  149. }
  150. }
  151. }

网上有人测试过,同种类型的 AsyncTask 实例,最大数量为 20 个。

如果超过,则会引发 RejectExcuteException,并 crash

因此,要考虑到用户的操作是否会引发频繁的 AsyncTask 实例化,若存在,则从 UI 上进行改进,比如:

分页机制;

线程池;

生产者-消费者模型。

2.取消AsyncTask任务

文档已经说明,cancel()方法不一定能成功,所以 onCancel() 回调方法不一定被调用。

但若一个 AsyncTask 结束,则一定会调用 onPostExcute() 方法。

对于一个 doInBackground()方法中含有 while/for 循环时,最好配置 isCancel标置来 break 循环。

这里有一个其他的例子,也挺好的,简单易懂。






文章来源: panda1234lee.blog.csdn.net,作者:panda1234lee,版权归原作者所有,如需转载,请联系作者。

原文链接:panda1234lee.blog.csdn.net/article/details/8787975

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。