A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 张然龙 金牌黑马   /  2014-7-30 12:34  /  1232 人查看  /  0 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

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() {                        
  3.           Bitmap b = loadImageFromNetwork();   
  4.           mImageView.setImageBitmap( b );   
  5.      }  
  6. }).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. ublic 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. }
  33. 在Activity中直接调用
  34. if(!img.isDrawingCacheEnabled() || !holder.image.getTag().equals(imgpath)){
  35.                 img.setImageResource(R.drawable.icon_app);
  36.                 img.setTag(imgpath);
  37.                 try{
  38.                     new CanvasImageTask().execute(img);
  39.                     img.setDrawingCacheEnabled(true);
  40.                 }catch (Exception e) {
  41.                     Log.e("error", "RejectedExecutionException in content_img: " +  imgpath);
复制代码

这样图片加载使用异步线程便不会进行堵塞发生错误,我们还可以使用 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);
复制代码



0 个回复

您需要登录后才可以回帖 登录 | 加入黑马