文档章节

Android线程模型和AsyncTask

蜗牛TT
 蜗牛TT
发布于 2012/11/06 22:38
字数 856
阅读 339
收藏 10

【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>

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

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

Bitmap b =  loadImageFromNetwork();


EE

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

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

new Thread(new Runnable() {  
     public void run() {                         
          Bitmap b = loadImageFromNetwork();    
          mImageView.setImageBitmap( b );    
     }  
}).start();

但这样会发生一些很难察觉的错误, 因为我们知道 UI 线程不是线程安全的。当然有很多种方法来处理这个问题:

android 提供了几种在其他线程中访问 UI 线程的方法。

• Activity.runOnUiThread( Runnable )
• View.post( Runnable )
• View.postDelayed( Runnable, long )
• Hanlder

new Thread( new Runnable() {    
            public void run() {    
                     final Bitmap b = loadImageFromNetwork();    
                     mImageView.post( new Runnable() {    
                     mImageView.setImageBitmap( b );    
});    
          }    
}).start();

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

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

ublic class CanvasImageTask extends AsyncTask<ImageView, Void, Bitmap>{
        private ImageView gView ;
        
    protected Bitmap doInBackground(ImageView... views) {
                Bitmap bmp = null ;
                ImageView view = views[0];
            // 根据iconUrl获取图片并渲染,iconUrl的url放在了view的tag中。
            if (view.getTag() != null) {
                    try {
                       URL url = new URL(view.getTag().toString());
                       HttpURLConnection conn = (HttpURLConnection)url.openConnection();
                       conn.setDoInput(true);
                       conn.connect();
                       InputStream stream = conn.getInputStream();
                       bmp = BitmapFactory.decodeStream(stream);
                       stream.close();
                    } catch (Exception e) {
                                Log.v("img", e.getMessage());
                            return null;
                    }
            }
            this.gView = view;
            return bmp;
    }
    protected void onPostExecute(Bitmap bm) {
            if (bm != null) {
                    this.gView.setImageBitmap(bm);
                    this.gView = null ;
            }
    }
    
}
在Activity中直接调用
if(!img.isDrawingCacheEnabled() || !holder.image.getTag().equals(imgpath)){
                img.setImageResource(R.drawable.icon_app);
                img.setTag(imgpath);
                try{
                    new CanvasImageTask().execute(img);
                    img.setDrawingCacheEnabled(true);
                }catch (Exception e) {
                    Log.e("error", "RejectedExecutionException in content_img: " +  imgpath);
这样图片加载使用异步线程便不会进行堵塞发生错误,我们还可以使用 callback 在图片加载完后进行回调

public class CanvasImageTaskCall extends AsyncTask<ImageView, Void, Bitmap> implements Callback{
    private ImageView gView ;
    
    protected Bitmap doInBackground(ImageView... views) {
            Bitmap bmp = null ;
            ImageView view = views[0];
            // 根据iconUrl获取图片并渲染,iconUrl的url放在了view的tag中。
            if (view.getTag() != null) {
                    try {
                       URL url = new URL(view.getTag().toString());
                       HttpURLConnection conn = (HttpURLConnection)url.openConnection();
                       conn.setDoInput(true);
                       conn.connect();
                       InputStream stream = conn.getInputStream();
                       bmp = BitmapFactory.decodeStream(stream);
                       stream.close();
                    } catch (Exception e) {
                            e.printStackTrace();
                            Log.v("img", e.getMessage());
                            Message msg = new Message();
                            msg.what = 0;
                            handleMessage(msg);
                            return null;
                    }
            }
            this.gView = view;
            return bmp;
    }
    protected void onPostExecute(Bitmap bm) {
            if (bm != null) {
                this.gView.setImageBitmap(bm);
                this.gView.setTag(bm);
                this.gView = null ;
                Message msg = new Message();
                msg.what = 1;
                handleMessage(msg);
            }
    }
    public boolean handleMessage(Message msg) {
        // TODO Auto-generated method stub
        return false;
    }
    
}
在 Activity 中直接调用

new CanvasImageTaskCall(){
                        @Override
                        public boolean handleMessage(Message msg) {
                                switch (msg.what) {
                                case 0:
                                        Log.i("test", "图片加载失败");
                                        break;
                                case 1:
                                        Log.i("test", "图片加载成功");
                                        break;
                                default:
                                        break;
                                }
                                saveButton.setTextColor(Color.WHITE);
                                saveButton.setClickable(true);
                                bitmap = (Bitmap) imageView.getTag();
                                return super.handleMessage(msg);
                        }
                }.execute(img);

本文转载自:http://blog.csdn.net/teasub/article/details/6453907

上一篇: git 配置
下一篇: 奇葩问题集
蜗牛TT
粉丝 55
博文 127
码字总数 34452
作品 0
海淀
高级程序员
私信 提问
Android 异步编程

文章作者:朱鸿,淘宝资深架构师 原文出处:http://hugozhu.myalert.info/2014/06/29/46-async-android.html Android的线程和内存模型 Android操作系统在boot后,会启动一个Zygote(受精卵)进...

鉴客
2014/07/01
1K
1
Android AsyncTask异步处理

在开发Android应用时必须遵守单线程模型的原则: Android UI操作并不是线程安全的并且这些操作必须在UI线程中执行。在单线程模型中始终要记住两条法则: 1. 不要阻塞UI线程 2. 确保只在UI线程...

长平狐
2013/01/06
103
0
android基础知识02——线程安全5: AsyncTask

android的UI操作不是线程安全的,同时也只有主线程才能够操作UI,同时主线程对于UI操作有一定的时间限制(最长5秒)。为了能够做一些比较耗时的操作(比如下载、打开大文件等),android提供...

迷途d书童
2012/03/23
1K
0
Android的UI设计与后台线程交互

本文将讨论Android应用程序的线程模型以及如何使用线程来处理耗时较长的操作,而不是在主线程中执行,保证用户界面(UI)的流畅运行。本文还将阐述一些用户界面(UI)中与线程交互的API。 UI...

mutouzhang
2014/03/15
477
2
Android 异步加载解决方案

Android的Lazy Load主要体现在网络数据(图片)异步加载、数据库查询、复杂业务逻辑处理以及费时任务操作导致的异步处理等方面。在介绍Android开发过程中,异步处理这个常见的技术问题之前,...

Pandora
2012/08/14
2.3K
1

没有更多内容

加载失败,请刷新页面

加载更多

redis数据类型/键值/服务常用操作、安全设置

Redis数据类型和常用操作 Redis有5中数据类型,分别是string(字符串)、list(链表)、set(集合)、sorted set(有序集合)、hash(哈希) 1.string string为最简单的类型,与Memcached一样,一个key...

asnfuy
35分钟前
4
0
SpringBoot整合邮件发送

本节介绍SpringBoot项目如何快速配置和发送邮件,包括简单的邮件配置、发送简单邮件、发送HTML邮件、发送携带附件的邮件等。 示例源码在:https://github.com/laolunsi/spring-boot-example...

空夜
35分钟前
5
0
删除目录的符号链接

我有一个重要目录的符号链接。 我想摆脱那个符号链接,同时保持它背后的目录。 我试过rm然后回来rm: cannot remove 'foo' 。 我尝试了rmdir并找回了rmdir: failed to remove 'foo': Director...

技术盛宴
39分钟前
5
0
分布式文件存储:FastDFS简单使用与原理分析

引言 FastDFS 属于分布式存储范畴,分布式文件系统 FastDFS 非常适合中小型项目,在我接手维护公司图片服务的时候开始接触到它,本篇文章目的是总结一下 FastDFS 的知识点。 用了 2 台 2 核 ...

ClawHub的技术分享
54分钟前
5
0
将Unix时间戳转换为JavaScript中的时间

我将时间作为Unix时间戳存储在MySQL数据库中,并将其发送到一些JavaScript代码。 我怎么会得到时间呢? 例如,以HH / MM / SS格式。 #1楼 另一种方式-从ISO 8601开始。 var timestamp = 1293...

javail
55分钟前
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部