zoukankan      html  css  js  c++  java
  • UI线程异常处理方法

    当应用程序启动,创建了一个叫“main”的线程,用于管理UI相关,又叫UI线程。其他线程叫工作线程(Work Thread)。

    Single Thread Model

     

    • 一个组件的创建并不会新建一个线程,他们的创建都在UI线程中进行,包括他们的回调方法,如onKeyDown()
    • 当在UI线程中进行某些耗时的操作时,将会阻塞UI线程,一般阻塞超过5秒就会显示一个ANR对话框(弹出程序无反应的对话框)。
    • UI线程是非线程安全的,所以,不能在工作线程中操作UI元素。

       

      两个原则

      • Do not block the UI thread (不要阻塞UI线程)
      • Do not access the Android UI toolkit from outside the UI thread (不要在工作线程中操作UI元素)

       

      在工作线程更新UI方法

      • Activity.runOnUiThread(Runnable)
      • Handler
        • sendMessage(Message)
        • post(Runnable)
      • AsyncTask
        • execute()
        • doInBackground()
        • onPostExecute()

       

      例子程序

      • HandlerActivity01
        • 在工作线程中进行UI操作。
      • HandlerActivity02
        • Handler的两个重要方法:sendMessagepost
      • HandlerActivity03
        • 官方推荐最佳方法。

       

      HandlerActivity01主要代码:

      Java代码
      1. btnEnd.setOnClickListener(new View.OnClickListener() {
      2. @Override
      3. public void onClick(View v) {
      4. new Thread(new Runnable() {
      5. @Override
      6. public void run()
      7. {
      8. //在新建的线程(工作线程)中改变Button的文字
      9. btnEnd.setText("Text Changed in Sub Thread");
      10. }
      11. }).start();
      12. }
      13. });

       

      这是一种错误的做法,运行程序,会报错误:

      Java代码
      1. android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

        

      HandlerActivity02主要代码:

      Java代码
      1. public class HandlerActivity02 extends Activity
      2. {
      3. private int title = 0;
      4. Button btnStart,btnEnd;
      5. private Handler mHandler = new Handler()
      6. {
      7. public void handleMessage(Message msg)
      8. {
      9. //更新UI
      10. switch (msg.what)
      11. {
      12. case 1:
      13. updateTitle();
      14. break;
      15. }
      16. };
      17. };
      18. public void onCreate(Bundle savedInstanceState)
      19. {
      20. super.onCreate(savedInstanceState);
      21. setContentView(R.layout.main);
      22. btnStart = (Button)findViewById(R.id.start);
      23. btnEnd = (Button)findViewById(R.id.end);
      24. //新启动一个线程,进行耗时操作
      25. Timer timer = new Timer();
      26. //每六秒执行一次MyTask的run方法
      27. timer.scheduleAtFixedRate(new MyTask(this), 1, 6000);
      28. }
      29. private class MyTask extends TimerTask
      30. {
      31. private Activity context;
      32. MyTask(Activity context)
      33. {
      34. this.context = context;
      35. }
      36. @Override
      37. public void run()
      38. {
      39. //耗时操作略....
      40. //更新UI方法 1
      41. Message message = new Message();
      42. message.what = 1;
      43. mHandler.sendMessage(message);
      44. //更新UI方法 2
      45. mHandler.post(updateThread);
      46. //更新UI方法 3
      47. context.runOnUiThread(updateThread);
      48. }
      49. }
      50. public void updateTitle()
      51. {
      52. setTitle("Welcome to Mr Wei's blog " + title);
      53. title++;
      54. }
      55. Runnable updateThread = new Runnable()
      56. {
      57. @Override
      58. public void run()
      59. {
      60. //更新UI
      61. btnStart.setText(String.valueOf(title));
      62. btnEnd.setText(String.valueOf(title));
      63. }
      64. };
      65. }

      这里有个容易出错的地方,在更新UI方法2和3中,我们传入的参数是一个Runnable对象,一般认为这就会启动一个新的线程,而且常有人在这个Runnable对象的run方法中进行耗时操作。看过这块的源码就会知道,其实,android只是调用了这个Runnable对象的run方法而已,并没有启动新的线程,而且我们不应该在run方法中进行耗时操作,因为这个run方法最终是在UI线程里面执行的。也就是说,run方法里面只应该放更新UI的代码,handleMessage方法也一样。

       

      如果你要看这部分源代码的话,相信这个图对你会有帮助:

       

       

       

      HandlerActivity03主要代码:

      Java代码
      1. public class HandlerActivity03 extends Activity
      2. {
      3. Button btnStart;
      4. @Override
      5. protected void onCreate(Bundle savedInstanceState)
      6. {
      7. // TODO Auto-generated method stub
      8. super.onCreate(savedInstanceState);
      9. setContentView(R.layout.main);
      10. btnStart = (Button)findViewById(R.id.start);
      11. btnStart.setOnClickListener(new View.OnClickListener() {
      12. @Override
      13. public void onClick(View v) {
      14. //开始执行AsyncTask,并传入某些数据
      15. new LongTimeTask().execute("New Text");
      16. }
      17. });
      18. }
      19. private class LongTimeTask extends AsyncTask
      20. {
      21. @Override
      22. protected String doInBackground(String... params)
      23. {
      24. try
      25. {
      26. //线程睡眠5秒,模拟耗时操作,这里面的内容Android系统会自动为你启动一个新的线程执行
      27. Thread.sleep(5000);
      28. }
      29. catch (InterruptedException e)
      30. {
      31. e.printStackTrace();
      32. }
      33. return params[0];
      34. }
      35. @Override
      36. protected void onPostExecute(String result)
      37. {
      38. //更新UI的操作,这里面的内容是在UI线程里面执行的
      39. btnStart.setText(result);
      40. }
      41. }
      42. }

       

      这个方法确实挺好,因为它为你封装了许多操作,你只需要记住在doInBackground方法中写耗时操作的代码,在onPostExecute方法中写更新UI的方法就行了

  • 相关阅读:
    WC项目
    团队项目(MVP新能源无线充电管理网站)(总结)
    学期目标
    个人目标、思维导图、不同点
    结对项目——黄金分割点游戏(陈香宇&蔡春燕)
    团队项目(MVP新能源无线充电管理网站)(个人任务2)
    四则运算
    读后疑问
    crontab 定时任务
    mysql主从配置
  • 原文地址:https://www.cnblogs.com/SZ2015/p/4641546.html
Copyright © 2011-2022 走看看