zoukankan      html  css  js  c++  java
  • android中工作线程安全

    当应用程序启动,创建了一个叫“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的两个重要方法:sendMessage和post。
      • HandlerActivity03
        • 官方推荐最佳方法。

      HandlerActivity01主要代码:

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

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

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

       这里有个容易出错的地方,在更新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.           
      11.         btnStart = (Button)findViewById(R.id.start);  
      12.         btnStart.setOnClickListener(new View.OnClickListener() {  
      13.               
      14.             @Override  
      15.             public void onClick(View v) {  
      16.                 //开始执行AsyncTask,并传入某些数据  
      17.                 new LongTimeTask().execute("New Text");  
      18.             }  
      19.         });  
      20.     }  
      21.       
      22.     private class LongTimeTask extends AsyncTask  
      23.     {  
      24.   
      25.         @Override  
      26.         protected String doInBackground(String... params)  
      27.         {  
      28.             try  
      29.             {  
      30.                 //线程睡眠5秒,模拟耗时操作,这里面的内容Android系统会自动为你启动一个新的线程执行  
      31.                 Thread.sleep(5000);  
      32.             }  
      33.             catch (InterruptedException e)  
      34.             {  
      35.                 e.printStackTrace();  
      36.             }  
      37.             return params[0];  
      38.         }  
      39.   
      40.         @Override  
      41.         protected void onPostExecute(String result)  
      42.         {  
      43.             //更新UI的操作,这里面的内容是在UI线程里面执行的  
      44.             btnStart.setText(result);  
      45.         }  
      46.           
      47.     }  
      48.   
      49. }  

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

  • 相关阅读:
    Oracle数据库相关问题
    常用Oracle数据库查询SQL
    VS2019添加引用错误:COM组件调用返回错误HRESULT E_FAIL
    C#.NET重点知识点汇总(三)
    C#.NET重点知识点汇总(二)
    C#.NET重点知识点汇总(一)
    ajax的19道经典面试题
    C#设计模式——抽象工厂模式
    C#设计模式——工厂方法模式
    C#设计模式——简单工厂模式
  • 原文地址:https://www.cnblogs.com/huangyibo/p/3958672.html
Copyright © 2011-2022 走看看