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. @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的方法就行了。

时间: 2024-10-13 02:21:25

android中工作线程安全的相关文章

【转载】Android中UI线程与后台线程交互设计的5种方法

原帖地址:http://www.cr173.com/html/19165_1.html 在android的设计思想中,为了确保用户顺滑的操作体验.一些耗时的任务不能够在UI线程中运行,像访问网络就属于这类任务.因此我们必须要重新开启一个后台线程运行这些任务.然而,往往这些任务最终又会直接或者间接的需要访问和控制UI控件.例如访问网络获取数据,然后需要将这些数据处理显示出来.就出现了上面所说的情况.原本这是在正常不过的现象了,但是android规定除了UI线程外,其他线程都不可以对那些UI控件访问

Android中UI线程与后台线程交互设计的5种方法

我想关于这个话题已经有很多前辈讨论过了.今天算是一次学习总结吧. 在android的设计思想中,为了确保用户顺滑的操作体验.一 些耗时的任务不能够在UI线程中运行,像访问网络就属于这类任务.因此我们必须要重新开启一个后台线程运行这些任务.然而,往往这些任务最终又会直接或者 间接的需要访问和控制UI控件.例如访问网络获取数据,然后需要将这些数据处理显示出来.就出现了上面所说的情况.原本这是在正常不过的现象了,但是 android规定除了UI线程外,其他线程都不可以对那些UI控件访问和操控.为了解决

Android中的线程

本文转自:http://www.jianshu.com/p/d59b3cce2b54 如何理解线程 在操作系统中,线程是操作系统调度的最小单元,同时线程又是一种受限的系统资源,即线程不可能无限制的产生,并且线程的创建和销毁都会有相应的开销,当系统中存在大量的线程时,系统会通过时间片轮转的方式调度每个线程,在这么多线程中有一个被称为主线程,主线程是指进程所拥有的线程,在JAVA中默认情况下一个进程只有一个线程,这个线程就是主线程.主线程主要处理界面交互相关的逻辑,因为用户随时会和界面发生交互,因此

Android中UI线程与后台线程交互设计的6种方法

在android的设计思想中,为了确保用户顺滑的操作体验.一些耗时的任务不能够在UI线程中运行,像访问网络就属于这类任务.因此我们必须要重新开启 一个后台线程运行这些任务.然而,往往这些任务最终又会直接或者间接的需要访问和控制UI控件.例如访问网络获取数据,然后需要将这些数据处理显示出来. 就出现了上面所说的情况.原本这是在正常不过的现象了,但是android规定除了UI线程外,其他线程都不可以对那些UI控件访问和操控.为了解决这个 问题,于是就引出了我们今天的话题.Android中后台线程如何

Android中UI线程与worker线程的通信方法

在安卓开发中,线程是十分重要的,几乎你能看到的所有的界面或者功能都是通过线程来完成的.安卓中的线程又分UI线程和工作线程.其中UI线程主要负责和用户交互(说白了就你你在安坐上看到的界面,点击或者拖动这样一些效果):而其它线程出现的主要目的是为UI线程服务. 一般而言,用户新建线程的目的是为了做一些计算或者进行一些IO操作来处理用户的需求.但是由于UI线程和其它线程是两个线程,不能使用一般的在同一个线程间变量通信的方式来进行数据传递.只好令找解决办法,目前我发现了又如下方法可以解决这个问题: 方法

Android中的线程池

总会有线程,总会有队列,等着被执行吧.so,让我们再深深看看线程池: 简介: 线程的使用在java中占有极其重要的地位,在jdk1.4极其之前的jdk版本中,关于线程池的使用是极其简陋的.在jdk1.5之后这一情况有了很大的改观.Jdk1.5之后加入了java.util.concurrent包,这个包中主要介绍java中线程以及线程池的使用.为我们在开发中处理线程的问题提供了非常大的帮助. 作用: 线程池作用就是限制系统中执行线程的数量.     根据系统的环境情况,可以自动或手动设置线程数量,

Android 在工作线程(非主线程)更改UI组件

Looper.prepare();          Toast.makeText(LoginActivity.this,filedId, Toast.LENGTH_LONG).show();        Looper.loop(); 这样为什么可以?然后就是loop 是个死循环,这样子真的好吗?

Android中线程间通信原理分析:Looper,MessageQueue,Handler

自问自答的两个问题 在我们去讨论Handler,Looper,MessageQueue的关系之前,我们需要先问两个问题: 1.这一套东西搞出来是为了解决什么问题呢? 2.如果让我们来解决这个问题该怎么做? 以上者两个问题,是我最近总结出来的,在我们学习了解一个新的技术之前,最好是先能回答这两个问题,这样你才能对你正在学习的东西有更深刻的认识. 第一个问题:google的程序员们搞出这一套东西是为了解决什么问题的?这个问题很显而易见,为了解决线程间通信的问题.我们都知道,Android的UI/Vi

如何在Android中判断某个线程是否是主线程

转帖: http://droidyue.com/blog/2014/07/12/check-main-thread-in-android-chinese-edition/ 如何在Android中判断某个线程是否是主线程?对于这个问题,你可能说根据线程的名字,当然这个可以解决问题,但是这样是最可靠的么?万一某天Google一下子将线程的名字改称其他神马东西呢. 方法揭晓 下面的方法是最可靠的解决方案. public static boolean isInMainThread(){ return L