zoukankan      html  css  js  c++  java
  • Android线程与异步消息处理机制

    在程序开发时,对于一些比较耗时的操作,我们通常会为其开辟一个单独的线程来执行,这样可以尽可能的减少用户等待的时间。在Android中,默认情况下,所有的操作都是在主线程中进行的,这个主线程负责管理与UI相关的事件,而在我们自己创建的子线程中,又不能对UI组件进行操作,因此,Android提供了消息处理传递机制来解决这一个问题。

    1、多线程的常见操作

      1、创建线程。

      在Android中,提供了两种创建线程的方法。(一种是通过Thread类的构造方法创建线程对象,并重写run()方法实现,另一种是通过实现Runnable接口来实现。)

      第一种方法:

      Thread thread=new Thread(new Runnable(){

        @Override

        public void run(){

        //要执行的操作

        }

      });

      thread.start();

      第二种方法:

      public class MainActivity extends Activity implement Runnable{

      @Override

      public void run(){

        //要执行的操作

        }

      }

      2、开启线程

      3、线程休眠

      4、中断线程

    下面用一个实例来实现上述的这些操作

    首先是布局文件:

     1 <?xml version="1.0" encoding="utf-8"?>
     2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     3     android:layout_width="fill_parent"
     4     android:layout_height="fill_parent" >
     5 
     6     <Button
     7         android:id="@+id/button1"
     8         android:layout_width="wrap_content"
     9         android:layout_height="wrap_content"
    10         android:text="@string/start" />
    11 
    12     <Button
    13         android:id="@+id/button2"
    14         android:layout_width="wrap_content"
    15         android:layout_height="wrap_content"
    16         android:text="@string/stop" />    
    17 
    18 </LinearLayout>
    View Code

    然后修改默认的Activity:

     1 public class MainActivity extends Activity implements Runnable {
     2     private Thread thread;    //声明线程对象
     3     int i;    //循环变量
     4     
     5     @Override
     6     public void onCreate(Bundle savedInstanceState) {
     7         super.onCreate(savedInstanceState);
     8         setContentView(R.layout.main);
     9         Button startButton=(Button)findViewById(R.id.button1);    //获取“开始”按钮
    10         startButton.setOnClickListener(new OnClickListener() {
    11             
    12             @Override
    13             public void onClick(View v) {
    14                 i=0;
    15                 thread=new Thread(MainActivity.this);    //创建一个线程
    16                 thread.start();    //开启线程
    17                 
    18             }
    19         });
    20         Button stopButton=(Button)findViewById(R.id.button2);    //获取“停止”按钮
    21         stopButton.setOnClickListener(new OnClickListener() {
    22             
    23             @Override
    24             public void onClick(View v) {
    25                 if(thread!=null){
    26                     thread.interrupt();    //中断线程
    27                     thread=null;
    28                 }
    29                 Log.i("提示:","中断线程");
    30                 
    31             }
    32         });
    33     }
    34 
    35     @Override
    36     protected void onDestroy() {
    37 
    38         if(thread!=null){
    39             thread.interrupt();    //中断线程
    40             thread=null;
    41         }
    42         super.onDestroy();
    43     }
    44     @Override
    45     public void run() {
    46         while(!Thread.currentThread().isInterrupted()){
    47             i++;
    48             Log.i("循环变量:",String.valueOf(i));
    49         }
    50         
    51     }
    52 }
    View Code

    接下来运行即可。

    上面只是线程的简单操作。这里推荐一篇写得比较详细的文章:《java中的多线程

    2、异步消息处理机制

    在上面我们已经介绍了线程相关的知识点,不过此时还没有在新创建的子线程中对UI界面上的内容进行操作,如果用上面的方法进行操作,将会抛出异常。为此,Android中引入了异步消息处理机制,来实现在新创建的线程中操作UI界面。

    首先,我们来了解一些概念。

    什么是异步?

    简单来说,就是A和B两个人可以同时做两种事,也就是分别做自己的事。(而不是A做完事后B才开始做事)

    什么是消息处理机制?

    就应用程序而言,Android系统中JAVA的应用程序和其他系统上相同,都是靠消息驱动来工作的,他们大致的工作原理如下:

    1、有一个消息队列,可以往这个消息队列中投递消息。

    2、有一个消息循环,不断从消息队列中取出消息,然后处理。

    在Android中,一个线程对应一个Looper对象,而一个Looper对象又对应一个MessageQueue(用于存放message)。

    接下来,我们来了解几个类:循环者Looper类,消息处理类Handler,消息类Message。

    Looper对象用来为一个线程开启一个消息循环,用来操作MessgeQueue。默认情况下,Android中新创建的线程是没有开启消息循环的。(主线程除外)

    消息处理类(Handler)允许发送和处理Message和Rannable对象到其所在线程的MessageQueue中。(它主要有两个作用:1、将Message或Runnable应用post()方法或sendMessage()方法发送到MessageQueue中,在发送时可以指定延时时间、发送时间或者要携带的bundle数据。当MessageQueue循环到该Message时,调用相应的Handler对象的handlerMessage()方法对其进行处理。2、在子线程中与主线程进行通信,也就是在工作线程中与UI线程进行通信。)另外,在一个线程中只能有一个Looper和MessageQueue,但是可以有多个Handler,而且这些Handler可以共享一个Looper和MessageQueue。

    消息类(Message)被存放在MessageQueue中,一个MessageQueue中可以包含多个Message对象。每个Message对象可以通过Messhe.obtain()方法或者Handler.obtainMessage()方法获得。

    关系如下图:

    (图片来源于网络)

    下面我们做一个简单的实例。(从子线程获取的数据更新到UI)

    布局文件如下:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical" >
        <Button 
            android:id="@+id/btn"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:text="点击改变下方界面"/>
        <TextView 
            android:id="@+id/tv"
            android:layout_marginTop="50dp"
            android:layout_gravity="center"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="数据没改变前"/>
    
    </LinearLayout>

    java代码如下:

    public class MainActivity extends Activity {
        
        private TextView tv;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            Button btn=(Button) findViewById(R.id.btn);
            tv = (TextView) findViewById(R.id.tv);
            btn.setOnClickListener(new OnClickListener() {
                
                @Override
                public void onClick(View v) {
                    new Thread(new Runnable() {
                        
                        @Override
                        public void run() {
                            Message msg=new Message();
                            msg.obj="您已点击按钮,数据发生改变";//message的内容
                            msg.what=1;//指定message
                            handler.sendMessage(msg);//handler发送message
                            
                        }
                    }).start();
                    
                }
            });
        }
        
        private Handler handler=new Handler(){
            public void handleMessage(Message msg) {
                switch (msg.what) {
                case 1://获取到what属性为1的message
                    tv.setText((String)msg.obj);//将message的内容填充到TextView中
                    break;
    
                default:
                    break;
                }
            };
        };
        
    
    }

    运行程序,结果如下图:

    此外,关于异步消息处理机制。除了handler外,常用的还有AsyncTask。关于AsyncTask请看另一篇博文《Android AsyncTask 初探》。

    在子线程中更改UI,更多内容请参考我的另一篇博文《Android 在子线程中更新UI》。

    以上三个类关系密切并且方法较多,建议大家参考开发文档详细了解:

    Looper:http://developer.android.com/intl/zh-cn/reference/android/os/Looper.html

    Handler:http://developer.android.com/intl/zh-cn/reference/android/os/Handler.html

    message:http://developer.android.com/intl/zh-cn/reference/android/os/Message.html

    此外,还有对其三者进行源码分析的一些相关的博客:

    http://www.cnblogs.com/zhaoxiaowei/category/568256.html

    作者:af74776
    文章出处:http://www.cnblogs.com/scetopcsa/
    欢迎关注微信公众号:yilu_yiyou(一路一游),一个不仅仅是代码的世界!
    如果文中有什么错误,欢迎指出。以免更多的人被误导。
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    汇编语言
    离散数学:每条边的权重均不相同的带权图有唯一最小生成树
    android源码如何起步与阅读方法
    linux内核——会话、进程组、线程组
    ubuntu系统——增加磁盘空间
    Android系统源代码——所需工具
    android源码相关网站
    git——分布式版本控制系统
    linux内核——进程,轻量级进程,线程,线程组
    Android系统源代码学习步骤
  • 原文地址:https://www.cnblogs.com/scetopcsa/p/3661963.html
Copyright © 2011-2022 走看看