Android中的handler

首先先看一下android中的线程基本使用方式:

1.      继Thread方式:复写run()方法

2.      实现Runnable方式 接口:传给Thread : new Thread(newplaybackRunnable()).start();

以上两种方法殊归同途,都是在新线程中调用用户实现run方法(方式上还是有区别的,需要可以查看资料,在我的搜藏中也有)。

 

下面我们来关注下android中的hanlder机制。handler主要的用途就是提供一个消息机制,可以方便地在一个消息循环线程中实现消息的处理,无论是在本线程还是在其他线程。不过,首先需要保证线程是有消息循环的。android中的UI线程都是由消息循环的。

 

来看一下handler机制三个相关的类:Handler, Message, Looper

 

 

首先来看下Looper类:它的构造函数是私有的,可见不能在外部创建。唯一创建的地方:

public static void prepare() {

       prepare(true);

    }

 

private static void prepare(boolean quitAllowed) {

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

thrownewRuntimeException("Only one Looper may be created per thread");

        }

sThreadLocal.set(new Looper(quitAllowed));

    }

 

此处创建了,就把它设置到ThreadLocal中。

再来看看Looper构造函数都干了什么:

    private Looper(boolean quitAllowed) {

        mQueue = new MessageQueue(quitAllowed);

        mRun = true;

        mThread = Thread.currentThread();

    }


 它创建了一个消息队列,又结合上面的prepare函数,可见Looper实例在一个Thread中使唯一的,进而消息队列也是唯一的。

 

然后是loop的主循环体:它不停地从消息队列中取出消息来处理。

  public static void loop() {

        final Looper me = myLooper();
//note how find the Looper
         if (me == null) {

            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");

        }

        final MessageQueue queue = me.mQueue;

 

        // Make sure the identity of this thread is that of the local process,

        // and keep track of what that identity token actually is.

        Binder.clearCallingIdentity();

        final long ident = Binder.clearCallingIdentity();

 

        for (;;) {

            Message msg = queue.next(); // might block

            if (msg == null) {

                // No message indicates that the message queue is quitting.

                return;

            }

 
            // This must be in a local variable, in case a UI event sets the logger

            Printer logging = me.mLogging;

            if (logging != null) {

                logging.println(">>>>> Dispatching to " + msg.target + " " +

                        msg.callback + ": " + msg.what);

            }

 

            msg.target.dispatchMessage(msg);

 

            if (logging != null) {

                logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);

            }

 

            // Make sure that during the course of dispatching the

            // identity of the thread wasn't corrupted.

            final long newIdent = Binder.clearCallingIdentity();
            if (ident != newIdent) {

                Log.wtf(TAG, "Thread identity changed from 0x"

                        + Long.toHexString(ident) + " to 0x"

                        + Long.toHexString(newIdent) + " while dispatching to "

                        + msg.target.getClass().getName() + " "

                        + msg.callback + " what=" + msg.what);

            }

 

            msg.recycle();

        }

    }

 

 这里注意消息队列的获得,来看mylooper函数:

    public static Looper myLooper() {

        return sThreadLocal.get();

}

 

可见,要想消息循环,之前必须要构造出looper实例,并放入到ThreadLocal中。这里,looper已经处理好了,是要调用上面的prepare函数,切忌!

 

然后就是消息如何处理了,可以看到,最主要的就是msg.target.dispatchMessage(msg);这句话,这句就会使你的消息调用handlerdispatchMessage(msg)函数来处理消息了:

    public void dispatchMessage(Message msg) {

        if (msg.callback != null) {

            handleCallback(msg);

        } else {

            if (mCallback != null) {

                if (mCallback.handleMessage(msg)) {

                    return;

                }

            }

            handleMessage(msg);

        }

    }

 

从上就看到了处理消息的三种方式:

1.  调用消息的callback

2.  调用Hanldercallback

3.  调用handlerhandleMessage

 

再来看看Handler

Handler总体来说有两种构造方式:

1.      不带looper的构造方式:

public Handler(Callback callback, boolean async) {

        if (FIND_POTENTIAL_LEAKS) {

            final Class<? extends Handler> klass = getClass();

            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&

                    (klass.getModifiers() & Modifier.STATIC) == 0) {

                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +

                    klass.getCanonicalName());

            }

        }

 

        mLooper = Looper.myLooper();

        if (mLooper == null) {

            throw new RuntimeException(

                "Can't create handler inside thread that has not called Looper.prepare()");

        }

        mQueue = mLooper.mQueue;

        mCallback = callback;

        mAsynchronous = async;

}

 
}

 

2.      带looper的构造方式:

  public Handler(Looper looper, Callback callback, boolean async) {

        mLooper = looper;

        mQueue = looper.mQueue;

        mCallback = callback;

        mAsynchronous = async;

}


不带looper的构造方式将获得本线程的Queue looper的构造方式,获得的是looperQueue.这为之后handler跑在哪个线程上打上了伏笔。

 

最后看看Message

Message的构造大体分为三种:

1.      不带handler和callback的构造:

       public static Message obtain() {

        synchronized (sPoolSync) {

            if (sPool != null) {

                Message m = sPool;

                sPool = m.next;

                m.next = null;

                sPoolSize--;

                return m;

            }

        }

        return new Message();

}

此时targetnull

 

2.      带参数Handler的构造:

      public static Message obtain(Handler h) {

        Message m = obtain();

        m.target = h;

 

        return m;

    }


此时target为传入的handler

 

3.      带handler和callback的构造:

         public static Message obtain(Handler h, Runnable callback) {

        Message m = obtain();

        m.target = h;

        m.callback = callback;

 

        return m;

    }

 

 


有了以上这些基础,我们再来看看消息handler机制是如何使用的:

有几种方式:

1. 直接获取message,然后传给handler处理:

Msg = Message.obtain();

Handler.sendMessage(msg);

这里可以跟踪Handler.sendMessage(msg),最后走到:

    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);

    }


可以看到,以上将msg入队到自己的queue中,最后就到了queue的线程中去处理了:

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {

        msg.target = this;

        if (mAsynchronous) {

            msg.setAsynchronous(true);

        }

        return queue.enqueueMessage(msg, uptimeMillis);

}

注意这里msg.target = this; 所以无论消息有没有设置target,只要调用了HandlerSendMessage, 它的处理就绑定到了handler上了。

Ok ! 这种方式是跑在handler的线程中的,至于handler值跑在哪个线程中,看看上面handler的两种构造函数就知道了。

 

2. 通过hanlder来获得Message:

class Handler{

public final Message obtainMessage()

{

     return Message.obtain(this);

}
}

可见最后调用的还是消息的obtain(Hanlder)函数。还是在handlerhandleMessage中处理。

 

3. 通过handler的post方式:

  Handler. post(Runnable r):

       {

       return  sendMessageDelayed(getPostMessage(r), 0);

}
    private static Message getPostMessage(Runnable r) {

        Message m = Message.obtain();

        m.callback = r;

        return m;

    }


最后还是在handler的线程中,处理的是runnable接口的实现。

 

4. 通过message的SendToTarget的方式:

Message.sendToTarget():

       public void sendToTarget() {

        target.sendMessage(this);

}


可见 这个是在与message关联的handler中处理的。注:处理之前message一定要有与之关联的target(Hanlder),也就是message的获得一定通过有handler的方式获得,或者之后要手动设置下handler,不然会因为找不到target而出错。

 

好了,以上4种大概就是我们一般使用handler消息机制的一般方式。

 

 

总结:

1. Looper不用用户操心,但是构造消息循环线程的话,一定要Looper.prepare()一下,以用来创建本地消息队列。

2. handler的两种构造方式决定了handler是在哪个线程上被处理的。 这里要注意:如果hanlder在本地线程上处理,则本地线程一定要有handler机制,也就是消息循环系统。不然handler会因为找不到Looper而出错!

3. Message的获取方式决定了消息的处理是在哪个函数中进行的(参考上面dispatchmessage处理)。 为消息的处理提供了多种方便的方式(参考Message的构造方式一节)。

 

 

最后来看下HandlerThread:

    public void run() {

        mTid = Process.myTid();

        Looper.prepare();

        synchronized (this) {

            mLooper = Looper.myLooper();

            notifyAll();

        }

        Process.setThreadPriority(mPriority);

        onLooperPrepared();

        Looper.loop();

        mTid = -1;

    }


这个类为我们提供了一个消息循环线程的所有工作,我们只要在这个线程上处理消息就可以了。

调用此类的getLooper可以得到looper,然后用它来构造hanlder就可以发送消息到这个线程来处理了。

 

 

 

 

 

 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
疫情居家办公系统管理系统按照操作主体分为管理员和用户。管理员的功能包括办公设备管理、部门信息管理、字典管理、公告信息管理、请假信息管理、签到信息管理、留言管理、外出报备管理、薪资管理、用户管理、公司资料管理、管理员管理。用户的功能等。该系统采用了MySQL数据库,Java语言,Spring Boot框架等技术进行编程实现。 疫情居家办公系统管理系统可以提高疫情居家办公系统信息管理问题的解决效率,优化疫情居家办公系统信息处理流程,保证疫情居家办公系统信息数据的安全,它是一个非常可靠,非常安全的应用程序。 管理员权限操作的功能包括管理公告,管理疫情居家办公系统信息,包括外出报备管理,培训管理,签到管理,薪资管理等,可以管理公告。 外出报备管理界面,管理员在外出报备管理界面可以对界面显示,可以对外出报备信息的外出报备状态进行查看,可以添加新的外出报备信息等。签到管理界面,管理员在签到管理界面查看签到种类信息,签到描述信息,新增签到信息等。公告管理界面,管理员在公告管理界面新增公告,可以删除公告。公告类型管理界面,管理员在公告类型管理界面查看公告的工作状态,可以对公告的数据进行导出,可以添加新公告的信息,可以编辑公告信息,删除公告信息
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值