android线程:

通用多个线程通信管理框架:

1、Handler监听者框架:子线程是事件源,主线程是监听者。
        Handler作为子线程的监听器出现:主线程中生成Handler的子类,并重写handleMessage(Message msg) 方法,
        用来对子线程响应。子线程调用Hanlder的sendMessage(message)发送事件。

  1. package fy.test;
  2. import android.app.Activity;
  3. import android.os.Bundle;
  4. import android.os.Handler;
  5. import android.os.Message;
  6. import android.widget.TextView;
  7. public class MyTest extends Activity {
  8. public static final int REFRESH = 0x000001;
  9. private TextView text = null;
  10. private int i = 0;
  11. private Handler mHandler = null;
  12. /** Called when the activity is first created. */
  13. @Override
  14. public void onCreate(Bundle savedInstanceState) {
  15. super.onCreate(savedInstanceState);
  16. setContentView(R.layout.main);
  17. text = (TextView) findViewById(R.id.threadText);
  18. mHandler = new Handler() {
  19. @Override
  20. public void handleMessage(Message msg) {
  21. if (msg.what == REFRESH) {
  22. text.setText(i + "");
  23. }
  24. super.handleMessage(msg);
  25. }
  26. };
  27. new MyThread().start();
  28. }
  29. public class MyThread extends Thread {
  30. public void run() {
  31. while (!Thread.currentThread().isInterrupted()) {
  32. i++;
  33. Message msg = new Message();
  34. msg.what = REFRESH;
  35. mHandler.sendMessage(msg);
  36. try {
  37. Thread.sleep(1000);
  38. } catch (InterruptedException e) {
  39. e.printStackTrace();
  40. }
  41. }
  42. }
  43. }
  44. }

2、Handler钩子方式:在主线程中生成一个Hanlder,用Handler的Post(Runnable)方法可以将Runnable钩到主线程中运行。

  1. package fy.test;
  2. import android.app.Activity;
  3. import android.os.Bundle;
  4. import android.os.Handler;
  5. import android.widget.TextView;
  6. public class MyTest extends Activity {
  7. private TextView text = null;
  8. private int i = 0;
  9. private Handler mHandler = null;
  10. /** Called when the activity is first created. */
  11. @Override
  12. public void onCreate(Bundle savedInstanceState) {
  13. super.onCreate(savedInstanceState);
  14. setContentView(R.layout.main);
  15. text = (TextView) findViewById(R.id.threadText);
  16. mHandler = new Handler();
  17. new Thread(new Runnable() {
  18. @Override
  19. public void run() {
  20. while (true) {
  21. i++;
  22. mHandler.post(new Runnable() {
  23. @Override
  24. public void run() {
  25. text.setText(i + "");
  26. }
  27. });
  28. try {
  29. Thread.sleep(1000);
  30. } catch (InterruptedException e) {
  31. e.printStackTrace();
  32. }
  33. }
  34. }
  35. }).start();
  36. }
  37. }

注意一下代码是错误的,因为post里的线程结束后才会刷新UI

  1. package fy.test;
  2. import android.app.Activity;
  3. import android.os.Bundle;
  4. import android.os.Handler;
  5. import android.widget.TextView;
  6. public class MyTest extends Activity {
  7. private TextView text = null;
  8. private int i = 0;
  9. private Handler mHandler = null;
  10. /** Called when the activity is first created. */
  11. @Override
  12. public void onCreate(Bundle savedInstanceState) {
  13. super.onCreate(savedInstanceState);
  14. setContentView(R.layout.main);
  15. text = (TextView) findViewById(R.id.threadText);
  16. mHandler = new Handler();
  17. mHandler.post(new Runnable() {
  18. @Override
  19. public void run() {
  20. // TODO Auto-generated method stub
  21. while(true){
  22. i ++;
  23. text.setText(""+i);
  24. try {
  25. Thread.sleep(1000);
  26. } catch (InterruptedException e) {
  27. e.printStackTrace();
  28. }
  29. }
  30. }
  31. });
  32. }
  33. }

3、AsyncTask框架

Activity的UI线程方案:

1、runOnUiThread(Runable):

  1. package fy.test;
  2. import android.app.Activity;
  3. import android.os.Bundle;
  4. import android.widget.TextView;
  5. public class MyTest extends Activity {
  6. private int x = 0;
  7. /** Called when the activity is first created. */
  8. @Override
  9. public void onCreate(Bundle savedInstanceState) {
  10. super.onCreate(savedInstanceState);
  11. setContentView(R.layout.main);
  12. final TextView text = (TextView) findViewById(R.id.threadText);
  13. new Thread(new Runnable() {
  14. @Override
  15. public void run() {
  16. while(true){
  17. //需要进行的逻辑处理
  18. x++;
  19. System.out.println("x="+x);
  20. //注:text的更新必须等到runnable里面的执行结束之后,才执行
  21. runOnUiThread(new Runnable() {
  22. public void run() {
  23. text.setText(x+"");
  24. }
  25. });
  26. try {
  27. Thread.sleep(1000);
  28. } catch (InterruptedException e) {
  29. e.printStackTrace();
  30. }
  31. }
  32. }
  33. }).start();
  34. }
  35. }

View的UI线程方案:

1、postInvalidate()重绘,可在子线程中更新界面

2、SufaceView框架



本文主要介绍Android的Handler的使用方法。Handler可以发送Messsage和Runnable对象到与其相关联的线程的消息队列。每个Handler对象与创建它的线程相关联,并且每个Handler对象只能与一个线程相关联。

Handler一般有两种用途:1)执行计划任务,你可以再预定的实现执行某些任务,可以模拟定时器。2)线程间通信。在Android的应用启动时,会
创建一个主线程,主线程会创建一个消息队列来处理各种消息。当你创建子线程时,你可以再你的子线程中拿到父线程中创建的Handler对象,就可以通过该
对象向父线程的消息队列发送消息了。由于Android要求在UI线程中更新界面,因此,可以通过该方法在其它线程中更新界面。
◆ 通过Runnable在子线程中更新界面的例子

○ 在onCreate中创建Handler
public class HandlerTestApp extends Activity {
        Handler mHandler;
        TextView mText;
        /** Called when the activity is first created. */
       @Override
       public void onCreate(Bundle savedInstanceState) {
           super.onCreate(savedInstanceState);
           setContentView(R.layout.main);
           mHandler = new Handler();//创建Handler
           mText = (TextView) findViewById(R.id.text0);//一个TextView
       }
     ○ 构建Runnable对象,在runnable中更新界面,此处,我们修改了TextView的文字.此处需要说明的是,Runnable对象可以再主线程中创建,也可以再子线程中创建。我们此处是在子线程中创建的。 
     Runnable mRunnable0 = new Runnable()
    {
                @Override
                public void run() {
                        // TODO Auto-generated method stub
                        mText.setText("This is Update from ohter thread, Mouse DOWN");
                }
    };

○ 创建子线程,在线程的run函数中,我们向主线程的消息队列发送了一个runnable来更新界面。

private void updateUIByRunnable(){
          new Thread() 
         { 
               //Message msg = mHandler.obtainMessage(); 
              public void run() 
             {

//mText.setText("This is Update from ohter thread, Mouse DOWN");//这句将抛出异常
                   mHandler.post(mRunnable0); 
             } 
         }.start();

}

◆ 用Message在子线程中来更新界面

用Message更新界面与Runnable更新界面类似,只是需要修改几个地方。
    ○ 实现自己的Handler,对消息进行处理

private class MyHandler extends Handler
    {

@Override
        public void handleMessage(Message msg) {
            // TODO Auto-generated method stub
            super.handleMessage(msg);
            switch(msg.what)
            {
            case UPDATE://在收到消息时,对界面进行更新
                mText.setText("This update by message");
                break;
            }
        }
    }

○ 在新的线程中发送消息    
    private void updateByMessage()
    {
        //匿名对象
         new Thread()
         {
                public void run()
                {
                    //mText.setText("This is Update from ohter thread, Mouse DOWN");

//UPDATE是一个自己定义的整数,代表了消息ID
                    Message msg = mHandler.obtainMessage(UPDATE);
                    mHandler.sendMessage(msg);
                }
         }.start();
    }

昨天看了看Android的线程文档,记录一些东西。

Android用的是J2SE,因此在其中的线程就是Java的线程。但是Android有自己的一套框架,因此线程的使用有一些新的东西。

活动与服务
在Android中,程序可以分成好几个组件,其中最重要的两个就是活动(Activity)和服务(Service)。活动是用户的GUI,而服务则运行于后台。比如说,一个IM,活动就是聊天的界面,而服务则用于网络通讯。

如果仅仅是这样的话,那么服务不过是一个没有界面的活动而已。但是实际上并非如此。为了节约资源,当一个活动不可见的时候,它是不会执行任何代码的,这时候就要靠服务了。例如在播放音乐的时候,就必须要用到服务,不然一切换到别的软件音乐就停了。

因此服务就给程序提供了后台运行的可能。更进一步的,服务是可以远程调用的,不只这个程序可以调用它,其他程序也可以调用它(前提是有相应的接口和权限)。

但是有一点要注意的是,同一个进程中的服务和活动是在同一线程中的。换句话说,后台和GUI是会相互阻塞的。这个和我的直觉有点出入,因为既然是后
台服务嘛,怎么会阻塞到前台界面呢,但是事实就是如此。因此要在服务中执行长时间的操作(如网络应用)时,还是要自己创建线程来操作。

Looper和HandlerThread
Android在Java的线程上又加了一层,使得线程拥有了消息队列(Message
Queue)的支持。提供此支持的就是Looper。一个Looper负责执行一个消息循环,当消息队列里有消息时,处理消息,否则保持休眠。通常的
GUI框架都会有消息循环与分发的概念,Android通过Looper将这个概念引入到了Java的线程中。通过它,只需要很少的代码就能为Java的
线程加入这个功能:

view sourceprint?01
class LooperThread extends Thread {

02     public Handler mHandler;

03

04     public void run() {

05         Looper.prepare();

06

07         mHandler = new Handler() {

08             public void handleMessage(Message msg) {

09                 // 在此处理新消息

10             }

11         };

12

13         Looper.loop();

14     }

15 }

其中重载Handler的handleMessage()方法来处理消息。

Android提供了HandlerThread类,这个类本身就是一个支持消息循环的线程类。

注意要启动一个线程还是需要手动调用start()的。

Handler
Handler是用于操作线程的消息队列的类。可以用空参数创建它,这样它就自动绑定到创建它的线程的消息队列上。也可以为
它提供一个Looper,这样它就会绑定到Looper所在的线程上。Handler为不同线程之间的通信提供了方便。要和另外一个线程通信,只要得到它
的Handler就行了。

对于上面的示例代码,mHandler就是绑定到新创建线程的Handler(因为run()是在新的线程中运行的)。对于一个
HandlerThread,可以用getLooper()来得到它的Looper,但是要注意必须在这之前用start()启动了线程,不然是
Looper是空的(文档上没说明这点,囧了我好一阵子)。

Handler的最大好处在于,它不只可以发送消息,还可以用post()来发送一个Runnable。这样一来,就可以在指定进程里面执行Runnable的run()方法中的代码了,也就是跨线程方法调用:)

另外,通过将Handler绑定到自己所在的线程,然后用post()方法,可以使一段Runnable里的代码不是立刻执行,而是在线程的消息队列轮到post过去的Runnable时才执行。不过我不明白这有什么用,还请高人指点。

Handler还可以指定消息/Runnable被处理的时间,这就可以把它当成定时器了(不过精确度不会太高吧)。

runOnUiThread()
当一个线程有结果了,要通知GUI更新呢?可以用Context的getMainLooper()来得到主
线程,然后用Handler操作。但是Activity类提供了一个简单的方法:runOnUiThread()。于是我们可以在线程中调用要更新的
Activity的某个更新方法,在那个方法里用runOnUiThread(),将要运行的代码封装在一个Runnable里喂给它就行了。

以上就是目前所知道的Android里关于线程的一些方面,估计还有我不知道的东西,以后再说咯:P

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

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

如果你想知道这有多糟糕,写一个简单的含有一个按钮的程序,并为按钮注册一个单击事件,并在事件处理器中调用这样的代码
Thread.sleep(2000)。在按下这个按钮这后恢复按钮的正常状态之前,它会保持按下状态大概2秒钟。如果这样的情况在你编写的应用程序中发
生,用户的第一反应就是你的程序运行很慢。

现在你知道你应该避免在UI线程中执行耗时的操作,你很有可能会在后台线程或工作者线程中执行这些耗时的任务,这样做是否正确呢?让我们来看一个例子,在这个例子中按钮的单击事件从网络上下载一副图片并使用ImageView来展现这幅图片。代码如下:

Java代码 
public void onClick( View v ) { 
          new Thread( new Runnable() {
                public void run() {
                    Bitmap b = loadImageFromNetwork();
                    mImageView.setImageBitmap( b );
                }
          }).start();
    } 
public void onClick( View v ) {
 new Thread(
 new Runnable() {
 public void run() {
 Bitmap b = loadImageFromNetwork();
 mImageView.setImageBitmap( b );
 } }).start();
}

这段代码好像很好地解决了你遇到的问题,因为它不会阻塞UI线程。很不幸,它违背了单线程模型:Android
UI操作并不是线程安全的并且这些操作必须在UI线程中执行。在这段代码片段中,在一个工作者线程中使用ImageView的方法,这回引起一些很古怪的
问题。查处这个问题并修复这个bug会很困难而且也很耗时。

Andriod提供了几种在其他线程中访问UI线程的方法。或许你已经对其中的一些方式很熟悉,但下面是一个更全面的列表:

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

上面的任何一个类或方法都可以修复我们前面代码中出现的问题。

Java代码  public void onClick( View v ) {            new Thread( new
Runnable() {                    public void run()
{                             final Bitmap b =
loadImageFromNetwork();                             mImageView.post( new
Runnable() {                                     
mImageView.setImageBitmap( b );                             
});                     }            }).start();    }  public void
onClick( View v ) { new Thread( new Runnable() { public void run() {
final Bitmap b = loadImageFromNetwork(); mImageView.post( new Runnable()
{ mImageView.setImageBitmap( b ); }); } }).start(); }

很不幸的是这些类或方法同样会使你的代码很复杂很难理解。然而当你需要实现一些很复杂的操作并需要频繁地更新UI时这会变得更糟糕。为了解决这个问
题,Android 1.5提供了一个工具类:AsyncTask,它使创建需要与用户界面交互的长时间运行的任务变得更简单。

在Android 1.0和1.1中具有与AsyncTask相同功能的类UserTask。它提供了完全一样的API,你需要做的只是把它的代码拷贝的你的程序中。

AsyncTask的目标是替你管理你的线程。前面的代码可以很容易地使用AsyncTask重写。

Java代码  public void onClick( View v ) {         new DownloadImageTask().execute( "http://example.com/image.png"
);    }       private class DownloadImageTask extends AsyncTask
{         protected Bitmap doInBackground( String... urls )
{              return loadImageFormNetwork( urls[0] );        
}            protected void onPostExecute( Bitmap result ) {            
mImageView.setImageBitmap( result );         }    }  public void
onClick( View v ) { new DownloadImageTask().execute( "http://example.com/image.png"
); } private class DownloadImageTask extends AsyncTask { protected
Bitmap doInBackground( String... urls ) { return loadImageFormNetwork(
urls[0] ); } protected void onPostExecute( Bitmap result ) {
mImageView.setImageBitmap( result ); } }

正如你看到的,使用AsyncTask必须要继承它。使用AsyncTask非常重要的是:AsyncTask的实例必须在UI线程中创建而且只能被使用一次。你可以使用预读AsyncTask的文档来来了解如何使用这个类,下面大概地了解一下它是如何工作的:

你可以使用泛型参数制定任务的参数、中间值(progress values)和任何的最终执行结果
doInBackground()方法会自动地在工作者线程中执行
onPreExecute()、onPostExecute()和onProgressUpdate()方法会在UI线程中被调用
doInBackground()方法的返回值会被传递给onPostExecute()方法
在doInBackground()方法中你可以调用publishProgress()方法,每一次调用都会使UI线程执行一次
onProgressUpdate()方法 你可以在任何时候任何线程中取消这个任务

除了官方的文档,你可以阅读Shelves和Photostream源代码中的几个复杂的示例。我强烈地推荐阅读Shelves的源代码,它会使你知道如何在配置更改之间持久化任务以及在activity被销毁时正确的取消任务。

不管是否使用AsyncTask,始终记住以下两个关于单线程模型的准则:不要阻塞UI线程以及一切Android UI操作都在UI

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/yangpeng98/archive/2010/05/26/5625955.aspx

android 线程的更多相关文章

  1. Android线程管理之ThreadLocal理解及应用场景

    前言: 最近在学习总结Android的动画效果,当学到Android属性动画的时候大致看了下源代码,里面的AnimationHandler存取使用了ThreadLocal,激起了我很大的好奇心以及兴趣 ...

  2. Android线程管理之Thread使用总结

    前言 最近在一直准备总结一下Android上的线程管理,今天先来总结一下Thread使用. 线程管理相关文章地址: Android线程管理之Thread使用总结 Android线程管理之Executo ...

  3. Android线程管理之ExecutorService线程池

    前言: 上篇学习了线程Thread的使用,今天来学习一下线程池ExecutorService. 线程管理相关文章地址: Android线程管理之Thread使用总结 Android线程管理之Execu ...

  4. Android线程管理之ThreadPoolExecutor自定义线程池

    前言: 上篇主要介绍了使用线程池的好处以及ExecutorService接口,然后学习了通过Executors工厂类生成满足不同需求的简单线程池,但是有时候我们需要相对复杂的线程池的时候就需要我们自己 ...

  5. Android线程管理之AsyncTask异步任务

    前言: 前面几篇文章主要学习了线程以及线程池的创建与使用,今天来学习一下AsyncTask异步任务,学习下AsyncTask到底解决了什么问题?然而它有什么弊端?正所谓知己知彼百战百胜嘛! 线程管理相 ...

  6. Android线程之主线程向子线程发送消息

    和大家一起探讨Android线程已经有些日子了,谈的最多的就是如何把子线程中的数据发送给主线程进行处理,进行UI界面的更新,为什么要这样,请查阅之前的随笔.本篇我们就来讨论一下关于主线程向子线程如何发 ...

  7. Android线程管理(三)——Thread类的内部原理、休眠及唤醒

    线程通信.ActivityThread及Thread类是理解Android线程管理的关键. 线程,作为CPU调度资源的基本单位,在Android等针对嵌入式设备的操作系统中,有着非常重要和基础的作用. ...

  8. Android线程管理(二)——ActivityThread

    线程通信.ActivityThread及Thread类是理解Android线程管理的关键. 线程,作为CPU调度资源的基本单位,在Android等针对嵌入式设备的操作系统中,有着非常重要和基础的作用. ...

  9. android 线程学习

    很多人觉得线程难理解,主要有两个问题: 线程休眠,既然线程已经休眠了,程序的运行速度还能提高吗? 线程体一般都进行死循环,既然线程死循环,程序就应该死掉了,就会没有反应. 1.关于线程休眠问题 对线程 ...

  10. Android 线程模型

    Android 线程模型 1. import android.os.Handler;  import android.os.Message; public class MainActivity ext ...

随机推荐

  1. Android 拍照 代码实例

    ------- 源自梦想.永远是你IT事业的好友.只是勇敢地说出我学到! ---------- 这是我做的一个简单的利用Android手机的摄像头进行拍照的实例. 在这里我实现了基本的拍照.照片的存储 ...

  2. oracle PL/SQL(procedure language/SQL)程序设计之异常(exception)

    什么是异常?在PL/SQL中的一个标识.在程序运行期间被触发的错误.异常是怎样被触发的?产生一个Oracle错误.用户显示触发.怎样处理异常?用异常处理句柄捕获异常.传播异常到调用环境. 捕获异常 E ...

  3. POJ 1797 Heavy Transportation (最短路)

    Heavy Transportation Time Limit: 3000MS   Memory Limit: 30000K Total Submissions: 22440   Accepted:  ...

  4. 转: android app进程保活的文章列表

    1. Android 后台任务型App多进程架构演化 http://www.jianshu.com/p/4ac1f373e8cd 2. 关于 Android 进程保活,你所需要知道的一切 http:/ ...

  5. 转:eclipse技巧之快速生成Override函数

    转自: http://www.cnblogs.com/junqilian/archive/2013/03/15/2960277.html 小提示:Eclipse 中快速实现或Override基类或接口 ...

  6. 磁珠 磁环 双向二极管 TVS二极管

    磁珠专用于抑制信号线.电源线上的高频噪声和尖峰干扰,还具有吸收静电脉冲的能力.磁珠是用来吸收超高频信号,像一些RF电路,PLL,振荡电路,含超高频存储器电路(DDR SDRAM,RAMBUS等)都需要 ...

  7. Javascript中对象类型的参数传递

    function setName(obj){ obj.name = 'Niccholas'; console.log(obj.name); //Niccholas obj = new Object() ...

  8. SQL IDENTITY(int,1,1) 用法

    select IDENTITY(int,1,1) as SortID from tb_order 仅当 SELECT 语句中有 INTO 子句时,才能使用 IDENTITY 函数. select ID ...

  9. 增强for循环用法___ArrayList数组实现使用下标最好,LinkedList使用增强型的(转载)

    总结: 1.For-Each循环的缺点:丢掉了索引信息. 当遍历集合或数组时,如果需要访问集合或数组的下标,那么最好使用旧式的方式来实现循环或遍历,而不要使用增强的for循环,因为它丢失了下标信息. ...

  10. github 学习笔记【一】

    这几天在学习github ,其实学了主要用来管理自己的项目!因为要在家里和公司两头做! 所以就开始学习使用!目前熟练几个命令,其他的一边用一遍学吧!想一举成功应该是不太可能的! 反复记忆才能更好,据说 ...