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

网站上怎么做动图长春seo整站优化

网站上怎么做动图,长春seo整站优化,北京网站建设方案飞沐,web前端开发论文1、前言 在 Android 开发中,Handler 的机制和运行原理这方面的知识可以说是每个人都需要熟悉的。这不仅是因为 Handler 是 Android 应用的基石之一,也因为 Handler 整体设计上也是十分优秀的。接下来我就梳理总结一下常见的 Handler 相关知识点。 2、基…

1、前言

在 Android 开发中,Handler 的机制和运行原理这方面的知识可以说是每个人都需要熟悉的。这不仅是因为 Handler 是 Android 应用的基石之一,也因为 Handler 整体设计上也是十分优秀的。接下来我就梳理总结一下常见的 Handler 相关知识点。

2、基本使用(GPT)

  1. 创建Handler对象:要使用Handler,首先需要创建一个Handler对象。Handler可以在UI线程或其他线程中创建,但通常在UI线程中创建,以便将消息发送到UI线程。

    Handler handler = new Handler();
    
  2. 发送消息:要将消息发送到Handler,可以使用Handler的post方法或sendMessage方法。通常,您将使用post方法执行一个Runnable任务。

    handler.post(new Runnable() {@Overridepublic void run() {// 在UI线程执行的任务// 可以更新UI元素}
    });
    

    或者使用sendMessage方法:

    Message message = handler.obtainMessage();
    message.what = MY_MESSAGE_CODE;
    handler.sendMessage(message);
    
  3. 处理消息:在Handler所在的线程中,可以覆盖handleMessage方法来处理消息。通常,您需要继承Handler类并重写handleMessage方法。

    class MyHandler extends Handler {@Overridepublic void handleMessage(Message msg) {switch (msg.what) {case MY_MESSAGE_CODE:// 处理消息break;// 可以处理更多不同消息类型}}
    }
    
  4. 关联Handler与Looper:Handler需要与Looper(消息循环)关联,以便能够在消息队列中接收和处理消息。通常,UI线程已经有一个与之关联的Looper,所以在UI线程中创建Handler不需要额外配置。但如果您在其他线程中创建Handler,需要先创建一个Looper。

    Looper.prepare(); // 创建一个新的Looper
    Handler handler = new Handler(); // 关联Handler与新的Looper
    Looper.loop(); // 开始消息循环,必须调用以使Looper活动
    
  5. 从后台线程向UI线程发送消息:通常情况下,Handler最常用于在后台线程执行任务后更新UI线程。例如,如果您在后台线程中进行网络请求,请求完成后,可以使用Handler将结果传递给UI线程以更新UI元素。

    new Thread(new Runnable() {@Overridepublic void run() {// 后台线程执行任务// ...// 任务完成后,使用Handler将结果传递给UI线程handler.post(new Runnable() {@Overridepublic void run() {// 更新UI}});}
    }).start();
    

这些是Android Handler的基本用法。Handler是Android中处理异步任务和多线程通信的重要工具,可以确保UI更新等操作在UI线程中执行,从而避免应用程序崩溃或出现不稳定行为。

3、流程梳理

从 2 中可以看出 Handler 有两种发送信息的方式。第一种是发送 Message;第二种是直接 post runnable。我们分别看下两种方法的源码处理。

3.1 获取 Message 的方式

发送 Message 首先需要获取一个 Message,当然可以直接 new 一个对象出来,但是也可以通过 Message.obtain() 方法来获取一个消息池里面的消息对象。

    public static Message obtain() {synchronized (sPoolSync) {if (sPool != null) {Message m = sPool;sPool = m.next;m.next = null;m.flags = 0; // clear in-use flagsPoolSize--;return m;}}return new Message();}

可见这种方式可以减少内存分配和垃圾回收的开销,因为它避免了频繁创建和销毁 Message 对象,而是重复使用已有对象。这在Android中的消息处理机制中非常有用,因为通常会有大量的消息对象需要创建和处理,如Handler中的消息队列。因此,Message.obtain 方法的使用方式类似于享元模式,通过共享可复用的对象来减少系统资源的消耗,提高性能。这有助于更有效地管理Android应用程序中的消息处理。

3.2 压入消息队列

这里面接着往下看,会通过 Message.enqueueMessage 将这个消息压入消息队列中。这里就要说下这个 Looper 的获取方式了。查看代码可以看到 Looper 是从 ThreadLocal 里面获取到的。ThreadLocal 保证了在每个线程内只有一个 Looper 对象。到这里消息已经进入消息队列中了。

final MessageQueue mQueue;public Handler(@Nullable Callback callback, boolean async) {mLooper = Looper.myLooper();if (mLooper == null) {throw new RuntimeException("Can't create handler inside thread " + Thread.currentThread()+ " that has not called Looper.prepare()");}mQueue = mLooper.mQueue;
}private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,long uptimeMillis) {msg.target = this;msg.workSourceUid = ThreadLocalWorkSource.getUid();if (mAsynchronous) {msg.setAsynchronous(true);}return queue.enqueueMessage(msg, uptimeMillis);
}// Looper.java
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();public static @Nullable Looper myLooper() {return sThreadLocal.get();
}

接下来就是取消息的过程,取消息的方法是在 Looper.java 的 loop 方法中,如果是在子线程使用的情况下需要自己手动启动 Looper.loop 方法开启轮询。主线程中则是由系统在 ActivityThread.java 的 main 方法里面为我们开启了轮询。

public static void main(String[] args) {Looper.prepareMainLooper();ActivityThread thread = new ActivityThread();thread.attach(false, startSeq);if (sMainThreadHandler == null) {sMainThreadHandler = thread.getHandler();}Looper.loop();throw new RuntimeException("Main thread loop unexpectedly exited");
}

接着看 loop 方法,这里面是一个死循环,会一直从消息队列中获取消息。获取到了后会执行 msg.target.dispatchMessage(msg); 方法。可以看到在 android30 里面已经系统已经集成了检测耗时消息的机制(logSlowDelivery 相关代码)。

public static void loop() {final Looper me = myLooper();if (me == null) {throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");}me.mInLoop = true;final MessageQueue queue = me.mQueue;for (;;) {Message msg = queue.next(); // might blockif (msg == null) {// No message indicates that the message queue is quitting.return;}// Make sure the observer won't change while processing a transaction.final Observer observer = sObserver;final long traceTag = me.mTraceTag;long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;long slowDeliveryThresholdMs = me.mSlowDeliveryThresholdMs;if (thresholdOverride > 0) {slowDispatchThresholdMs = thresholdOverride;slowDeliveryThresholdMs = thresholdOverride;}final boolean logSlowDelivery = (slowDeliveryThresholdMs > 0) && (msg.when > 0);final boolean logSlowDispatch = (slowDispatchThresholdMs > 0);final boolean needStartTime = logSlowDelivery || logSlowDispatch;final boolean needEndTime = logSlowDispatch;if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {Trace.traceBegin(traceTag, msg.target.getTraceName(msg));}final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;final long dispatchEnd;Object token = null;if (observer != null) {token = observer.messageDispatchStarting();}long origWorkSource = ThreadLocalWorkSource.setUid(msg.workSourceUid);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);}}if (logSlowDelivery) {if (slowDeliveryDetected) {if ((dispatchStart - msg.when) <= 10) {Slog.w(TAG, "Drained");slowDeliveryDetected = false;}} else {if (showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery",msg)) {// Once we write a slow delivery log, suppress until the queue drains.slowDeliveryDetected = true;}}}if (logSlowDispatch) {showSlowLog(slowDispatchThresholdMs, dispatchStart, dispatchEnd, "dispatch", 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.recycleUnchecked();}
}

这里面 target 在 enqueueMessage 已经设置成了发送 handler。所以执行逻辑会回到 handler 的 dispatchMessage 方法里面。

3.3 消息执行

这里面可以先看一下 post runnable 方法。其实还是发送的 callback 是 runnable 的 Message。所以处理流程都是统一的。

// Handler.java   
public void dispatchMessage(@NonNull Message msg) {// 1、如果 msg 存在 callback 则直接执行,post 方式都会走到这里if (msg.callback != null) {handleCallback(msg);} else {// 2、mCallback 不为空则进入这里处理,这个 mCallback 可以通过构造方法传入if (mCallback != null) {if (mCallback.handleMessage(msg)) {return;}}// 3、最后会走到自身 handleMessage 方法,这个方法可以通过继承重写handleMessage(msg);}
}public final boolean post(@NonNull Runnable r) {return  sendMessageDelayed(getPostMessage(r), 0);
}private static Message getPostMessage(Runnable r) {Message m = Message.obtain();m.callback = r;return m;
}

走到这里,可以发现我们的 Handler 机制在 Java 层已经完全梳理一遍了。下面继续看下 native 层的部分。这里就引入了一个经典问题:那就是主线程 loop 方法是死循环,系统为什么不会卡死呢?
从源码可以看到 loop 方法里面调用了消息队列的 next 方法,这里面会调用继续调用 native 的 nativePollOnce(ptr, nextPollTimeoutMillis); 方法。这里面会通过 epoll 机制,当等待消息的时候,会释放系统资源,当被唤醒时再继续操作。唤醒操作 nativeWake(mPtr); 。

// 0 立即返回,2000 等待 2s,-1 永久休眠
static void android_os_MessageQueue_nativePollOnce(JNIEnv* env, jobject obj,jlong ptr, jint timeoutMillis) {NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);nativeMessageQueue->pollOnce(env, obj, timeoutMillis);
}// 底层通过 epoll 的方式监听读端,会进入等待,等待写入端有数据写入
int eventCount = epoll_wait(mEpollFd.get(), eventItems, EPOLL_MAX_EVENTS, timeoutMillis);// 插入消息的时候,会调用 wake 方法,会写入了 1,唤醒
uint64_t inc = 1;
ssize_t nWrite = TEMP_FAILURE_RETRY(write(mWakeEventFd.get(), &inc, sizeof(uint64_t)));

3.4 消息屏障

消息屏障的典型用例是在UI线程中执行UI更新,以确保UI更新的操作按照它们被提交的顺序执行。例如,如果在后台线程中进行了多次UI更新,并将这些更新消息发送到UI线程的消息队列中,可以使用 sendMessageAtFrontOfQueue 方法来确保这些UI更新按照它们被发送的顺序执行,从而避免UI显示的不一致性。通过 sendMessageAtFrontOfQueue 方法会将时间设置为 0,在进入消息队列的过程中,会直接插入到队列头部,所以可以确保执行优先级较高。

3.5 IdleHandler

IdleHandler是Android中的一个回调接口,它用于在主线程空闲时执行任务。当主线程没有处理消息时(即处于空闲状态),IdleHandler中的回调方法将被触发,允许您执行一些耗时较长的任务,而不会影响到UI的响应性。这在某些情况下非常有用,例如在后台预加载数据或执行其他非UI相关的工作。

// 创建一个IdleHandler
MessageQueue.IdleHandler idleHandler = new MessageQueue.IdleHandler() {@Overridepublic boolean queueIdle() {// 在主线程空闲时执行的任务// 可以执行一些耗时操作,不会阻塞UI线程return false; // 返回true表示继续监听,false表示不再监听}
};// 注册IdleHandler
Looper.myQueue().addIdleHandler(idleHandler);

这块处理逻辑是在 MessageQueue 的 next 方法内部。

4、总结

到这里基本梳理了 Handler 的一些使用和原理,虽然各种框架和 Kotlin 都可以很方便的执行切换线程的操作了,但是这些原理性的东西还是值得我们学习并了解的。

http://www.15wanjia.com/news/28092.html

相关文章:

  • 那几家是做失物招领的网站百度招聘平台
  • wordpress设置网站关键字什么软件推广效果好
  • 外贸网站 中英投广告的平台有哪些
  • 用frontpage制作网页教程南京seo外包
  • 青岛做外贸网站的公司外贸展示型网站建设公司
  • 厦门做模板网站的公司广州seo优化排名推广
  • 车机油哪个网站做的好在线crm系统
  • 怎样在网站上做免费的网业百度seo优化服务
  • 网站开发外包价格北京官网seo收费
  • zblog做的商城网站腾讯网网站网址
  • 慈溪网站制作专业黑帽seo
  • dedecms手机网站百度人工在线客服
  • VPS做镜像网站郑州官网网站推广优化公司
  • 网站子页面怎么做秦皇岛seo排名
  • 网站外链推广平台东莞产品网络推广
  • 黑群晖wordpress建站百度一下手机版首页
  • 深圳网站建设外包公司怎么提高关键词搜索权重
  • 3g免费网站制作网站推广计划书范文500字
  • 双峰做网站网络营销策略都有哪些
  • 珠海seo海网站建设360站长
  • 郴州做网站ku0735百度账号注册中心
  • wordpress插件验证论坛如何做seo
  • 达州市做网站seo搜索引擎优化排名哪家更专业
  • sharepoint做网站百度的电话人工客服电话
  • 佛山做网站有哪几家baike seotl
  • 沈阳网站优化建设青岛网站制作设计
  • 免费做自我介绍网站百度seo是什么意思呢
  • 哪些网站用户体验好友链交易网
  • 国内做网站哪家好关键词智能调词工具
  • 大学生怎么做网站支付模块游戏推广话术