博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
计时器---------------多线程案例
阅读量:6060 次
发布时间:2019-06-20

本文共 4078 字,大约阅读时间需要 13 分钟。

hot3.png

Android中的线程

  在Android平台中多线程应用很广泛,在UI更新、游戏开发和耗时处理(网络通信等)等方面都需要多线程。Android线程涉及的技术有:Handler;Message;MessageQueue;Looper;HandlerThread。

  Android线程应用中的问题与分析

  为了介绍这些概念,我们把计时器的案例移植到Android系统上,按照在Frame方式修改之后的代码清单8-4,完整代码请参考chapter8_3工程中 chapter8_3代码部分。

  【代码清单8-4】

public class chapter8_3 extends Activity {
    
private 
String TAG = 
"
chapter8_3
";
    
private Button btnEnd;
    
private TextView labelTimer;
    
private Thread clockThread;
    
private 
boolean isRunning = 
true;
    
private 
int 
timer = 
0;
    
@Override
    
public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        btnEnd = (Button) findViewById(R.id.btnEnd);
        btnEnd.setOnClickListener(
new OnClickListener() {
            @Override
            
public void onClick(View v) {
                isRunning = 
false;
            }
        });
        labelTimer = (TextView) findViewById(R.id.labelTimer);
        /* 线程体是Clock对象本身,线程名字为
"
Clock
" */
        clockThread = 
new Thread(
new Runnable() {
            @Override
            
public void run() {
                
while (isRunning) {
                    try {
                        Thread.currentThread().sleep(
1000);
                        
timer++;
                        labelTimer.setText(
"
逝去了 
" + 
timer + 
"
 秒
");
                        
Log.d(TAG, 
"
lost  time 
" + 
timer);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        clockThread.start(); /* 启动线程 */
    }
    }

  程序打包运行结果出现了异常,如图8-8所示。

Android线程应用中的问题与分析

▲图8-8 运行结果异常图

  我们打开LogCat窗口,出错日志信息如图8-9所示。

Android线程应用中的问题与分析

▲图8-9 出错日志

  系统抛出的异常信息是“Only the original thread that created a view hierarchy can touch its views”,在Android中更新UI处理必须由创建它的线程更新,而不能在其他线程中更新。上面的错误原因就在于此。

  现在分析一下上面的案例,在上面的程序中有两个线程:一个主线程和一个子线程,它们的职责如图8-10所示。

  由于labelTimer是一个UI控件,它是在主线程中创建的,但是它却在子线程中被更新了,更新操作在clockThread线程的run()方法中实现,代码如下:

Android线程应用中的问题与分析

▲图8-10 线程职责

/* 线程体是Clock对象本身,线程名字为
"
Clock
" */
clockThread = 
new Thread(
new Runnable() {
    @Override
    
public void run() {
        
while (isRunning) {
            try {
                Thread.currentThread().sleep(
1000);
                
timer++;
                labelTimer.setText(
"
逝去了 
" + 
timer + 
"
 秒
");
                
Log.d(TAG, 
"
lost  time 
" + 
timer);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
});

  这样的处理违背了Android多线程编程规则,系统会抛出异常“Only the original thread that created a view hierarchy can touch its views”。

  要解决这个问题,就要明确主线程和子线程的职责。主线程的职责是创建、显示和更新UI控件、处理UI事件、启动子线程、停止子线程;子线程的职责是计算逝去的时间和向主线程发出更新UI消息,而不是直接更新UI。它们的职责如图8-11所示。

Android线程应用中的问题与分析

▲图8-11 线程职责

  主线程的职责是显示UI控件、处理UI事件、启动子线程、停止子线程和更新UI,子线程的职责是计算逝去的时间和向主线程发出更新UI消息。但是新的问题又出现了:子线程和主线程如何发送消息、如何通信呢?

  在Android中,线程有两个对象—消息(Message)和消息队列(MessageQueue)可以实现线程间的通信。下面再看看修改之后的代码清单8-5,完整代码请参考chapter8_4工程中chapter8_4代码部分。

  【代码清单8-5】

public class chapter8_4 extends Activity {
    
private 
String TAG = 
"
chapter8_3
";
    
private Button btnEnd;
    
private TextView labelTimer;
    
private Thread clockThread;
    
private 
boolean isRunning = 
true;
    
private Handler handler;
    @Override
    
public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        btnEnd = (Button) findViewById(R.id.btnEnd);
        btnEnd.setOnClickListener(
new OnClickListener() {
            @Override
            
public void onClick(View v) {
                isRunning = 
false;
            }
        });
        handler = 
new Handler() {
            @Override
            
public void handleMessage(Message msg) {
                switch (msg.what) {
                
case 
0:
                    labelTimer.setText(
"
逝去了 
" + msg.obj + 
"
 秒
");
                }
            }
        };
        labelTimer = (TextView) findViewById(R.id.labelTimer);
        /* 线程体是Clock对象本身,线程名字为
"
Clock
" */
        clockThread = 
new Thread(
new Runnable() {
            @Override
            
public void run() {
                
int 
timer = 
0;
                
while (isRunning) {
                    try {
                        Thread.currentThread().sleep(
1000);
                        
timer++;
                        /* labelTimer.setText(
"
逝去了 
" + 
timer + 
"
 秒
"); */
                        Message msg = 
new Message();
                        msg.obj = 
timer;
                        msg.what = 
0;
                        handler.sendMessage(msg);
                        
Log.d(TAG, 
"
lost  time 
" + 
timer);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        clockThread.start(); /* 启动线程 */
    }

  有的时候为了将Android代码变得更加紧凑,把线程的创建和启动编写在一条语句中,如下面chapter8_5的代码片段。代码清单8-6所示,完整代码请参考chapter8_5工程中 chapter8_5代码部分。

  【代码清单8-6】

new Thread() {
        @Override
        
public void run() {
            
int 
timer = 
0;
            
while (isRunning) {
                ry {
                    Thread.currentThread().sleep(
1000);
                    
timer++;
                    / labelTimer.setText(
"
逝去了 
" + 
timer + 
"
 秒
");
                    Message msg = 
new Message();
                    msg.obj = 
timer;
                    msg.what = 
0;
                    handler.sendMessage(msg);
                    
Log.d(TAG, 
"
lost  time 
" + 
timer);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }.start();

转载于:https://my.oschina.net/xubohui/blog/85530

你可能感兴趣的文章
centos6.8 安装jdk
查看>>
Retrofit官方文档翻译
查看>>
Effective C++ ------- virtual
查看>>
c/c++再学习:C++中public、protect、private的访问权限控制
查看>>
jQuery操纵一些元素的隐显
查看>>
MySQL , MHA , Haproxy 配置
查看>>
JQuery固定表头插件fixedtableheader源码注释
查看>>
JavaScript碎片
查看>>
crm 03--->销售页面及逻辑
查看>>
Win7下设置VMware9虚拟机上网功能(NAT方式)
查看>>
jQuery之ajaxForm提交表单
查看>>
写一个SingleTon,(饿最终、懒同步)
查看>>
嵌入式BSP工程师
查看>>
Android开发指南(38) —— Status Bar Notifications
查看>>
【iOS】在Swift中使用JSONModel
查看>>
使用SQL Server发送邮件时遇到的诡异事件
查看>>
七、Json格式的对象都可以通过遍历来获得里面的value值
查看>>
单页面使用多个编辑器
查看>>
NOPcommerce研究
查看>>
JasperReport学习札记6-JRXML的标签
查看>>