当前位置: 首页 > news >正文

用什么做网站原型图网站建设通常用到哪些编程

用什么做网站原型图,网站建设通常用到哪些编程,货代新手怎么找客户,wordpress 插件激活前言 想必大家都知道Android系统有自己的一套消息分发机制#xff0c;#xff0c;从App启动那一刻起#xff0c;App就创建了主线程的消息分发实例#xff1a;Looper.sMainLooper,并开始无限循环#xff0c;也就是App的心脏#xff0c;一直跳动#xff0c;负责协调分配来…前言 想必大家都知道Android系统有自己的一套消息分发机制从App启动那一刻起App就创建了主线程的消息分发实例Looper.sMainLooper,并开始无限循环也就是App的心脏一直跳动负责协调分配来自各方的事件让App不断响应用户操作,如果主线程出现了异常也就是心脏跳动异常停止那么App的生命随之终止也就是常见的‘进程已停止运行’。那么你有没有想过既然他在一直无限循环为什么没有卡死呢为什么能看到“应用无响应”?怎么保证界面刷新不受其他事件影响怎么做到有条不理的处理每一条消息等等这些问题呢作为一名Android开发者我想我们有必要对其结构进行简单了解。 思路整理 基于消息分发机制我们可以从以下几个方面由深到浅去解惑 MessageMessageQueue 的核心逻辑Looper的核心逻辑Handler机制 在阅读前你可能需要对数据结构单链表有一定的了解。 源码基于 Android API 33 Message 消息对象部分源码 public final class Message implements Parcelable {///*** The targeted delivery time of this message. The time-base is* {link SystemClock#uptimeMillis}.* hide Only for use within the tests.*/UnsupportedAppUsageVisibleForTesting(visibility VisibleForTesting.Visibility.PACKAGE)public long when;//UnsupportedAppUsage/*package*/ Handler target;//是否为异步消息/*** Returns true if the message is asynchronous, meaning that it is not* subject to {link Looper} synchronization barriers.** return True if the message is asynchronous.** see #setAsynchronous(boolean)*/public boolean isAsynchronous() {return (flags FLAG_ASYNCHRONOUS) ! 0;} } 关于此类需要知道的是我们外部创建的target一般不为空为空一般是系统内部创建的消息比如执行View的invalidate()就是发送了target为空的异步消息具体看 消息队列中的分发逻辑。 MessageQueue 消息队列 顾名思义是一个存放消息Message的队列主要负责管理消息的插入和取出。每个消息都有对应的创建时间插入队列中的消息会按时间排序当调用next时会从队列中取出一条符合条件的Message如果没有则next函数会进入休眠状态直到被唤醒。为了方便理解下面对该类的核心方法核心变量分开分析。 大致结构如下 //源码位于 android.os.MessageQueue UnsupportedAppUsage SuppressWarnings(unused) private long mPtr; // used by native code UnsupportedAppUsage Message mMessages;boolean enqueueMessage(Message msg, long when){} Message next() {} UnsupportedAppUsage TestApi public int postSyncBarrier(){}UnsupportedAppUsage TestApi public void removeSyncBarrier(int token) {}mPtr 看起来就是一个指针源码中注释为 used by native code也就是说是在Native层用的代码我们只需知道他是一道闸堵塞next方法用的。 mMessages 队列的头部消息。 postSyncBarrier removeSyncBarrier 这两个方法是发送和移除同步屏障消息我们可以把它想象成为一道栅栏能拦截所有同步消息,只允许异步信息通过。当向队列中插入该消息后消息分发会主动跳过所有同步消息即使队列中没有异步消息直至屏障被移除。 不难发现调用postSyncBarrier时会返回一个int类型也就是屏障的标识自然移除屏障的时候需要传入这个标识。 至于为什么加入这个机制大致因为加入队列中有很多消息此时用户点击了一下界面如果没有这个机制那么响应用户点击的操作需要等待其他事件被分发完后才轮到容易让用户觉得不流畅所以系统为了UI相关的消息要优先被分发在队列中插入同步屏障信号之后响应点击的消息会被优先处理处理完成后再把信号移除继续执行其他分发。 这个机制如果处理不好屏障没有正常移除就会出现进程假死的问题这也就是官方为何把此方法标记成UnsupportedAppUsage不给开发者调用。 *那么这样就可以避免不会出问题吗*不可能这只是减少了问题的出现概率还是有机会出现的屏障信号是系统在更新UI时发送的如果我们操作不当频繁在子线程操作UI可能某一瞬间发送了超过两个屏障信号但是只记录到最后一个token更新完成后自然只移除了最后添加的屏障结果就是之前插入的一直挂在队列中堵塞主线程所有同步消息也就引发了同步屏障泄露 的问题App就直接出现了明明有些控件明明还在刷新但是怎么点都没反应。 这也是为什么官方只允许我们只能在主线程执行更新UI操作原因之一。 enqueueMessage 分发消息把用户发的Message插入到队列中。关键源码 boolean enqueueMessage(Message msg, long when){//target为空为屏障消息,屏障信息只能由系统代码发送用户端发送的消息target不可能是空//这里就解析了为什么用户不能发送没有target的消息if (msg.target null) {// throw new IllegalArgumentException(Message must have a target.);}//......省略synchronized (this) {//......省略//1.把当前的对头赋值给pMessage p mMessages;boolean needWake;//是否需要唤醒next函数if (p null || when 0 || when p.when) { //2.A 如果对头为空队列没有任何消息或者when为0只有刚开机才会存在或者msg的时间比队头的时间早//把待分发消息插到对头// New head, wake up the event queue if blocked. msg.next p; //把当前消息的next指向p 尽管p为空mMessages msg; //把当前消息放到对头needWake mBlocked;//} else { //2.B 队列中已有消息这时需要把当前消息按时间顺序插到队列中// Inserted within the middle of the queue. Usually we dont have to wake // up the event queue unless there is a barrier at the head of the queue // and the message is the earliest asynchronous message in the queue. //3、是否需要唤醒正在堵塞、队头是屏障信号、当前消息是异步消息 needWake mBlocked p.target null msg.isAsynchronous(); Message prev; for (;;) { //4、开始循环队列和队列中消息when做比较找出当前消息的when值在队列中最适合的位置prev p; //此时p的角色为当前遍历的消息先赋值给上一条消息保证每次循环能拿到上一条消息和下一条消息方便插入p p.next; //取下一条消息赋值到pif (p null || when p.when) { //5、如果下一条消息是空说明已到达队尾或者当前消息的时刻比下一条消息的时刻小说明此时的位置最适合结束循环break; }//队头符合步骤3处条件说明有同步屏障信号并且当前p是异步消息根据步骤5能走到这里说消息分发时机还没到所以不需要唤醒nextif (needWake p.isAsynchronous()) { needWake false; } } //把当前消息入队插入到上一条消息和p之间msg.next p; // invariant: p prev.next prev.next msg;}// We can assume mPtr ! 0 because mQuitting is false.if (needWake) { //唤醒next函数取 消息 分发nativeWake(mPtr);}}return true; } next 取消息 从队列中取出一条可用消息when时机合适如果有就返回没有则堵塞直到mPtr被唤醒。 UnsupportedAppUsageMessage next() {//......省略//1、下一次唤醒时间int nextPollTimeoutMillis 0;for (;;) {//2、开始死循环取消息if (nextPollTimeoutMillis ! 0) {Binder.flushPendingCommands();}//3、堵塞时长为nextPollTimeoutMillis或者主动调用唤醒函数nativeWakenativePollOnce(ptr, nextPollTimeoutMillis);//被唤醒后开始取消息synchronized (this) {//同步锁保证线程安全// Try to retrieve the next message. Return if found.//记下当前系统时间后面判断消息是否达到时间条件final long now SystemClock.uptimeMillis();Message prevMsg null;Message msg mMessages;if (msg ! null msg.target null) {//4、关键点target为空说明当前队头消息为屏障信号需要优先处理离信号最近的异步消息// Stalled by a barrier. Find the next asynchronous message in the queue.do {//一直在队列中寻找离信号最近的异步消息直到没找到或者到达队尾prevMsg msg;msg msg.next;//如果一直找到队尾msg.next是空结束循环} while (msg ! null !msg.isAsynchronous());}if (msg ! null) {//5、此时如果有屏障信号的话步骤4肯定走了msg不为空肯定是异步消息否则msg必为空//检查该消息是否以达到分发时机if (now msg.when) {//当前时间还没达到消息的时机计算还差多久赋值给nextPollTimeoutMillis进入下一次堵塞直到达到时间nextPollTimeoutMillis再取该消息// Next message is not ready. Set a timeout to wake up when it is ready.nextPollTimeoutMillis (int) Math.min(msg.when - now, Integer.MAX_VALUE);} else {//已达到取消息时机// Got a message.mBlocked false;//把消息出队if (prevMsg ! null) {//说明此消息在队列里面同步屏障会优先执行里面的异步消息要把消息出队把该消息的上一条消息的next直接指向该消息的下一条消息prevMsg.next msg.next;} else {//说明此消息是队头直接把当前消息的next放到队头mMessages msg.next;}//删除出队消息的next指向msg.next null;if (DEBUG) Log.v(TAG, Returning message: msg);//标注消息正在使用msg.markInUse();//把该消息返回return msg;}} else {//6、没有符合条件消息继续下一次循环取符合条件的消息//如果屏障信号没有被移除又没有异步消息进入队列那么next函数将陷入死循环循环线路 3--》4--》6//导致APP所有同步消息无法被处理表现为软件部分界面卡死如文本正常刷新点击事件无法响应并且不会引发ANR// No more messages.nextPollTimeoutMillis -1;}// Process the quit message now that all pending messages have been handled.if (mQuitting) {dispose();return null;}// If first time idle, then get the number of idlers to run.// Idle handles only run if the queue is empty or if the first message// in the queue (possibly a barrier) is due to be handled in the future.if (pendingIdleHandlerCount 0 (mMessages null || now mMessages.when)) {pendingIdleHandlerCount mIdleHandlers.size();}if (pendingIdleHandlerCount 0) {// No idle handlers to run. Loop and wait some more.mBlocked true;continue;}if (mPendingIdleHandlers null) {mPendingIdleHandlers new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];}mPendingIdleHandlers mIdleHandlers.toArray(mPendingIdleHandlers);}// Run the idle handlers.// We only ever reach this code block during the first iteration.for (int i 0; i pendingIdleHandlerCount; i) {final IdleHandler idler mPendingIdleHandlers[i];mPendingIdleHandlers[i] null; // release the reference to the handlerboolean keep false;try {keep idler.queueIdle();} catch (Throwable t) {Log.wtf(TAG, IdleHandler threw exception, t);}if (!keep) {synchronized (this) {mIdleHandlers.remove(idler);}}}// Reset the idle handler count to 0 so we do not run them again.pendingIdleHandlerCount 0;// While calling an idle handler, a new message could have been delivered// so go back and look again for a pending message without waiting.nextPollTimeoutMillis 0;}} Looper 一个无限循环的类他内部持有消息队列MessageQueue的引用当Looper.loop()后将会一直调用MessageQueue.next函数获取消息next在没有消息的时候又会堵塞让出CPU资源这就是为什么死循环却没有占满CPU的原因。关键源码 public final class Looper {public static void prepare() {prepare(true);}public static Looper getMainLooper() {synchronized (Looper.class) {return sMainLooper;}}/*** 循环一次的逻辑* Poll and deliver single message, return true if the outer loop should continue.*/SuppressWarnings(AndroidFrameworkBinderIdentity)private static boolean loopOnce(final Looper me,final long ident, final int thresholdOverride) {//从队列中取一条消息Message msg me.mQueue.next(); // might blockif (msg null) {//由于next没消息会堵塞所以没消息的时候这里不会执行除非强制退出// No message indicates that the message queue is quitting.return false;}try {//开始分发取到的消息msg.target.dispatchMessage(msg);if (observer ! null) {observer.messageDispatched(token, msg);}dispatchEnd needEndTime ? SystemClock.uptimeMillis() : 0;} catch (Exception exception) {if (observer ! null) {observer.dispatchingThrewException(token, msg, exception);}throw exception;} finally {ThreadLocalWorkSource.restore(origWorkSource);if (traceTag ! 0) {Trace.traceEnd(traceTag);}}//省略// Make sure that during the course of dispatching the// identity of the thread wasnt 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.recycleUnchecked();return true;}/*** 开始无限循环* Run the message queue in this thread. Be sure to call* {link #quit()} to end the loop.*/SuppressWarnings(AndroidFrameworkBinderIdentity)public static void loop() {final Looper me myLooper();if (me null) {throw new RuntimeException(No Looper; Looper.prepare() wasnt called on this thread.);}if (me.mInLoop) {Slog.w(TAG, Loop again would have the queued messages be executed before this one completed.);}me.mInLoop true;// 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();// Allow overriding a threshold with a system prop. e.g.// adb shell setprop log.looper.1000.main.slow 1 stop startfinal int thresholdOverride SystemProperties.getInt(log.looper. Process.myUid() . Thread.currentThread().getName() .slow, 0);me.mSlowDeliveryDetected false;for (;;) {//无限循环核心if (!loopOnce(me, ident, thresholdOverride)) {return;}}} } Handler 通过Handler我们可以把消息发送到对应的消息队列中是用户代码操作消息队列的入口。关键源码 public class Handler {/*** Use the provided {link Looper} instead of the default one.** param looper The looper, must not be null.*/public Handler(NonNull Looper looper) {this(looper, null, false);}/*** Use the provided {link Looper} instead of the default one and take a callback* interface in which to handle messages.** param looper The looper, must not be null.* param callback The callback interface in which to handle messages, or null.*/public Handler(NonNull Looper looper, Nullable Callback callback) {this(looper, callback, false);} } 上面只列举了几个构造函数其他一些post消息函数就不一一说明了主要是Handler创建需要关联一个Looper发消息的时候又调用了Looper 内部的消息队列的分发消息函数把消息插入到队列中完成用户对消息队列的操作。 总结 至此相信你对消息分发机制也有大概的理解。
http://www.zqtcl.cn/news/259816/

相关文章:

  • asp iis设置网站路径效果好网站建设哪家好
  • 河南做外贸网站的公司大连在哪个省的什么位置
  • 网站架构怎么做wordpress e-commerce themes
  • 哪些网站微信支付平台经营管理系统
  • 教育教学成果展示网站建设桂林网站开发公司
  • 唐山房产网站建设asp.net 网站压缩
  • 卫浴网站设计大型网站建设的必须条件
  • 肇庆制作企业网站seo网站建设课程
  • 没有公司自己做网站wordpress lms插件
  • 申请一个网站需要怎么做北京网络公司信息
  • 珠海市建设局网站分销系统价格多少
  • 杭州建网站企业seo营销工具
  • php旅游类网站开发wordpress 文章内
  • 企业管理外贸企业网站优化
  • 免费图纸网东莞百度快照优化排名
  • 南宁网站建设培训学校青海网站建设加q5299丶14602做词
  • 鱼台做网站多少钱wordpress pot
  • 招聘网站建设维护人员怎样自己开发一款软件
  • 上海网站制作怎么选泰安网红人物
  • 企业网站建设义乌南靖网站建设
  • 抖音电商网站建设如何制作app推广
  • 关键词的选择网站提示网站建设电销异议处理话术
  • 南京建设网站内容网站打开速度慢是否需要升级带宽
  • 内容类网站如何 流量厦门市建设局网站住房保障专栏
  • 朝城做网站公司网站内容建设要求age06
  • 云南省城乡建设培训中心网站备份wordpress网站
  • 快速建站公司地址vr哪家公司做得好
  • 网站空间怎么更换网站营销如何做
  • 制作单页网站要网址wordpress更新显示失败
  • 阿里巴巴网站建设公司设计网站制作