今天在论坛上看到一些关于线程的帖子,我觉得与我理解的有些差异,拿上来与大家讨论下
关于android的线程模型:当一个android的应用运行后, 就会有一个UI的main线程启动,这是一个非常重要的线程,它负责把事件分派到相应的控件,其中就包括屏幕绘图事件,它同样是用户与android控件交互的线程。比如,当你在屏幕上的EditText上输入文字,UI线程会把这个事件分发给刚输入文字的EditText,紧接会向事件队列发送一个更新(invalidate)请求。UI线程会把这个请求移出事件队列并通知EditText在屏幕上重新绘制自身。
这种单线线程模型就会使得android的应用程序性能低下, 如果在这个单线程里执行一些耗时的操作, 比如访问数据库, 或是从网络端下载图片, 就会会阻塞整个用户界面。 比如如下操作:
1. Bitmap b = loadImageFromNetwork();
复制代码
这个操作非常耗时, 在这种情况下你会发现, 界面僵死在那里并且android在系统5秒中后没有反应,会显示一个关闭或等待的错误。
也许我们可以使用一个新的Thread来解决它
1. new Thread(new Runnable() {
2. public void run() { Bitmap b = loadImageFromNetwork();
3. mImageView.setImageBitmap( b );
4. }
5. }).start();
复制代码
但这样会发生一些很难察觉的错误, 因为我们知道UI线程不是线程安全的。当然有很多种方法来处理这个问题:
android提供了几种在其他线程中访问UI线程的方法。
• Activity.runOnUiThread( Runnable )
• View.post( Runnable )
• View.postDelayed( Runnable, long )
• Hanlder
1. new Thread( new Runnable() {
2. public void run() {
3. final Bitmap b = loadImageFromNetwork();
4. mImageView.post( new Runnable() {
5. mImageView.setImageBitmap( b );
6. });
7. }
8. }).start();
复制代码
这种方法比较繁琐,同时当你需要实现一些很复杂的操作并需要频繁地更新UI时这会变得更糟糕。为了解决这个问题,android提供了一个工具类:AsyncTask,它使创建需要与用户界面交互的长时间运行的任务变得更简单。
我就拿加载网络图片举个例子:
1. public class CanvasImageTask extends AsyncTask<ImageView, Void, Bitmap>{
2. private ImageView gView ;
3.
4. protected Bitmap doInBackground(ImageView... views) {
5. Bitmap bmp = null ;
6. ImageView view = views[0];
7. // 根据iconUrl获取图片并渲染,iconUrl的url放在了view的tag中。
8. if (view.getTag() != null) {
9. try {
10. URL url = new URL(view.getTag().toString());
11. HttpURLConnection conn = (HttpURLConnection)url.openConnection();
12. conn.setDoInput(true);
13. conn.connect();
14. InputStream stream = conn.getInputStream();
15. bmp = BitmapFactory.decodeStream(stream);
16. stream.close();
17. } catch (Exception e) {
18. Log.v("img", e.getMessage());
19. return null;
20. }
21. }
22. this.gView = view;
23. return bmp;
24. }
25. protected void onPostExecute(Bitmap bm) {
26. if (bm != null) {
27. this.gView.setImageBitmap(bm);
28. this.gView = null ;
29. }
30. }
31.
32. }
复制代码
在Activity中直接调用
1. if(!img.isDrawingCacheEnabled() || !holder.image.getTag().equals(imgpath)){
2. img.setImageResource(R.drawable.icon_app);
3. img.setTag(imgpath);
4. try{
5. new CanvasImageTask().execute(img);
6. img.setDrawingCacheEnabled(true);
7. }catch (Exception e) {
8. Log.e("error", "RejectedExecutionException in content_img: " + imgpath);
9. }
10. }
复制代码
这样图片加载使用异步线程便不会进行堵塞发生错误,我们还可以使用callback在图片加载完后进行回调
1. public class CanvasImageTaskCall extends AsyncTask<ImageView, Void, Bitmap> implements Callback{
2. private ImageView gView ;
3.
4. protected Bitmap doInBackground(ImageView... views) {
5. Bitmap bmp = null ;
6. ImageView view = views[0];
7. // 根据iconUrl获取图片并渲染,iconUrl的url放在了view的tag中。
8. if (view.getTag() != null) {
9. try {
10. URL url = new URL(view.getTag().toString());
11. HttpURLConnection conn = (HttpURLConnection)url.openConnection();
12. conn.setDoInput(true);
13. conn.connect();
14. InputStream stream = conn.getInputStream();
15. bmp = BitmapFactory.decodeStream(stream);
16. stream.close();
17. } catch (Exception e) {
18. e.printStackTrace();
19. Log.v("img", e.getMessage());
20. Message msg = new Message();
21. msg.what = 0;
22. handleMessage(msg);
23. return null;
24. }
25. }
26. this.gView = view;
27. return bmp;
28. }
29. protected void onPostExecute(Bitmap bm) {
30. if (bm != null) {
31. this.gView.setImageBitmap(bm);
32. this.gView.setTag(bm);
33. this.gView = null ;
34. Message msg = new Message();
35. msg.what = 1;
36. handleMessage(msg);
37. }
38. }
39. public boolean handleMessage(Message msg) {
40. // TODO Auto-generated method stub
41. return false;
42. }
43.
44. }
复制代码
在Activity中直接调用
1. new CanvasImageTaskCall(){
2. @Override
3. public boolean handleMessage(Message msg) {
4. switch (msg.what) {
5. case 0:
6. Log.i("test", "图片加载失败");
7. break;
8. case 1:
9. Log.i("test", "图片加载成功");
10. break;
11. default:
12. break;
13. }
14. saveButton.setTextColor(Color.WHITE);
15. saveButton.setClickable(true);
16. bitmap = (Bitmap) imageView.getTag();
17. return super.handleMessage(msg);
18. }
19. }.execute(img);
复制代码
关于android的线程模型:当一个android的应用运行后, 就会有一个UI的main线程启动,这是一个非常重要的线程,它负责把事件分派到相应的控件,其中就包括屏幕绘图事件,它同样是用户与android控件交互的线程。比如,当你在屏幕上的EditText上输入文字,UI线程会把这个事件分发给刚输入文字的EditText,紧接会向事件队列发送一个更新(invalidate)请求。UI线程会把这个请求移出事件队列并通知EditText在屏幕上重新绘制自身。
这种单线线程模型就会使得android的应用程序性能低下, 如果在这个单线程里执行一些耗时的操作, 比如访问数据库, 或是从网络端下载图片, 就会会阻塞整个用户界面。 比如如下操作:
1. Bitmap b = loadImageFromNetwork();
复制代码
这个操作非常耗时, 在这种情况下你会发现, 界面僵死在那里并且android在系统5秒中后没有反应,会显示一个关闭或等待的错误。
也许我们可以使用一个新的Thread来解决它
1. new Thread(new Runnable() {
2. public void run() { Bitmap b = loadImageFromNetwork();
3. mImageView.setImageBitmap( b );
4. }
5. }).start();
复制代码
但这样会发生一些很难察觉的错误, 因为我们知道UI线程不是线程安全的。当然有很多种方法来处理这个问题:
android提供了几种在其他线程中访问UI线程的方法。
• Activity.runOnUiThread( Runnable )
• View.post( Runnable )
• View.postDelayed( Runnable, long )
• Hanlder
1. new Thread( new Runnable() {
2. public void run() {
3. final Bitmap b = loadImageFromNetwork();
4. mImageView.post( new Runnable() {
5. mImageView.setImageBitmap( b );
6. });
7. }
8. }).start();
复制代码
这种方法比较繁琐,同时当你需要实现一些很复杂的操作并需要频繁地更新UI时这会变得更糟糕。为了解决这个问题,android提供了一个工具类:AsyncTask,它使创建需要与用户界面交互的长时间运行的任务变得更简单。
我就拿加载网络图片举个例子:
1. public class CanvasImageTask extends AsyncTask<ImageView, Void, Bitmap>{
2. private ImageView gView ;
3.
4. protected Bitmap doInBackground(ImageView... views) {
5. Bitmap bmp = null ;
6. ImageView view = views[0];
7. // 根据iconUrl获取图片并渲染,iconUrl的url放在了view的tag中。
8. if (view.getTag() != null) {
9. try {
10. URL url = new URL(view.getTag().toString());
11. HttpURLConnection conn = (HttpURLConnection)url.openConnection();
12. conn.setDoInput(true);
13. conn.connect();
14. InputStream stream = conn.getInputStream();
15. bmp = BitmapFactory.decodeStream(stream);
16. stream.close();
17. } catch (Exception e) {
18. Log.v("img", e.getMessage());
19. return null;
20. }
21. }
22. this.gView = view;
23. return bmp;
24. }
25. protected void onPostExecute(Bitmap bm) {
26. if (bm != null) {
27. this.gView.setImageBitmap(bm);
28. this.gView = null ;
29. }
30. }
31.
32. }
复制代码
在Activity中直接调用
1. if(!img.isDrawingCacheEnabled() || !holder.image.getTag().equals(imgpath)){
2. img.setImageResource(R.drawable.icon_app);
3. img.setTag(imgpath);
4. try{
5. new CanvasImageTask().execute(img);
6. img.setDrawingCacheEnabled(true);
7. }catch (Exception e) {
8. Log.e("error", "RejectedExecutionException in content_img: " + imgpath);
9. }
10. }
复制代码
这样图片加载使用异步线程便不会进行堵塞发生错误,我们还可以使用callback在图片加载完后进行回调
1. public class CanvasImageTaskCall extends AsyncTask<ImageView, Void, Bitmap> implements Callback{
2. private ImageView gView ;
3.
4. protected Bitmap doInBackground(ImageView... views) {
5. Bitmap bmp = null ;
6. ImageView view = views[0];
7. // 根据iconUrl获取图片并渲染,iconUrl的url放在了view的tag中。
8. if (view.getTag() != null) {
9. try {
10. URL url = new URL(view.getTag().toString());
11. HttpURLConnection conn = (HttpURLConnection)url.openConnection();
12. conn.setDoInput(true);
13. conn.connect();
14. InputStream stream = conn.getInputStream();
15. bmp = BitmapFactory.decodeStream(stream);
16. stream.close();
17. } catch (Exception e) {
18. e.printStackTrace();
19. Log.v("img", e.getMessage());
20. Message msg = new Message();
21. msg.what = 0;
22. handleMessage(msg);
23. return null;
24. }
25. }
26. this.gView = view;
27. return bmp;
28. }
29. protected void onPostExecute(Bitmap bm) {
30. if (bm != null) {
31. this.gView.setImageBitmap(bm);
32. this.gView.setTag(bm);
33. this.gView = null ;
34. Message msg = new Message();
35. msg.what = 1;
36. handleMessage(msg);
37. }
38. }
39. public boolean handleMessage(Message msg) {
40. // TODO Auto-generated method stub
41. return false;
42. }
43.
44. }
复制代码
在Activity中直接调用
1. new CanvasImageTaskCall(){
2. @Override
3. public boolean handleMessage(Message msg) {
4. switch (msg.what) {
5. case 0:
6. Log.i("test", "图片加载失败");
7. break;
8. case 1:
9. Log.i("test", "图片加载成功");
10. break;
11. default:
12. break;
13. }
14. saveButton.setTextColor(Color.WHITE);
15. saveButton.setClickable(true);
16. bitmap = (Bitmap) imageView.getTag();
17. return super.handleMessage(msg);
18. }
19. }.execute(img);
复制代码
发表评论
-
startActivityForResult 简介
2011-03-29 15:55 1239依次打开Activity A1--A2--A3--A4 这时 ... -
startActivityForResult
2011-03-29 15:49 1101startActivityForResult 方法-- ... -
史上最全的Android的Tab与TabHost讲解
2011-03-28 11:22 1532Tab与TabHost 这就是Tab,而盛放Tab的 ... -
Android对话框
2011-03-25 11:21 1081Android 对话框(Dialog)大全 ... -
PreferenceActivity详解
2011-03-25 11:15 1400为了引入这个概率 首先从需求说起 即:现有某Activity专 ... -
TCP/UDP/HTTP
2011-03-25 11:09 1083先来一个讲TCP、UDP和HTTP ... -
9png
2011-03-25 11:08 1868今天学习了用9png图来优化横屏竖屏的UI,使用sdk自带的工 ... -
Notification
2011-03-25 11:07 877Android系统的状态栏(Status Bar)中有一个创新 ... -
一些技巧
2011-03-25 11:03 7381:查看是否有存储卡插入 String status=Envi ... -
布局像素单位
2011-03-25 11:03 780Android的layout文件中有时候可能会指定具体的单位, ... -
使用ActivityGroup来切换Activity和Layout
2011-03-25 11:02 1075在一个主界面中做Activity切换一般都会用TabActiv ... -
activitygroup
2011-03-25 11:01 1639说说tabhost和activitygroup 最近 ... -
类级框架
2011-03-25 11:00 709类集框架:Collection,Map,Iterator,En ... -
Intent打电话
2011-03-25 11:00 1170intent英文意思是意图,pending表示即将发生或来临的 ... -
Intent Uri
2011-03-25 10:59 1021进入联系人页面 1.Intent intent = new I ... -
Service
2011-03-25 10:59 905一、Service的概念 Service是Android程序中 ... -
Broadcast Receiver
2011-03-25 10:56 1881一、Broadcast Receiver简介 Android中 ... -
ContentProvider MIME类型
2011-03-25 10:55 1197Android程序的主要4部分 ... -
ContentProvider-1查询
2011-03-25 10:55 1185今天看了android的官方文档中ContentProvide ... -
ContentProvider-2modify data:insert,update,delete
2011-03-25 10:54 1154今天补充关于modify data ...
相关推荐
《MFC多线程的创建,包括工作线程和用户界面线程》全面讲解MFC多线程的创建,界面多线程与工作者多线程,多线程的起源、继承与派生,两多线程之间的区别与相同点,定时器与多线程的关系与异同(定时器是定时优先抢占...
在C#中,由于使用线程和调用UI的线程属于两个不同的线程,如果在线程中直接设置UI元素的属性,此时就会出现跨线程错误。 下面介绍两种解决方案 第一种:使用控件自带的Invoke或者BeginInvoke方法。 Task....
基于SpringBoot和POI实现单线程和多线程导出Excel.zip基于SpringBoot和POI实现单线程和多线程导出Excel.zip基于SpringBoot和POI实现单线程和多线程导出Excel.zip基于SpringBoot和POI实现单线程和多线程导出Excel.zip...
在多线程编程这块,我们经常要使用Handler(处理),Thread(线程)和Runnable这三个类,那么他们之间的关系你是否弄清楚了呢? 首先说明Android的CPU分配的最小单元是线程,Handler一般是在某个线程里创建的,因而...
Qt 多线程及简单实例 demo。 多线程的几大特点: 1.多线程的执行顺序无法保证,与操作系统的调度策略和线程优先级等因素有关。 2.多线程的切换可能发生在任何时刻、任何地点。 3.多线程对代码的敏感度高,因此对...
从属线程需要随时将中间结果先是在主界面上,鉴于控件总是由主执行线程所有,从属线程中对控件的任何调用都需要“封送处理”调用。 封送处理是跨线程边界移动调用的行为,需耗费大量的资源。为使需要发生的封送处理...
单线程 单线程 单线程 单线程 单线程 单线程
a: 创建一个线程 b: 创建多个线程 c: 多线程访问同一资源 d: 经典线程同步互斥问题 e: 使用关键段解决子线程互斥问题 f: 利用事件实现线程同步问题 g: 利用互斥量来解决线程同步互斥问题 h: problem1 生产...
Qt线程间共享数据主要有两种方式: 1)使用共享内存。即使用一个两个线程都能够共享的变量(如全局变量),这样两个线程都能够访问和修改该变量,从而达到共享数据的目的。 2)使用singal/slot机制,把数据从一个...
在计算机处理器发展为包含越来越多的核心的时期,多线程是创建可伸缩性、高效的、高响应性应用程序的关键因素。如果你没有正确地使用多线程,它会导致难以捉摸的问题,需要你花费大量时间去解决。因此,现代应用程序...
MFC多线程 工作者线程 用户界面线程
java多线程每个线程挨着打印ABC的4种实现方式,有4个线程t1、t2、t3、t4,t1打印A后t2打印A再t3打印A再t4打印A,然后从新回到t1打印B再t2打印B...t4打印B... 4个线程轮流打印abc... 一个线程可以理解为一个人,打印...
一、题目: 创建线程,利用互斥实现线程共享变量通信 二、目的 掌握线程创建和终止,加深对线程和进程概念的理解,会用同步与互斥方法实现线程之间的通信。 三、内容和要求 软件界面上点“创建线程” 按钮,创建三个...
在使用线程时,最麻烦的就是线程的同步控制,如暂停、继续、停止(包括暂停状态下)等。虽然微软提供了 SuspendThread、TerminateThread 等函数“似乎”可以完成这个功能,但如果你在代码里使用这些函数,则往往会...
//线程1线程句柄 HANDLE hThread2; //线程2线程句柄 HANDLE hThread3; //线程3线程句柄 在增加三个结构体类型的变量,用做线程函数的参数传递; HANDLE hThread1; //线程1线程句柄 HANDLE hThread2; //线程2...
c_多线程c_多线程c_多线程c_多线程c_多线程c_多线程c_多线程c_多线程c_多线程c_多线程c_多线程c_多线程c_多线程c_多线程c_多线程c_多线程c_多线程c_多线程c_多线程c_多线程c_多线程c_多线程c_多线程c_多线程c_多线程...
1. 编写程序,使用两个线程,一个队列, 其中一个线程从键盘读取数据,放入到队列中,直到读取的数据是字符串quit则结束,线程的任务就是循环读取数据直到特定的字符串quit。另外一个线程,不断的从队列中读取数据...
Qt中利用OpenCV2.4.4多线程打开多摄像机 每个线程处理一个摄像机,从中拿出帧显示到主线程的Label控件上 模拟了一个16个摄像机的场景,有不开多线程和打开多线程的对比。 可以明显感觉到打开多线程后主界面不卡了。 ...
C++_p2p实现多线程文件传输.docC++_p2p实现多线程文件传输.docC++_p2p实现多线程文件传输.docC++_p2p实现多线程文件传输.docC++_p2p实现多线程文件传输.docC++_p2p实现多线程文件传输.docC++_p2p实现多线程文件传输....
《秒杀多线程第十六篇 多线程十大经典案例之一 双线程读写队列数据》 http://blog.csdn.net/morewindows/article/details/8646902 配套程序 在《秒杀多线程系列》的前十五篇中介绍多线程的相关概念,多线程同步互斥...