Android中线程使用基础详解(一看就明白)

前言

线程这个东东真的是一个很平常的工具了,在我们大Android包括Java中都是必不可少司空见惯的东西,最近正好有段难得的离职空闲,今天就来和大家探讨探讨。ps:友情提示,以下链接请童靴们使用vpn查看。

正文

无论何时第一次启动Android应用程序,都会自动创建一个名为“main”的线程。主线程(也称为UI线程)非常重要,因为它负责将事件分派给相应的widget,并且包含绘制事件。这也是童靴们与Android widget进行交互的线程。例如,如果触摸屏幕上的一个Button,则UI线程将触发(dispatch)事件(event)分派给widget,该widget依次设置其按下的状态并向事件队列发布无效请求。UI线程使请求出队,并通知widget重绘本身。

这种单线程模型在Android应用程序中可能会产生不好的性能,而这些应用程序并没有考虑到这种影响由于所有事情都发生在执行长操作的单个线程(如网络访问或数据库查询)上,因此此线程将阻塞整个用户界面。在漫长的操作过程中,不能派发任何事件,包括绘画事件。从用户的角度来看,应用程序显示为挂起。更糟糕的是,如果UI线程被阻塞超过几秒(当前大约5秒),用户将看到臭名昭着的“应用程序无响应”(ANR)对话框。(你将有50%的几率永久失去该用户,这可能是你们公司销售人员挂着大鼻涕在寒风中送出鼠标垫可乐等换回来的一个用户 :))

如果童靴们想看看这看起来有多操蛋,用一个Thread.sleep(2000)在OnClickListener中调用的按钮编写一个简单的应用程序(ps:对thread的调用必须包在try/catch块中,避免抛出InterruptedException)。在返回到正常状态之前,按钮将保持其按压状态约2秒钟。发生这种情况时,用户很容易感知应用程序缓慢。

既然童靴们知道必须避免在UI线程上进行冗长的操作,童靴们可能会使用额外的线程(后台线程或工作线程)来执行这些操作。我们以一个点击监听器为例,通过网络下载一个图像并将其显示在一个ImageView中

public void onClick(View v) {

    new Thread(new Runnable() {

        public void run() {

            Bitmap b = loadImageFromNetwork();

            mImageView.setImageBitmap(b);

        }

    }).start();

}

起初,这段代码似乎是一个很好的解决方案,因为它不会阻塞UI线程。不幸的是,这违反了单线程模型:Android UI工具包不是线程安全的,并且必须总是在UI线程上操作。在这段代码中,ImageView在一个工作线程上进行操作,这可能会导致非常奇怪的问题。追查和修复这些错误可能是困难和耗时的。

Android提供了几种从其他线程访问UI线程的方式。童靴们可能已经熟悉了其中的一些,但是这里有一个全面的列表:

Activity.runOnUiThread(Runnable)

View.post(Runnable)

View.postDelayed(Runnable, long)

Handler

任何这些类和方法都可以用来纠正我们以前的代码示例:

public void onClick(View v) {

    new Thread(new Runnable() {

        public void run() {

            final Bitmap b = loadImageFromNetwork();

            mImageView.post(new Runnable() {

                public void run() {

                    mImageView.setImageBitmap(b);

                }

            });

        }

    }).start();

}

可惜的是,这些类和方法往往会使你的代码更复杂,更难以阅读。当你的实现需要频繁的UI更新的复杂操作时,情况会变得更糟。为了解决这个问题,Android 1.5提供了一个名为AsyncTask的工具类,它简化了需要与用户界面进行通信的长时间运行任务的创建。

AsyncTask也可以用于名为UserTask的Android 1.0和1.1。它提供了完全相同的API,童靴们所要做的就是在应用程序中复制它的源代码。

目标AsyncTask是为您照顾线程管理。我们以前的例子可以很容易地改写为AsyncTask:

public void onClick(View v) {

    new DownloadImageTask().execute("http://example.com/image.png");

}

private class DownloadImageTask extends AsyncTask {

    protected Bitmap doInBackground(String... urls) {

        return loadImageFromNetwork(urls[0]);

    }

    protected void onPostExecute(Bitmap result) {

        mImageView.setImageBitmap(result);

    }

}

正如所看到的,AsyncTask必须通过子类化来使用它。记住一个AsyncTask实例必须在UI线程上创建并且只能执行一次也是非常重要的。大家可以阅读AsyncTask文档以全面了解如何使用此类,但下面简要介绍它的工作原理:

大家可以使用泛型指定参数的类型,进度值和任务的最终值

doInBackground()方法在工作线程上自动执行

onPreExecute()onPostExecute()onProgressUpdate()都在UI线程上调用

doInBackground()返回的值被发送到onPostExecute()

童靴们可以随时在doInBackground()中调用publishProgress()以在UI线程上执行onProgressUpdate()

童靴们可以随时从任何线程取消任务

除了官方的文档,童靴们可以读取Shelves(源代码的几个复杂的例子ShelvesActivity.javaAddBookActivity.java)和照片流(LoginActivity.javaPhotostreamActivity.javaViewPhotoActivity.java)。强烈建议阅读Shelves的源代码,以了解如何在配置更改中保留任务,以及在活动被破坏时如何正确取消它们。

无论是否使用AsyncTask,请始终记住关于单线程模型的以下两条规则:请勿阻止UI线程,并确保仅在UI线程上访问Android UI工具包。AsyncTask只是使这两件事情更容易。

后记

这个后记纯属扯淡,不看也罢!

北京离职半个月了,走亲访友,看看风景,真的是不亦乐乎!奈何双亲担忧我成无业游民,于是往下个目的地互联网之都选投了几份简历,HR们真的很热情,家长里短一聊半小时,很是暖心。互联网之都就是不一样,关爱程序猿,从你我做起!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,755评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,369评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,799评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,910评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,096评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,159评论 3 411
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,917评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,360评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,673评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,814评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,509评论 4 334
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,156评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,882评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,123评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,641评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,728评论 2 351

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,870评论 25 707
  • 当某个应用组件启动且该应用没有运行其他任何组件时,Android 系统会使用单个执行线程为应用启动新的 Linux...
    小芸论阅读 1,683评论 0 12
  • 温暖,是被呵护的体现,比如为孩子提供了温暖的衣服或者空间还有对孩子“真诚的爱”(这里说的爱是诚实的,不是勉强对付的...
    July姗姗阅读 224评论 0 0
  • 几个男生聚拢谈论的话题总是离不开无聊的那几个,目不转睛地盯着迎面而来的妹纸,一个哥们淫笑:喂,你们都喜欢胸大的吗?...
    疯马皮阅读 348评论 0 0
  • 2017年8月3日 星期四 雨 学经人员:琪佳妈、琪琪、佳佳。 宝贝年龄:琪琪9岁1个月,佳佳7岁10个月。 ...
    顺德琪佳妈阅读 246评论 0 0