Android的activity启动延迟加载
来源:互联网 发布:如何删除知乎提问 编辑:程序博客网 时间:2024/05/17 21:41
我们有时会遇到白屏或者页面切换卡顿等现象,这些都是Activity启动速度慢的表现.我们一般有两种优化方式,软优化和硬优化.硬优化主要是针对代码的结构和逻辑,如精简布局,减少层次使用include,merge,viewStub;能用基本类型如Int,Long,就不用Integer,Long对象等.软优化尽可能减少代码的结构和逻辑,下面我们主要来看软优化的延迟加载.
延迟加载是把可以延迟展示的UI操作放在IdleHandler中
public class BaseActivity extends Activity { @Override protected void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); Looper.myQueue().addIdleHandler(new IdleHandler() { @Override public boolean queueIdle() { onCreateDelay(savedInstanceState); return false; } }); } protected void onCreateDelay(Bundle bundle) { // TODO : 可以延迟展示的UI操作 }}
在Looper的消息循环方法中一直通过Message msg = queue.next();来获得下一个消息
public static void loop() { final Looper me = myLooper(); 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.recycleUnchecked(); } }
我们接下来看MessageQueue的next方法:
Message next() { // Return here if the message loop has already quit and been disposed. // This can happen if the application tries to restart a looper after quit // which is not supported. final long ptr = mPtr; if (ptr == 0) { return null; } int pendingIdleHandlerCount = -1; // -1 only during first iteration int nextPollTimeoutMillis = 0; for (;;) { if (nextPollTimeoutMillis != 0) { Binder.flushPendingCommands(); } nativePollOnce(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) { // Stalled by a barrier. Find the next asynchronous message in the queue. do { prevMsg = msg; msg = msg.next; } while (msg != null && !msg.isAsynchronous()); } if (msg != null) { if (now < msg.when) { // 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) { prevMsg.next = msg.next; } else { mMessages = msg.next; } msg.next = null; if (DEBUG) Log.v(TAG, "Returning message: " + msg); msg.markInUse(); return msg; } } else { // 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 handler boolean 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; } }
当msg 为空时并不会马上返回,而是继续往下执行,接着下面的for循环中有我们刚开始添加的IdleHandler,并回调queueIdle(),最后根据最开始的返回boolean值来决定是否保留IdleHandler,我们返回的false,代表下次线程空闲时不会调用这个IdleHander了.
总结:MessageQueue.IdleHandler可以用来在线程空闲的时候,指定一个操作;有点类似Handler.postDelayed(Runnable r, long delayMillis),都是在将来的某一个时间执行一个操作。
不过,使用IdleHandler的好处在于可以不用指定一个将来时间,只要线程空闲了,就可以执行它指定的操作。比较适合那种需要在将来执行操作,但是又不知道需要指定多少延迟时间的操作。
1 0
- Android的activity启动延迟加载
- Android的activity启动延迟加载
- Android启动另一个Activity时无法执行语句解决办法之加载延迟
- Android Home键后Activity延迟启动
- Activity延迟加载
- Activity+Viewpager 延迟加载
- Android中Activity的四种加载(启动)模式
- Android Home键之后启动Activity延迟5秒
- Android Activity延迟跳转
- Android Activity延迟跳转
- Activity开机画面延迟启动
- Android中延迟加载的问题
- Android中延迟加载方法的使用
- Android项目的启动一般过程,Activity的启动(加载)模式
- Android-->动态加载Activity (不使用Intent,启动Activity)
- android 延迟加载动作
- android app 延迟加载
- 延迟加载ycm以加快vim的启动速度
- C语言练习题每练 1:字符串统计单词个数,单词由空格隔开
- 30 年后你拿什么养活自己(1):培养理财意识的一本书
- 字符串(String)
- 剖析C++对象模型
- 读取电话联系人
- Android的activity启动延迟加载
- 悬浮框效果
- DirectXMath
- File的sd卡
- 数据库三范式讲解
- NFS安装
- Picasso详细解析(一)
- LeetCode ——258.Add Digits
- Android 热修复总结