Android 线程模型和 AsyncTask

android 的线程模型:当一个 android 的应用运行后,就会有一个 UI 的 main 线程启动 , 这是一个非常重要的线程,它负责把事件分派到相应的控件,其中就包括屏幕绘图事件,它同样是用户与 android 控件 交互的线程。比如,当你在屏幕上的 EditText 上输入文字, UI 线程会把这个事件分发给刚输入文字的 EditText ,紧接会向事件队列发送一个更新 ( invalidate )请求。 UI 线程会把这个请求移出事件队列并通知 EditText 在屏幕上重新绘制自身。

这种单线线程模型就会使得 android 的应用程序性能低下, 如果在这个单线程里执行一些耗时的操作, 比如访问数据库, 或是从网络端下载图片, 就会会阻塞整个用户界面。 比如如下操作:

view source
print ?
1 Bitmap b =  loadImageFromNetwork();

这个操作非常耗时, 在这种情况下你会发现 , 界面僵死在那里并且 android 在系统 5 秒中后没有反应,会显示一个关闭或等待的错误。

也许我们可以使用一个新的 Thread 来解决它

view source
print ?
1 newThread(newRunnable() { 
2     publicvoidrun() {                        
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

view source
print ?
1 newThread(newRunnable() {   
2            publicvoidrun() {   
3                     finalBitmap b = loadImageFromNetwork();   
4                     mImageView.post(newRunnable() {   
5                     mImageView.setImageBitmap( b );   
6 });   
7          }   
8 }).start();

这种方法比较繁琐,同时当你需要实现一些很复杂的操作并需要频繁地更新UI 时这会变得更糟糕。为了解决这个问题,android 提供了一个工具类:AsyncTask ,它使创建需要与用户界面交互的长时间运行的任务变得更简单。

就拿加载网络图片举个例子:

view source
print ?
01 ublicclassCanvasImageTaskextendsAsyncTask<ImageView, Void, Bitmap>{
02        privateImageView gView ;
03        
04    protectedBitmap doInBackground(ImageView... views) {
05                Bitmap bmp =null;
06                ImageView view = views[0];
07            // 根据iconUrl获取图片并渲染,iconUrl的url放在了view的tag中。
08            if(view.getTag() !=null) {
09                    try{
10                       URL url =newURL(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                            returnnull;
20                    }
21            }
22            this.gView = view;
23            returnbmp;
24    }
25    protectedvoidonPostExecute(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                    newCanvasImageTask().execute(img);
39                    img.setDrawingCacheEnabled(true);
40                }catch(Exception e) {
41                    Log.e("error","RejectedExecutionException in content_img: "+  imgpath);

这样图片加载使用异步线程便不会进行堵塞发生错误,我们还可以使用 callback 在图片加载完后进行回调

view source
print ?
01 publicclassCanvasImageTaskCallextendsAsyncTask<ImageView, Void, Bitmap>implementsCallback{
02    privateImageView gView ;
03    
04    protectedBitmap doInBackground(ImageView... views) {
05            Bitmap bmp =null;
06            ImageView view = views[0];
07            // 根据iconUrl获取图片并渲染,iconUrl的url放在了view的tag中。
08            if(view.getTag() !=null) {
09                    try{
10                       URL url =newURL(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 =newMessage();
21                            msg.what =0;
22                            handleMessage(msg);
23                            returnnull;
24                    }
25            }
26            this.gView = view;
27            returnbmp;
28    }
29    protectedvoidonPostExecute(Bitmap bm) {
30            if(bm !=null) {
31                this.gView.setImageBitmap(bm);
32                this.gView.setTag(bm);
33                this.gView =null;
34                Message msg =newMessage();
35                msg.what =1;
36                handleMessage(msg);
37            }
38    }
39    publicbooleanhandleMessage(Message msg) {
40        // TODO Auto-generated method stub
41        returnfalse;
42    }
43    
44 }

在 Activity 中直接调用

view source
print ?
01 newCanvasImageTaskCall(){
02                        @Override
03                        publicbooleanhandleMessage(Message msg) {
04                                switch(msg.what) {
05                                case0:
06                                        Log.i("test","图片加载失败");
07                                        break;
08                                case1:
09                                        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                                returnsuper.handleMessage(msg);
18                        }
19                }.execute(img);

你可能感兴趣的:(Android 线程模型和 AsyncTask)