`
trygood
  • 浏览: 76107 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论
阅读更多
今天在论坛上看到一些关于线程的帖子,我觉得与我理解的有些差异,拿上来与大家讨论下  
      关于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);
复制代码
分享到:
评论

相关推荐

    MFC多线程的创建,包括工作线程和用户界面线程

    《MFC多线程的创建,包括工作线程和用户界面线程》全面讲解MFC多线程的创建,界面多线程与工作者多线程,多线程的起源、继承与派生,两多线程之间的区别与相同点,定时器与多线程的关系与异同(定时器是定时优先抢占...

    C# 跨线程访问UI线程控件

    在C#中,由于使用线程和调用UI的线程属于两个不同的线程,如果在线程中直接设置UI元素的属性,此时就会出现跨线程错误。    下面介绍两种解决方案  第一种:使用控件自带的Invoke或者BeginInvoke方法。 Task....

    基于SpringBoot和POI实现单线程和多线程导出Excel.zip

    基于SpringBoot和POI实现单线程和多线程导出Excel.zip基于SpringBoot和POI实现单线程和多线程导出Excel.zip基于SpringBoot和POI实现单线程和多线程导出Excel.zip基于SpringBoot和POI实现单线程和多线程导出Excel.zip...

    Android 中三种启用线程的方法总结

    在多线程编程这块,我们经常要使用Handler(处理),Thread(线程)和Runnable这三个类,那么他们之间的关系你是否弄清楚了呢? 首先说明Android的CPU分配的最小单元是线程,Handler一般是在某个线程里创建的,因而...

    Qt 多线程及简单实例 demo

    Qt 多线程及简单实例 demo。 多线程的几大特点: 1.多线程的执行顺序无法保证,与操作系统的调度策略和线程优先级等因素有关。 2.多线程的切换可能发生在任何时刻、任何地点。 3.多线程对代码的敏感度高,因此对...

    C#多线程编程 四个显示线程计算结果的函数

    从属线程需要随时将中间结果先是在主界面上,鉴于控件总是由主执行线程所有,从属线程中对控件的任何调用都需要“封送处理”调用。 封送处理是跨线程边界移动调用的行为,需耗费大量的资源。为使需要发生的封送处理...

    JAVA单线程多线程

    单线程 单线程 单线程 单线程 单线程 单线程

    多线程代码 经典线程同步互斥问题 生产者消费者问题

    a: 创建一个线程 b: 创建多个线程 c: 多线程访问同一资源 d: 经典线程同步互斥问题 e: 使用关键段解决子线程互斥问题 f: 利用事件实现线程同步问题 g: 利用互斥量来解决线程同步互斥问题 h: problem1 生产...

    Qt多线程通信 附源码demo

    Qt线程间共享数据主要有两种方式: 1)使用共享内存。即使用一个两个线程都能够共享的变量(如全局变量),这样两个线程都能够访问和修改该变量,从而达到共享数据的目的。 2)使用singal/slot机制,把数据从一个...

    C#多线程编程实战 源代码

    在计算机处理器发展为包含越来越多的核心的时期,多线程是创建可伸缩性、高效的、高响应性应用程序的关键因素。如果你没有正确地使用多线程,它会导致难以捉摸的问题,需要你花费大量时间去解决。因此,现代应用程序...

    MFC多线程 工作者线程 用户界面线程

    MFC多线程 工作者线程 用户界面线程

    java多线程每个线程挨着打印ABC的4种实现方式

    java多线程每个线程挨着打印ABC的4种实现方式,有4个线程t1、t2、t3、t4,t1打印A后t2打印A再t3打印A再t4打印A,然后从新回到t1打印B再t2打印B...t4打印B... 4个线程轮流打印abc... 一个线程可以理解为一个人,打印...

    创建线程,利用互斥实现线程共享变量通信

    一、题目: 创建线程,利用互斥实现线程共享变量通信 二、目的 掌握线程创建和终止,加深对线程和进程概念的理解,会用同步与互斥方法实现线程之间的通信。 三、内容和要求 软件界面上点“创建线程” 按钮,创建三个...

    C++实现的可以安全的暂停、继续、停止线程的线程类和Sample

    在使用线程时,最麻烦的就是线程的同步控制,如暂停、继续、停止(包括暂停状态下)等。虽然微软提供了 SuspendThread、TerminateThread 等函数“似乎”可以完成这个功能,但如果你在代码里使用这些函数,则往往会...

    c++多线程的创建挂起执行与销毁

    //线程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_多线程c_多线程c_多线程...

    编写程序,使用两个线程,一个队列,其中一个线程从键盘读取数据,放入到队列中,直到读取的数据是字符串quit则结束

    1. 编写程序,使用两个线程,一个队列, 其中一个线程从键盘读取数据,放入到队列中,直到读取的数据是字符串quit则结束,线程的任务就是循环读取数据直到特定的字符串quit。另外一个线程,不断的从队列中读取数据...

    Qt中利用OpenCV2.4.4多线程打开多摄像机

    Qt中利用OpenCV2.4.4多线程打开多摄像机 每个线程处理一个摄像机,从中拿出帧显示到主线程的Label控件上 模拟了一个16个摄像机的场景,有不开多线程和打开多线程的对比。 可以明显感觉到打开多线程后主界面不卡了。 ...

    C++_p2p实现多线程文件传输.doc

    C++_p2p实现多线程文件传输.docC++_p2p实现多线程文件传输.docC++_p2p实现多线程文件传输.docC++_p2p实现多线程文件传输.docC++_p2p实现多线程文件传输.docC++_p2p实现多线程文件传输.docC++_p2p实现多线程文件传输....

    秒杀多线程第十六篇 多线程十大经典案例之一 双线程读写队列数据

    《秒杀多线程第十六篇 多线程十大经典案例之一 双线程读写队列数据》 http://blog.csdn.net/morewindows/article/details/8646902 配套程序 在《秒杀多线程系列》的前十五篇中介绍多线程的相关概念,多线程同步互斥...

Global site tag (gtag.js) - Google Analytics