使用线程更新UI

关键字 Thread 线程 停止

日期 2010/7/31

简述

当第一次启动一个Android 程序时,Android 会自动创建一个称为“main” 主线程的线程。这个主线程(也称为UI 线程)很重要,因为它 负责把事件分派到相应的控件,其中就包括屏幕绘图事件,它同样是用户与Andriod 控件交互的线程。比如,当你在屏幕上按下一个按钮后,UI 线程会把这 个事件分发给刚按得那个按钮,紧接着按钮设置它自身为被按下状态并向事件队列发送一个无效(invalidate )请求。UI 线程会把这个请求移出事件队 列并通知按钮在屏幕上重新绘制自身。

单线程模型会在没有考虑到它的影响的情况下引起Android 应用程序性能低下,因为所有的任务都在同一个线程中执行,如果执行一些耗时的操作,如 访问网络或查询数据库,会阻塞整个用户界面。当在执行一些耗时的操作的时候,不能及时地分发事件,包括用户界面重绘事件。从用户的角度来看,应用程序看上 去像挂掉了。更糟糕的是,如果阻塞应用程序的时间过长(现在大概是5 秒钟)Android 会向用户提示一些信息,即打开一个 应用程序没有相应 (application not responding 的对话框。

如果你想知道这有多糟糕,写一个简单的含有一个按钮的程序,并为按钮注册一个单击事件,并在事件处理器中调用这样的代码 Thread.sleep(2000) 。在按下这个按钮这后恢复按钮的正常状态之前,它会保持按下状态大概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 线程中执行。

使用Handler 来更新UI

建立一个线程,设一个boolean 变量来控制线程的运行,当收到被调用 interrupt() 时就产生InterruptedException 异常,catch 异常后改变变量,这样就可以停止线程了。

private Thread thread = new Thread() {       @Override       public void run() {              boolean running = true;              while (running) {                     try {                            settime.sendMessage(settime.obtainMessage());                            Thread.sleep(1000);                     } catch (InterruptedException e) {                            Log.d("Thread", "Exception");                            running =false;                     }              }       }};

Handler 可以认为是消息队列,线程发送消息,主线程中的Handler 收到消息,更新UI ,这样就避免了UI 在线程中被更新。

private Handler settime = new Handler() {       Time t = new Time();       String time = new String();       @Override       public void handleMessage(Message msg) {              super.handleMessage(msg);              t.setToNow();              tv_time.setText(time.format("%2d:%2d %d", t.hour, t.minute, t.second));       }};

调用interrupt() 以停止线程运行

b_cancel.setOnClickListener(new OnClickListener() {       @Override       public void onClick(View v) {              thread.interrupt();       }});

更多相关文章

  1. android设备与蓝牙模块之间交互(蓝牙命令,收发)的两种方式,附DEMO下
  2. Android界面刷新方法
  3. 异步任务加载网络数据——AsyncTask使用
  4. android笔记--android的进程与线程
  5. Android性能分析工具Systrace和TraceView的使用
  6. android多线程断点下载——网络编
  7. 深入Android开发之--Android事件模型
  8. Android消息机制(二)
  9. 【转】Android面试题大集合

随机推荐

  1. 【DG】DG概念原理详解
  2. 【ASM】ASM基础知识
  3. 【MOS】OCR/Vote disk 维护操作: (添加/
  4. 【DG】DG环境的日常巡检
  5. 分布式监控系统Zabbix--完整安装记录 -添
  6. DG环境的日常巡检
  7. NestJs学习之旅(1)——快速开始
  8. 3.22作业-0411
  9. 使用flex仿写手机首页
  10. js三 作用域与闭包,继承