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代码
- btnEnd.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- new Thread(new Runnable() {
- @Override
- public void run()
- {
- //在新建的线程(工作线程)中改变Button的文字
- btnEnd.setText("Text Changed in Sub Thread");
- }
- }).start();
- }
- });
这是一种错误的做法,运行程序,会报错误:
Java代码
- android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
HandlerActivity02主要代码:
Java代码
- public class HandlerActivity02 extends Activity
- {
- private int title = 0;
- Button btnStart,btnEnd;
- private Handler mHandler = new Handler()
- {
- public void handleMessage(Message msg)
- {
- //更新UI
- switch (msg.what)
- {
- case 1:
- updateTitle();
- break;
- }
- };
- };
- public void onCreate(Bundle savedInstanceState)
- {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- btnStart = (Button)findViewById(R.id.start);
- btnEnd = (Button)findViewById(R.id.end);
- //新启动一个线程,进行耗时操作
- Timer timer = new Timer();
- //每六秒执行一次MyTask的run方法
- timer.scheduleAtFixedRate(new MyTask(this), 1, 6000);
- }
- private class MyTask extends TimerTask
- {
- private Activity context;
- MyTask(Activity context)
- {
- this.context = context;
- }
- @Override
- public void run()
- {
- //耗时操作略....
- //更新UI方法 1
- Message message = new Message();
- message.what = 1;
- mHandler.sendMessage(message);
- //更新UI方法 2
- mHandler.post(updateThread);
- //更新UI方法 3
- context.runOnUiThread(updateThread);
- }
- }
- public void updateTitle()
- {
- setTitle("Welcome to Mr Wei's blog " + title);
- title++;
- }
- Runnable updateThread = new Runnable()
- {
- @Override
- public void run()
- {
- //更新UI
- btnStart.setText(String.valueOf(title));
- btnEnd.setText(String.valueOf(title));
- }
- };
- }
这里有个容易出错的地方,在更新UI方法2和3中,我们传入的参数是一个Runnable对象,一般认为这就会启动一个新的线程,而且常有人在这个Runnable对象的run方法中进行耗时操作。看过这块的源码就会知道,其实,android只是调用了这个Runnable对象的run方法而已,并没有启动新的线程,而且我们不应该在run方法中进行耗时操作,因为这个run方法最终是在UI线程里面执行的。也就是说,run方法里面只应该放更新UI的代码,handleMessage方法也一样。
如果你要看这部分源代码的话,相信这个图对你会有帮助:

HandlerActivity03主要代码:
Java代码
- public class HandlerActivity03 extends Activity
- {
- Button btnStart;
- @Override
- protected void onCreate(Bundle savedInstanceState)
- {
- // TODO Auto-generated method stub
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- btnStart = (Button)findViewById(R.id.start);
- btnStart.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- //开始执行AsyncTask,并传入某些数据
- new LongTimeTask().execute("New Text");
- }
- });
- }
- private class LongTimeTask extends AsyncTask
- {
- @Override
- protected String doInBackground(String... params)
- {
- try
- {
- //线程睡眠5秒,模拟耗时操作,这里面的内容Android系统会自动为你启动一个新的线程执行
- Thread.sleep(5000);
- }
- catch (InterruptedException e)
- {
- e.printStackTrace();
- }
- return params[0];
- }
- @Override
- protected void onPostExecute(String result)
- {
- //更新UI的操作,这里面的内容是在UI线程里面执行的
- btnStart.setText(result);
- }
- }
- }
这个方法确实挺好,因为它为你封装了许多操作,你只需要记住在doInBackground方法中写耗时操作的代码,在onPostExecute方法中写更新UI的方法就行了。
android中工作线程安全的更多相关文章
- android中的线程池学习笔记
阅读书籍: Android开发艺术探索 Android开发进阶从小工到专家 对线程池原理的简单理解: 创建多个线程并且进行管理,提交的任务会被线程池指派给其中的线程进行执行,通过线程池的统一调度和管理 ...
- Android多线程编程<一>Android中启动子线程的方法
我们知道在Android中,要更新UI只能在UI主线程去更新,而不允许在子线程直接去操作UI,但是很多时候,很多耗时的工作都交给子线程去实现,当子线程执行完这些耗时的工作后,我们希望去修改 ...
- Android中后台线程如何与UI线程交互
我想关于这个话题已经有很多前辈讨论过了.今天算是一次学习总结吧. 在android的设计思想中,为了确保用户顺滑的操作体验.一些耗时的任务不能够在UI线程中运行,像访问网络就属于这类任务.因此我们必须 ...
- Android中UI线程与后台线程交互设计的6种方法
在android的设计思想中,为了确保用户顺滑的操作体验.一些耗时的任务不能够在UI线程中运行,像访问网络就属于这类任务.因此我们必须要重新开启 一个后台线程运行这些任务.然而,往往这些任务最终又会直 ...
- Android中UI线程与后台线程交互设计的5种方法
我想关于这个话题已经有很多前辈讨论过了.今天算是一次学习总结吧. 在android的设计思想中,为了确保用户顺滑的操作体验.一 些耗时的任务不能够在UI线程中运行,像访问网络就属于这类任务.因此我们必 ...
- Android中的线程池概述
线程池 Android里面,耗时的网络操作,都会开子线程,在程序里面直接开过多的线程会消耗过多的资源,在众多的开源框架中也总能看到线程池的踪影,所以线程池是必须要会把握的一个知识点; 线程运行机制 开 ...
- android中开启线程
其实Android启动线程和JAVA一样有两种方式,一种是直接Thread类的start方法,也就是一般写一个自己的类来继承Thread类.另外一种方式其实和这个差不多啊! 那就是Runnable接口 ...
- android中对线程池的理解与使用
前段时间有幸接到腾讯上海分公司的 Android开发面试,虽然最后一轮被毙了.但还是得总结一下自己在android开发中的一些盲点,最让我尴尬的是面试官问我几个android中线程池的使用与理解..哎 ...
- Android中的线程池
在Android中,主线程不能执行耗时的操作,否则可能会导致ANR.那么,耗时操作应该在其它线程中执行.线程的创建和销毁都会有性能开销,创建过多的线程也会由于互相抢占系统资源而导致阻塞的现象.这个时候 ...
随机推荐
- 【C语言入门教程】目录/大纲
第一章 C语言编程基础 1.1 基本程序结构 1.2 函数库 和 链接 1.3 C语言“32个”关键字 第二章 数据类型.运算符和表达式 2.1 数据类型(5种基本数据类型),聚合类型与修饰符 2.2 ...
- 垂直居中display:table;
父级元素 display:table: 子元素 display:table-cell:vertical-align:middle:
- T-SQL 语句的理解
1.T-SQL中各子句在逻辑上按照以下顺序进行处理 . . . .. .ORDER BY 查询实例: SELECT EMPID, YEAR(ORDERDATE) AS ORDERYEAR, COUNT ...
- c++ 虚函数和纯虚函数
在你设计一个基类的时候,如果发现一个函数需要在派生类里有不同的表现,那么它就应该是虚的.从设计的角度讲,出现在基类中的虚函数是接口,出现在派生类中的虚函数是接口的具体实现.通过这样的方法,就可以将对象 ...
- java 深入技术六(Map)
Map 1.map概述 map.put(key,value)里面存放的是两个相关的数据,key=value键值对 Map集合中存放的是键值对(put(key,value)),用get(key)获取集合 ...
- Python~删除空格,插入换行符号
f.write(rf.replace(' ','')) f.write(rf.replace('1041','\n1041')) 不能连续起作用? # -*- coding: UTF-8 -*- im ...
- putty可以远程连接linux,但上不了网(nat模式)
话说,这个问题搞了我一个下午 = = 不过终于可以用NAT模式上网了,还是挺有成就感的 首先放张这样的图上去 证明putty 连linux 是木有问题的,但是上不了网哦~~~ 大家请注意, 当前ip是 ...
- PHP获取当前位置
如果想动态的获取当前栏目所处的位置,就要关联到数据库,下面是例子: 栏目表(category): 涉及到二级目录. (1)首先在你的首页导航栏,还有首页所出现的链接后面,为栏目加上catid,就像这样 ...
- 【转】B-树和B+树的应用:数据搜索和数据库索引
B-树 1 .B-树定义 B-树是一种平衡的多路查找树,它在文件系统中很有用. 定义:一棵m 阶的B-树,或者为空树,或为满足下列特性的m 叉树: ⑴树中每个结点至多有m 棵子树: ⑵若根结点不是叶子 ...
- Delphi:与VCL同步(Synchronize()、用消息来同步)
看本文时,可以同时参考:Delphi中线程类 TThread实现多线程编程(事件.临界区.Synchronize.WaitFor……) 先说一下RTL和VCL RTL(Run-Time library ...