`
helpbs
  • 浏览: 1163372 次
文章分类
社区版块
存档分类
最新评论

不良代码展示-Activity中使用线程的例子

 
阅读更多

一段坏代码如何变成优雅代码

原创文章,如有转载,请注明出处:http://blog.csdn.net/yihui823/article/details/6741411

今天看到一段很糟糕的代码。于是做了一个工程,模拟这段代码,向大家说明一下线程在使用中要注意的几点。这个例子适合给新手,也欢迎各位高手来指点一下。

首先,上代码。

第一个类LoginService,这是一个模拟类,把业务剥离出去了。只是模拟登录操作而已。


第二个类就是我们的Activity了。







增加了Log,以便查看登录情况。模拟业务代码只改了一行,就是登录永远是失败。现在运行一下呢。停在页面上没有动静了,logcat里也不断的打出:
we are login
这个也不会有什么错误,对吧。但是,我们如果按“返回”键退出页面,再看看logcat呢?
we are login的log还在不停的输出,是吗?
我想现在大家应该知道哪里出了问题了。就是说,我们的线程启动之后,就没法停掉了。
这里我要说一下。我一直认为,
new Thread(new Runnable() {…}().start();
这种代码写的非常的不好。你直接构造了一个对象,但是这个对象你没有任何的变量去指向它。这个线程被你启动之后,你已经无法再去跟踪、调用、管理了。这个线程,只能自生自灭,永远游离在你的控制范围之外。你会不会觉得,这个线程跟僵尸一样?对,这就是僵尸进程,如果它没有停止的条件,就永远在你的系统里消耗你的资源。
所以我觉得使用线程的一个基本认识:生成的线程类,一定要有一个变量去指向它,以便在合适的时候销毁。
这里说到销毁,这就是另一个问题了。Thread类已经废弃了stop方法了,因为线程需要自行去释放该释放的资源,不能光依赖于运行框架的控制。我们需要在Thread里面,加上他自己停止的代码。也就是说,不论如何,线程应该会自己去停止掉,而不应该是无限制的运行。
另外,我们在Android里面,还应该注意Activity的各个状态周转。一般来说,线程的启动在onCreate里是不合适的,我们必须考虑到onResume和onPause的情况。
那么,我们总结下,Activity里使用线程有三个注意:
1, 线程对象一定要有变量指向它,以便我们可以控制。
2, 线程类一定要有停止条件,以便外界通知线程自行停止。
3, 在onResume里启动线程,在onPause里停止线程

我们根据以上三点,重新写一下Activity。



现在,我们的线程可以在页面退出的时候正常停止了。

但是这段代码还是有问题的。我们仔细看看,线程在Activity构造的时候就已经创建了,然后在程序进到前台的时候启动,退到后台的时候停止。但是线程有这么一个特性:
一旦线程的run()函数运行结束了,这个线程就销毁了,不能再启动了。
现在我们的程序,在退出后将不可能再次显示,所以系统会马上回收掉Activity。如果我们的页面增加一个按钮,迁移到另一个页面,那么在那个页面返回的时候,就会有异常出现。我们修改一下代码来试试。
增加一个Activity:



别忘了修改AndroidManifest.xml,增加Activity的说明:

<activity android:name=".TempActivity"
android:label="@string/app_name"/>

修改BadCodeActivity:



其实就是加了一个按钮,做一个页面迁移。别忘了在main.xml里面加上:


现在我们运行程序。运行之后,点击按钮,画面闪动一下说明是切换了页面。我们偷了个懒,两个Activity共用一个layout,所以页面没有任何变化。但是没关系,我们看log,we are login已经停止输出了。这个时候,我们再按返回键,应该是切换回BadCodeActivity。这个时候系统报错:

java.lang.IllegalThreadStateException: Thread already started.

显然,就是说线程已经启动过了,不能再次被利用。

我们对代码需要做一点点修改。当然,我们也顺手改掉一个BUG:在退出的时候还会报告登录成功。

并且,我们把控制变量都放在内部类里,做到变量最小化生存空间。

修改后如下:


现在,我们点击按钮,进入到TempActivity的时候,登录log停止输出;然后按返回键,回到BadCodeActivity的时候,登录log又继续输出。程序基本完成,没有僵尸线程存在了。红色的那行代码是关键!

我们总结一下:

1, 线程对象一定要有变量指向它,以便我们可以控制。

2, 线程类一定要有停止条件,以便外界通知线程自行停止。

3, 线程启动之后,不管是不是已经停止了,都是不能再次利用的。

4, 在onResume里新建和启动线程,在onPause里停止线程。






  


  
分享到:
评论

相关推荐

    Android高级编程--源代码

    8.3.2 在工作(worker)线程中使用Toast 265 8.4 Notification简介 266 8.4.1 Notification Manager简介 267 8.4.2 创建Notification 267 8.4.3 触发Notification 268 8.4.4 向Earthquake Monitor中添加...

    新版Android开发教程.rar

    放源代码的移动系统。开放手机联盟包括手机制造商、手机芯片厂商和移动运营商几类。目前,联盟成员 数 量已经达到了 43 家。 移动手机联盟创始成员: Aplix 、 Ascender 、 Audience 、 Broadcom 、中国移动、 eBay ...

    安卓MonkeyRunner自动化测试Lowen.zip

    代码有待完善,欢迎有兴趣的朋友一起讨论(目前报表里面使用echarts部分没有写数据处理逻辑,框架已搭好) 主框架代码1 bin\lowen_play.bat 循环执行N个py脚本 1.初始化路径,时间 ...

    《软件系统架构与开发环境》第二章源代码-by 南邮-陈杨

    资深专家倾情之作,揭秘软件系统架构设计真谛 内容包罗万象 叙述言简意赅 分析全面透彻 层次清晰合理 软件架构的好坏直接决定了软件系统的成败,而软件架构设计最关键的就是要解决... 2.7.4 Android应用开发例子 152

    EventBus例子

    关于EventBus的android代码实现。EventBus主要用于线程间的通信。总共分为四部分,发布者、订阅者、事件、总线。本例子实现两Activity间的事件订阅和发布。

    android-tinyasync:Android 活动中半同步半异步方法的最小演示

    任何直接与服务器通信的应用程序都必须在单独的线程中执行此操作,通常使用 AsyncTask。 关于如何做到这一点有很多困惑,还有很多不同的方法。 一些开发人员甚至围绕事件驱动的框架(如 RX And​​roid)重新设计...

    android开发之欢迎界面的小例子

    activity中线程代码如下:(顺便检测一下网络是否打开) [java] 代码如下:@Override protected void onStart() { super.onStart(); if(&lt;SPAN xss=removed&gt;isNetworkConnected()){ new Thread(){ @Override

    Android 常用六大框架

    支持链式表达查询,更直观的查询语义,参考下面的介绍或sample中的例子。 (2) 注解模块:android中的ioc框架,完全注解方式就可以进行UI,资源和事件绑定; 新的事件绑定方式,使用混淆工具混淆后仍可正常工作;...

    Android Thread 介绍与实例

    Android中很重要的一个机制就是线程+消息,当然线程并不是android独有的,下面,简单的说说使用线程的时候应该注意的地方 我们采用最简单的方法来建立一个android的线程+消息的例子 1.Thread + Handler [java] 代码...

    android Handler详细使用方法实例

    开发环境为android4.1.Handler使用例1这个例子是最简单的介绍handler使用的,是将handler绑定到它所建立的线程中.本次实验完成的功能是:单击Start按钮,程序会开始启动线程,并且线程程序完成后延时1s会继续启动该...

    坚持学习WF

    坚持学习WF(10):在工作流中使用关联 当工作流实例在本地服务接口上侦听相同事件的不同实例时,就无法确定该响应哪个事件。如何解决这个问题呢,我们就需要在工作流中使用关联。 坚持学习WF(11):工作流通信与队列 WF...

    坚持学习WF,WF学习教程

    本文利用MSDN中的一个例子来说明工作流中的线程以及如何使用DefaultWorkflowSchedulerService和ManualWorkflowSchedulerService服务。 坚持学习WF(20):规则引擎中的活动条件 坚持学习WF(21):规则引擎中的RuleSet ...

    androidListView的上部下拉刷新下部点击加载更多具体实现及拓展

    这次就不上图了,例子太多太多了,想必大家都见过...具体应用:(只需要这样引用即可.)在Activity中的调用,相比大家都清楚,开个异步或线程进行加载数据,这里我简单说一下异步使用,线程同理.代码如下:先声明一点,

    android开发资料大全

    Android中利用画图类和线程画出闪烁的心形,送给亲爱的他 android自带的示例程序 BluetoothChat 变蓝牙串口助手(内含DIY蓝牙遥控车附源码实例教程) Android高手过招 FAQ 网友收集的android开发书籍(可下载哦)...

    log4cplus 源码(C++编写的开源的日志系统)

    本文介绍了使用log4cplus有六个步骤,并提供了一些例子引导你了解log4cplus的基本使用。 ### 基本使用 ### 使用log4cplus有六个基本步骤: 1. 实例化一个appender对象 2. 实例化一个layout对象 3. 将layout...

    Moxy:Moxy是适用于Android的MVP库,具有增量注释处理器和ktx功能

    重新创建Activity时, Presenter保持活动状态(简化了多线程处理) 自动还原重新创建的活动中的所有内容(包括其他动态内容) 例子 查看界面 interface MainView : MvpView { @AddToEndSingle fun displayUser ...

    OPhone应用开发权威指南(黄晓庆)

    5.2.1 一个简单的例子:绘制立方体 169 5.2.2 理解变换 175 5.2.3 投影变换 177 5.2.4 视口变换 179 5.2.5 矩阵堆栈 180 5.3 绘制图元 180 5.3.1 图元种类 180 5.3.2 指定顶点数据 182 5.3.3 绘制图元 186 5.4 颜色...

    AsyncTask陷阱之:Handler,Looper与MessageQueue的详解

    AsyncTask的隐蔽陷阱先来看一个实例这个例子很简单,展示了AsyncTask的一种极端用法,挺怪的。 代码如下:public class AsyncTaskTrapActivity extends Activity { private SimpleAsyncTask asynctask; private ...

Global site tag (gtag.js) - Google Analytics