您的位置:首页 > 移动开发 > Android开发

Android-多线程

2015-12-09 13:47 344 查看
我每次写博客之前都忍不住想搞搞怪,这是一种什么逻辑与心态,侏罗纪与神心态,看来我很有闷骚作家的潜力啊!思泉涌动,如浩瀚江水,如涓涓细流,哈哈!不废话了。



默认情况下 : 所有在应用中的操作都运行在UI线程(主线程)上,因此之所以出现ANR问题,根因就在于主线程中被执行了耗时操作,阻塞了主线程,使其无法及时的绘制界面和相应用户的输入事件,系统可能杀死应用程序。

*来看看官方文档:*By default, all components of the same application run in the same process and thread (called the “main” thread)

原则:只有那些必须在主线程中执行才会生效的方法,才放在主线程中【界面绘制,UI更新,控件交互】,其他的一切操作都应该分逻辑地放在一个个单独的线程中执行。尤其是耗时的操作【文件,数据库,网络,计算】,同一时间运行的线程量也得控制,因为CPU频繁切换线程也是会损失性能的。

分开描述:

1) Activity. runOnUiThread(Runnable action),这里有一个概念就是:主线程的生命周期是贯串应用程序的始终的,所有在主线程上的操作,比如runnable 类型的action 【代表会被线程执行的命令】 会在Handler的协作下被投掷post到event queue 消息 队列(MessageQueue) ,Looper负责维护,不断的查询queue,一旦发现有action,立马托付给主线程执行。

函数原型截图如下:



2) Thread / Runnable :一个异步执行单元,有自己独立的堆栈,

1. 继承Thread 类,重载run()方法

new MyThread().start();

Starts executing the active part of the class’ code. This method is called when a thread is started that has been created with a class which implements Runnable.

2. new Thread(Runnable) .start()–>implements Runnable ->重载run()接口// providing a new Thread instance with a Runnable object during its creation.

new Thread(new MyRunnable()).start();

注意:

启动线程:start;

操作系统调度,设置优先级 : setPriority(int) ;

关系:Thread implements Runnable 继承关系

编程原则:每次执行操作,调用start( )都需创建一个新的Thread线程对象,避免直接使用thread类,使用其包装类,GC频繁回收闲置的线程对象,以及OS频繁创建线程对象都是影响性能的;

参考官方文档:A Thread is a concurrent unit of execution. It has its own call stack for methods being invoked, their arguments and local variables.

3) Handler : 更细粒度地控制线程上的操作,其细粒度表现在:安装操作的执行时间,对象复用,不会担心会被GC回收,对象会一直运行,这也带来一个维护问题,需要显式终止线程对象 。

public final boolean post(Runnable r)

{

return sendMessageDelayed(getPostMessage(r), 0);

}

// runnable被封装成了一个Message ,通过其变量callback 来保存

private static Message getPostMessage(Runnable r) {

Message m = Message.obtain();

m.callback = r;

return m;

}

Handler机制:handler实现线程间的通信,怎么理解?默认情况下刚刚建立的线程是不会关联一个消息循环【Threads by default do not have a message loop associated with them】,也就是无法关联looper【used to run a message loop for a thread.】只有主线程,才会关联一个looper,关联一个消息队列,这也就是主线程会一直运行的原因,线程之间的通信,这个时候就需要线程能够处理来自其他线程发送过来的消息事件,通过looper添加一个消息队列MessageQueue【仅仅是一个容器】message 也是由looper来打包的dispatch【holding the list of messages to be dispatched by a Looper】而把message发送添加到队列中也是由关联looper的handler完成的,因此当需要一个线程不断循环,一旦有新任务则执行,执行完继续等待下一个任务时,就使用Looper线程,普通线程变为循环工作的线程。

**1)**MessageQueue:通过Looper.myQueue()可以获得当前线程关联的MessageQueue

还有一个前提是当前线程必须要运行关联一个looper,不然将会抛出空指针异常【NullPointerException】

2) // sThreadLocal.get() will return null unless you’ve called prepare().

static final ThreadLocal sThreadLocal = new ThreadLocal();

在源代码中、其中threadlocal应该理解为ThreadLocalVariable,当使用ThreadLocal

维护Looper对象时,它会为每个使用该对象的线程提供一个独立的Looper副本,独立修改互不影响。

public static Looper myLooper() {

return sThreadLocal.get();

}

**3)**Looper : Looper对象的创建,会自动创建一个Message Queue!单独开线程需要你关联一个Looper对象,但是没有构造函数,提供了一个Looper .prepare( )

private Looper(boolean quitAllowed) {

mQueue = new MessageQueue(quitAllowed);

mThread = Thread.currentThread();

}

private static void prepare(boolean quitAllowed) {

//每一个线程对象只能保持一个looper对象,否则重复调用,会出现运行异常

if (sThreadLocal.get() != null) {

throw new RuntimeException(“Only one Looper may be created per thread”);

}

sThreadLocal.set(new Looper(quitAllowed));

}

同时需要调用Looper.loop(),并进入消息循环for (;;),队列运行可以接受消息了,发送消息msg.target.dispatchMessage(msg);

//以下就是一个关联Looper的线程的典型例子

* class LooperThread extends Thread {

* public Handler mHandler;

*

* public void run() {

* Looper.prepare();

*

* mHandler = new Handler() {

* public void handleMessage(Message msg) {

* // process incoming messages here

* }

* };

*

* Looper.loop();

* }

* }

Looper. quit()可以结束looper循环

Handler.getLooper().quit();

4)系统创建的主线程关联的looper和手动创建的looper区别在于一个参数quitAllowed 是否允许消息循环退出,主线程是不允许,而手动创建looper是默认退出的。

5)发送/处理/接受/移除消息:Handler

5.1.一旦线程关联的looper初始化完成,并开始运作进入消息循环状态,则其他的线程就可以发送消息了。Handler. sendMessage(Message msg) / Handler. post(Runnable r),最终这些方法都会调用sendMessageAtTime,说白了就是把消息压进栈,所以必须保证MessageQueue的存在,所以非主线程要关联looper,否则会报运行时的错误

public boolean sendMessageAtTime(Message msg, long uptimeMillis) {

MessageQueue queue = mQueue;

if (queue == null) {

RuntimeException e = new RuntimeException(

this + ” sendMessageAtTime() called with no mQueue”);

Log.w(“Looper”, e.getMessage(), e);

return false;

}

return enqueueMessage(queue, msg, uptimeMillis);

}

**5.2.**Handler. handleMessage() / Handler. dispatchMessage() 后者是前者的封装

//其实就是一个优先级的执行问题

public void dispatchMessage(Message msg) {

if (msg.callback != null) {

handleCallback(msg);

} else {

if (mCallback != null) {

if (mCallback.handleMessage(msg)) {

return;

}

}

handleMessage(msg);

}

}

5.3 . 当出现public class HandlerDemo extends Activity implements Handler.Callback

public interface Callback {

public boolean handleMessage(Message msg);

}

5.4. Handler只处理自己发出的消息,实现异步处理,异步 表现在,通知消息循环

要执行一个任务(Handler1.sendMessage),并在loop到自己的时候执行该任务(Handler1.handleMessage),也就是说一个线程可以有多了handler,但是只能有一个Looper !

5.5. 构造handler对象

private Handler handler = new Handler(){

@Override

public void handleMessage(Message msg) {

super.handleMessage(msg);

switch (msg.what) {

或者public Handler(Looper looper, this)

**6)**Message:存在构造函数,但只是一个空壳的声明而言,并推荐两种方式来获取message!各种重载的Message. Obtain( ) 以及Handler.obtainMessage(),本质上后者是对前者的封装。

public final Message obtainMessage()

{

return Message.obtain(this);

}

在缓存池中获取新消息实例,避免每调用一次就构造不同的对象,从而实现对象复用

几个参数:

Message .what : switch区分不同消息的标志位

Message.target : handler对象,更加说明Message有不同的发送主体Handler,能找到处理它的handler。

Message .callback : Runnable

携带数据:基本INT类型/bundle类型/obj类型arg1/ arg2/data/ obj

7) HandlerThread: extends Thread 关联looper的帮助类,可以利用它来创建循环线程【Handy class for starting a new thread that has a looper. The looper can then be

used to create handler classes. Note that start() must still be called.】自带Looper使他可以通过消息来多次重复使用当前线程,而不用像原来那样创建多个匿名线程,

**8)**AsyncTask

参考文档:

/article/5087381.html

/article/6981722.html

/article/1653413.html

/article/2802342.html

/article/1369222.html

/article/11172384.html

截图如下:







未完待续。。。。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: