Android—开发自学历程(3)-多线程

我们做的是Android的应用开发,凡是应用都会存在线程,存在线程就会需要用到多线程的机制;Android应用许多时候也要用到多线程,如UI更新、耗时的操作、网络编程等等。Android的多线程算是较为复杂的一种。首先我们知道Android基本是使用java来写的,所以Android的多线程应该也跟java差不多。首先我们知道java编写多线程有两种方式。
一、是继续Thread类
二、是实现Runable接口
想必学过java的人都不陌生,那按理说Android也应该如此,但是实际却还是有差别的;我们先用java的方式写下:

package com.maple.baiduweather;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;

public class MainActivity extends Activity {
    private static final String TAG = "mainActivity";

    private TextView mTimeText = null;
    private int timer = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mTimeText = (TextView) findViewById(R.id.text_view);

        new Thread() {
            public void run() {
                try {
                    Thread.sleep(1000);
                    timer++; 
                    mTimeText.setText("时间:" + timer + "s");
                    Log.d(TAG, "time:"+timer);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            };
        }.start();
    }
}

看起来好像很完美对吧。但是运行时抛出如下异常
这里写图片描述
报异常:android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
【只有原始创建这个视图层次(view hierachy)的线程才能修改它的视图(view)】
这是异常解释,意思就是说只有主线程可以更新UI。这其实是Android的一种保护机制,因为子线程更新UI是不安全的,为什么这样呢?原因很简单,子线程有可能有很多个,如果它们同时更新一个UI控件的话,就有可能发生冲突,所以Android在这里限定了只有主线程有权利更新UI,你子线程要跟新,来告诉主线程,让主线程来操作。
那子线程如何通知主线程更新UI呢?这里就要使用Handle类了。

Handle

Handle是直接继承与java.lang.Object的。
一个Handle允许发送和处理Message或者Runnable对象,并且会关联到主线程MessageQueue中,每个Handler具有一个单独的线程,并且关联到一个消息队列的线程,就是说一个Handler有一个固有的消息队列。当实例化一个Handler 的时候,它就承载在一个线程和消息队列的线程,这个Handler可以把Message或Runnable压入到消息队列,并且从消息队列中取出 Message或Runnable,进而操作它们。
Handle的两个作用:①在工作线程中发送消息②在UI中处理和获取信息;
从上面我们可以知道Handle可以把一个Message对象或者Runnable对象压进线程的消息队列,然后主线程中获取Message对象或者Runnable对象。Handle压入消息队列有两个方法:Post和sendMessage;

  • Post:Post允许把一个Runnable对象压入到消息队列中。它的方法有:post(Runnable)、postAtTime(Runnable,long)、postDelayed(Runnable,long)。
  • sendMessage:sendMessage允许把一个包含消息数据的Message对象压入到消息队列中。它的方法有:sendEmptyMessage(int)、sendMessage(Message)、sendMessageAtTime(Message,long)、sendMessageDelayed(Message,long)。

具体我们看下方法,首先我们使用post方法:

        new Thread(new Runnable(){          
            @Override
            public void run() {
                mHandle.post(new Runnable() {                   
                    @Override
                    public void run() {
                            try {
                                Thread.sleep(1000);
                                timer++; 
                                mTimeText.setText("时间:" + timer + "s");
                                Log.d(TAG, "time:"+timer);
                            } catch (InterruptedException e) {
                                // TODO Auto-generated catch block
                                e.printStackTrace();
                            }
                        }
                });
            }
        }).start();

但是post方式有个局限性,那就是它的Runnable对象的run()方法的代码,都执行在UI线程上,一旦遇到那种无法执行在UI线程上的操作,就无法使用post方法了。
下面看下Message方法

    private Handler mHandle = new Handler() {
        // 在Handler中获取消息,重写handleMessage()方法
        @Override
        public void handleMessage(android.os.Message msg) {
            switch (msg.what) {
            case 1:
                timer++; 
                mTimeText.setText("时间:" + timer + "s");
                Log.d(TAG, "time:"+timer);
                break;
            default:
                break;
            }
        };
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mTimeText = (TextView) findViewById(R.id.text_view);
        // 新启动一个子线程
        new Thread(new Runnable(){          
            @Override
            public void run() {
                    try {
                            Thread.sleep(1000);
                            Message msg = new Message();
                            msg.what = 1;
                            mHandle.sendMessage(msg);
                            Log.d(TAG, "time:"+timer);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
            }
        }).start();
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

「已注销」

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值