android性能优化之启动速度优化

一叶飘舟 一叶飘舟     2023-03-02     125

关键词:

前言

文本主要会介绍三大块:

1.简略介绍APP启动的完整流程,对整个流程有所了解,才知道在哪里可以进行优化。

2.一些常用的APP启动优化的方案,主要分为三大块优化方向。

3.一些不常见的APP启动优化的方案,甚至包含一些FW层的代码改动,有的可能是对应用开发者无效的,但是对于车载开发是有用的。

一安卓APP启动完整流程分析(冷启动)

图1:

主要分为三个阶段:

1.1 桌面点击APP图标,通知到AMS去完成应用进程的创建的流程

1.安卓系统启动后,拉起的第一个应用是桌面应用。它由SystemServer负责创建,并持有AMS的binder引用。

2.点击桌面图标后,Launcher会通过binder通知AMS启动该APP。

3.AMS会根据传递过来的信息查询APP应用进程在后台是否存在。如果在后台,则属于热启动,如果不在后台,则属于冷启动。优化的重点一般都是冷启动。

4.如果APP进程不存在。AMS主要会做两件事:

一:AMS首先会读取对应APP的Manifest信息(此配置信息是存在于AMS中,手机启动或者应用安装时读取到内存中的),然后根据MainActivity的主题设置,读取其背景图并展示到屏幕上。

二:通过socket的方式通知Zygote去fork产生APP进程。

如图2所示:

1.2 应用进程创建后的流程

5.APP进程创建后,会通过执行ActivityThread中的main方法。此方法主要做了两件事,

第一会进行Looper的初始化;

第二会通过attach方法通知AMS,进行进程的绑定,此时也会把APP创建的binder传递给AMS。

6.AMS中完成注册绑定后,会通过binder通知APP进行application的绑定。APP端binder的接收者是ApplicationThread(下同)。ApplicationThread会被调用bindApplication方法,然后通过handler通知ActivityThread去调用handleBindApplication方法。

7.handleBindApplication方法负责应用初始化的所有流程。主要流程图如下图所示:

图3:

首先,在方法中,通过ContextImpl.createAppContext(this, data.info)去加载DEX文件以及资源。

具体加载DEX的方法在LoadedApk的createOrUpdateClassLoaderLocked方法中:

private void createOrUpdateClassLoaderLocked(List<String> addedPaths) 
        ...
 
        //生成Classloader
            mDefaultClassLoader = ApplicationLoaders.getDefault().getClassLoaderWithSharedLibraries(
                    zip, mApplicationInfo.targetSdkVersion, isBundledApp, librarySearchPath,
                    libraryPermittedPath, mBaseClassLoader,
                    mApplicationInfo.classLoaderName, sharedLibraries, nativeSharedLibraries);
            mAppComponentFactory = createAppFactory(mApplicationInfo, mDefaultClassLoader);
 
        ...
        //把上面生成的mDefaultClassLoader赋值给mClassLoader
        if (mClassLoader == null) 
            mClassLoader = mAppComponentFactory.instantiateClassLoader(mDefaultClassLoader,
                    new ApplicationInfo(mApplicationInfo));
        
    

第二,去执行Application的的attachBaseContext方法。

第三,执行installProvider方法,加载App中的各个ContentProvider

第四,执行Application的onCreate()方法

1.3 Activity的首屏展示流程

8.AMS通知APP创建Application后,还会通知APP进程去启动activity。这时候ApplicationThread接收到之后,会通知ActivityThread完成Activity的启动流程。这个根据android版本不同有区别,android12之后传递的是ClientTransaction。该对象包含一系列事务,对应的会通知构建activity的各个流程。

9.ActivityThread中会分别执行handleLaunchActivity,handleStartActivity,handleResumeActivity等方法,对应的会执行Activity的onCreate,onStart,onResume方法。

10.在handleResumeActivity方法中,执行完resume方法后,判断如何未关联到window上,则会把DecorView加到到ViewManager上。

public void handleResumeActivity(ActivityClientRecord r, boolean finalStateRequest,
            boolean isForward, String reason) 
        ...
        if (!performResumeActivity(r, finalStateRequest, reason)) 
            return;
        
        ...
        if (r.window == null && !a.mFinished && willBeVisible) 
            r.window = r.activity.getWindow();
            View decor = r.window.getDecorView();
            decor.setVisibility(View.INVISIBLE);
            ViewManager wm = a.getWindowManager();
            WindowManager.LayoutParams l = r.window.getAttributes();
            a.mDecor = decor;
            l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
            l.softInputMode |= forwardBit;
            if (r.mPreserveWindow) 
                a.mWindowAdded = true;
                r.mPreserveWindow = false;
                // Normally the ViewRoot sets up callbacks with the Activity
                // in addView->ViewRootImpl#setView. If we are instead reusing
                // the decor view we have to notify the view root that the
                // callbacks may have changed.
                ViewRootImpl impl = decor.getViewRootImpl();
                if (impl != null) 
                    impl.notifyChildRebuilt();
                
            
            if (a.mVisibleFromClient) 
                if (!a.mWindowAdded) 
                    a.mWindowAdded = true;
                    wm.addView(decor, l);
                 else 
                    // The activity will get a callback for this @link LayoutParams change
                    // earlier. However, at that time the decor will not be set (this is set
                    // in this method), so no action will be taken. This call ensures the
                    // callback occurs with the decor set.
                    a.onWindowAttributesChanged(l);
                
            
 
            // If the window has already been added, but during resume
            // we started another activity, then don't yet make the
            // window visible.
         else if (!willBeVisible) 
            if (localLOGV) Slog.v(TAG, "Launch " + r + " mStartedActivity set");
            r.hideForNow = true;
        
        ...
    

11.ViewManager的最终实现类是WindowManagerGlobal,在addView(DecorView)时,会创建ViewRootImpl负责后续绘制的完整流程。

12.添加完成后。ViewRootImpl会生成渲染任务TraversalRunnable,在收到垂直信号量之后执行。任务执行完成后,则首屏就显示在屏幕上了。

二.如何排查启动卡顿问题

2.1 使用SystemTrace的方式进行分析

2.1.1 如何得到冷启动总耗时的准确数据

首先的确保杀死应用,adb shell pkill beanlab (包名匹配到beanlab就杀掉)

然后使用 adb shell am start -W [包名]/[包名.Activity] 。

启动APP,查询App的启动时间

查询结果中,对应的时间参数详细解析如下:

ThisTime:对应activity启动耗时;

TotalTime:应用自身启动耗时 = ThisTime + 应用application等资源启动时间

WaitTime:系统启动应用耗时 = TotalTime + 系统资源启动时间

2.1.2 如何观察冷启动耗时的各个时间段的准确数据

通过抓取systrace可以从图上观察到 bindApplication ->activityStart->activityResume->Choreographer#doFrame

也可以添加自己的方法抓取,注意开始和结束必须成对出现

Trace.beginSection("你的方法");

Trace.endSection();

2.1.3 如何得到冷启动结束的回调

首先是display time:从Android KitKat版本开始,Logcat中会输出从程序

启动到某个Activity显示到画面上所花费的时间。这个方法比较适合测量程序的启动

时间。

筛选AcctivityManager: Displayed

ActivityManager: Displayed com.beantechs.beanlab/.ui.HomeActivity: +842ms 这个时间 和 adb启动分析的 TotalTime 一致

2.2 使用matrix框架

三.如何进行启动优化

第一章时,我们了解了一个APP启动的完整流程。对这个流程分析一下,我们可以住要分成以下三块:

1.从用户点击图标,到通知系统去创建APP进程。

2.APP进程创建后,通知AMS并且进行绑定并走Application的所有流程。

3.启动Activity的流程。

所以如何进行启动优化,也主要按照这三块分类去讲解。

3.1 优化APP进程创建之前的卡顿问题

这一块由于主要运行在系统层面,所以我们可优化的点不多。虽然我们不能彻底解决,但是还是可以一定程度上优化用户的体验。

3.1.1 通过预制图进行体验感觉上的优化。

第一章的时候我们讲过,AMS会根据传递过来的信息,会在启动APP进程之前,加载一张APP的背景图。所以我们可以通过提前加载预制图,让用户感官上知道我们APP已经启动。目前市场上大的APP都有设置预制图,比如支付宝的预制图就是以下这张:

配置方法如下:

在Manifest中,给Main的Activity设置theme即可。

 
<activity
    android:name=".SplashActivity"
    android:theme="@style/LoadingAppTheme"
    tools:replace="android:label">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>
 
<style name="LoadingAppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <!-- Customize your theme here. -->
    <item name="colorPrimary">@color/colorPrimary</item>
    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    <item name="colorAccent">@color/colorAccent</item>
    <item name="windowNoTitle">true</item>
    <item name="windowActionBar">false</item>
    <item name="android:windowContentOverlay">@null</item>
    <item name="android:listDivider">@drawable/divider_line</item>
    <item name="android:windowFullscreen">true</item>
    <item name="android:windowBackground">@drawable/launcher_previewwindow</item>
</style>

android12及以上的版本,支持黑白屏动画形式的展示,具体的使用方式这里就不展开了,原理是一样的。

将现有的启动画面实现迁移到 Android 12 及更高版本

3.2 优化应用初始化耗时问题

应用初始化的优化,主要其实就是就是对bindApplication这个方法的优化,通过打点日志分析,我们发现其实主要有以下几个耗时点,也是对应的我们的优化点。

3.2.1 优化APK加载

第一章时我们知道,加载DEX是在ContextImpl.createAppContext()的时候,自然也是启动主流程上。加载DEX的流程是从APK包中解压,然后ODEX优化,最后加载到内存当中。自然的,如果DEX越少,那么解压的就越少,ODEX优化的越少,速度也就越快。

所以我们优化的主要方法是拆分APP,也是通过组件化,插件化的方式去进行加载。

系统需要在启动的时候读取哪些内容呢?主要有两个部分,dex文件和资源文件。所以我们可以把一个很大的APK,按照业务拆分成多个小的APK。其中主APK中的Dex文件和资源弄的很小,其余业务APK放到asset文件夹中。等到APP启动后,再去解压加载业务APK。因为主APK很小,所以启动速度自然就会快得多。而等到应用启动后,再去通过懒加载的方式,逐渐加载其它模块的业务APK,因为在后台加载,所以也不会影响用户正常的操作,这就是我们组件化启动优化的方案。

结合实际项目,大多数APP其实都不大,所以并不太需要通过这种模块化的方案进行优化,所以就不详细讲如何优化了。有兴趣的可以看一下ShadowRePlugin等框架。

3.2.2 ContentProvider优化

通过第一章的图3我们可以知道,在Application的启动流程中,会依次执行attachBaseContext,ContentProvider的onCreate,Application的onCreate方法。

举例:

public class XXXProvider
    ...
    @Override
    public boolean onCreate() 
        //context init
        ...
        //db init
        dbUtil = DatabaseUtil.getInstance();
        dbUtil.open();
        return true;
    
 
    @Override
    public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable                     String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) 
        return dbUtil.fetchAll();
    
 
    ...

我们可以知道,加载数据库是耗时操作,则我们应该挪到其他步骤当中。

解决问题:

ContentProvider的onCreate()是启动流程当中的,所以我们可以把加载数据库的耗时操作放到query中,或者等到启动完成后延时加载。

public class XXXProvider
    ...
    @Override
    public boolean onCreate() 
        return true;
    
 
    @Override
    public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable                     String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) 
        if(dbUtil==null)
            dbUtil = DatabaseUtil.getInstance();
            dbUtil.open();
        
        return dbUtil.fetchAll();
    
 
    ...
3.2.3 Application中onCreate优化

进行onCreate优化,核心是要梳理onCreate中我们到底做了什么。通过梳理可以发现,onCreate方法中,我们经常要初始化各种框架,比如Bugly.init(),LeakCanary.init()等等,这些框架虽然每个耗时并不多,但是因为是串行执行,累加起来,总耗时反而不少。

举例:

这里以某款APP为例,我们先查看其systrace文件(该文件在5.2当中)

其中bindApplication方法中有一部分如下图所示:

图中显示有加载多个不同SDK类的操作,而且是串行的结构,所以我们可以推断,应用在bindApplication的时候做了太多的初始化操作并且并行执行,导致耗时较多,而且bindApplication对应的是我们项目中Application的onCreate方法。

解决问题:

所以我们可以进行以下几点的优化:

1.部分任务不要主线程执行的,可以挪到子线程执行。

2.有些任务在子线程执行,但是依赖主线程某个任务执行完才可以。这种我们可以等到对应主线任务执行完再把任务加入到子线程池中。

当然,如果相互依赖的逻辑复杂,上面的方式就不太合适了,我们可以使用一个已经封装好的任务拓扑依赖框架来解决这问题:android-startup

使用简介:

首先build.gradle中添加依赖:

implementation 'io.github.idisfkj:android-startup:1.1.0'

创建待执行的启动任务类:

class SampleFirstStartup : AndroidStartup<String>() 
 
     //是否主线程执行
    override fun callCreateOnMainThread(): Boolean = true
 
    //是否依赖主线程任务
    override fun waitOnMainThread(): Boolean = false
 
    //执行的初始化操作
    override fun create(context: Context): String? 
        // todo something
        return this.javaClass.simpleName
    
 
    //依赖哪些其他任务
    override fun dependenciesByName(): List<String>? 
        return null
    
 

然后我们在启动的时候,把这些StartUp组装一下就可以了。

class SampleApplication : Application() 
    override fun onCreate() 
        super.onCreate()
        StartupManager.Builder()
            .addStartup(SampleFirstStartup())
            .addStartup(SampleSecondStartup())
            .addStartup(SampleThirdStartup())
            .addStartup(SampleFourthStartup())
            .build(this)
            .start()
            .await()
    

或者在manifest中注册也可以

<provider
    android:name="com.rousetime.android_startup.provider.StartupProvider"
    android:authorities="$applicationId.android_startup"
    android:exported="false">
 
    <meta-data
        android:name="com.rousetime.sample.startup.SampleFourthStartup"
        android:value="android.startup" />
 
</provider>
3.2.4 其它初始化时的耗时操作

1.SharedPreferences涉及到IO操作,所以如果SP存储数据较大的话,阻塞时间会较长

SharedPreferences sp = getSharedPreferences("1", 0);

sp.getString("1", "1");

3.3 解决Activity加载问题

3.3.1:主线程不执行耗时操作

通过第一章的流程讲解,我们可以知道在第一帧绘制之前,主线程会执行onCreate,onStart,onResume三个方法,所以这三个方法中,一定不能有耗时的方法。

如果一定需要主线程执行的,可以使用IdelHandler的方式解决(IdelHandler会在主线程不忙时执行)。

比如我们在加载数据的时候,就可以通过IdelHandler的方式来代替:

实例如下:

原代码:

@Override
protected void onResume() 
    super.onResume();
    ...
    loadData();
    ...

 
private void loadData() 
    ...
    组装请求..
    发送请求...
    解析数据...

改成:

@Override
protected void onResume() 
    super.onResume();
    ...
    MessageQueue.IdleHandler idleHandler = () -> 
        loadData();
        return false;
    ;
    getMainLooper().getQueue().addIdleHandler(idleHandler);
   
    ...

 
private void loadData() 
    ...
    组装请求...
    发送请求...
    解析数据...
3.3.2:预加载页面

我们通过第二章的工具可以发现,Activity的几个生命周期中,onCreate方法一般是最为耗时的,而onCreate方法中,最为耗时的一般是setContentView(int)方法。

通过深入阅读源码可以可以发现,这其中最为耗时的部分就是把复杂的xml转化为ViewGroup对象。

这种问题,我们可以通过下面的方案来解决:

1. 使用AsyncLayoutInflater。

2.我可以做一个这样的操作,在Application的onCreate方法的任务中,添加一个这样的任务,子线程中把xml转化为ViewGroup。这样执行到Activity的onCreate方法中时,我们可以直接使用ViewGroup对象,从而节省了XML解析的时间。(如果布局文件中含有fragment不能采用此方案)

3.转Compose。Compose的话没有解析XML的时间,也不受到过多布局层级的影响。

3.3.3:局部加载优先显示框架或者占位图

还是通过第二章的工具,我们发现在项目中,measure/layout/draw也是很耗时的(其中一半measure是最耗时的)。这是因为我们布局太复杂了,导致界面渲染的时候需要反复计算,从而耗费时间。

所以针对这种情况,我们可以主要有4个方法来解决:

  1. 非主框架的部分使用ViewStub加载,等到主框架加载并显示出来后,再去加载内容的部分。我们经过测算,在第四帧之后,框架是可以完全显示出来的,所以在第四帧之后进行ViewStub内容的加载,是最为合适的。

  1. 降低布局层次嵌套和复杂度。复杂布局使用约束布局,尽量少使用weight属性等等。

  1. 解决过度绘制问题

  1. 优先加载占位图,等到内容显示好之后,在把占位图隐藏掉。

3.3.4:预加载数据

页面加载好了之后,自然就是请求网络加载数据了。

通过网络加载数据,大多数都是通过OKHttp进行请求。如果想更快的展示出来并且不在乎有效性,那么可以开启使用缓存,并且设置缓存有效时间。

但是这样也有个问题,如果设置了有效期,那么有效期内该请求全部都使用缓存。此时就无法获取最新的数据了,哪怕非首次请求也不行,因为服务并不会为你单独开辟一个新的接口。

我们可以实现这样的一个小需求:“首次请求使用缓存,非首次请求不使用缓存,并且还能把收到的响应更新到首次请求的缓存中”,这样就能比较好的解决上面所说的问题了。

具体例子可以参考我的另外一篇文章中的6.2。OKHttp原理讲解之责任链模式及扩展_失落夏天的博客-CSDN博客_android okhttp责任链

3.4 其它优化

除了针对我们自身代码的优化,还有什么别的优化空间吗?当然有

3.4.1 Baseline Profile

这是google2022年开发者大会新提出的方案。

其核心原理是安卓7.0以后Android支持JIT,AOT并存的混合编译模式。

两者各有优势,JIT即时编译,虽然运行速度慢,但不需要编译时间。而AOT需要编译,后续运行速度快。

一般情况下,首次启动的时候会使用JIT编译,因为AOT需要转换,会导致首次启动耗时。后续使用的时候,安卓系统会根据使用频率计算出那些高频使用的代码,转换为AOT的方式进行编译加载,保证后续这块代码的运行速度。

而Baseline Profile就是需要我们自己把这些高频使用代码,提前打包到APK中,这样首次启动的时候,安卓会通过AOT转换为ODEX代码,以后使用这些可执行文件,速度上就会更快。

3.4.2 Hardcoder

这是腾讯开源的一个框架,核心原理是在需要手机性能时,主动通知系统去提升CPU频率,从而提升手机性能。而不需要性能时,则通知系统降频,避免手机电量的浪费。

https://github.com/Tencent/Hardcoder

3.4.3 Embryo方案

这是一加手机的一个方案,简单解释下就是在后台预创建一个进程,提前加载好资源。这样等到这个APP真的启动的时候,就可以直接使用,而不是重新创建了。

这里其实我有一个更简单有效的方案,我们知道,APP冷启动的时候,是System_server通知Zygote去fork应用进程的,应用进程创建后,再回掉通知System_server进程。至少在这段时间内,是没有绑定任何应用层信息的,也就是下图红框中的部分。

所以,就像APP中的预加载一样,我们为什么不能在系统层预加载一个APP进程呢?等到真的有APP应用创建需求的时候,直接去使用这个APP进程,而不是走创建流程创建一个。因为走的是socket通信,以及fork进程需要时间,所以整个流程有可能可以节省多达100ms的流程。这个方案还在调研探索中,目前理论上是可行的。

3.4.4 Redex方案

这个是facebook提出的一个方案,其实核心本质和proguard有一些类似,混淆字节码,让加载的DEX文件变的更小,则加载变得就更快。redex还有一个突出的亮点就是除了混淆之外,还能做一定的字节码层面的优化,比如A调用B,B调用C的场景,直接改成A调用C,这样减少了一层方法栈,执行速度肯定是更快的。

当然,这个的目标就不单纯的只是解决启动速度了,而是让APP运行的更快乐。

但是这个方法已经已经推出了很久了,到目前为止并不是很流行,其原因也是这样的操作容易引起各种各样的问题。

四.备注

文章中的源码是基于安卓12。如有描述不准确的地方,或者好的建议,欢迎指出来。

android性能优化-启动速度优化(代码片段)

文章目录1.启动的状态2.冷启动耗时2.1系统日志统计2.2adb命令统计3.启动分析3.1CPUProfile工具简单教程3.2启动耗时分析3.3使用DebugApi生成.trace文件4.StrictMode严苛模式5.结尾做开发除了实现功能,还要注重优化,性能优化包括的... 查看详情

android性能优化之启动优化(代码片段)

Android性能优化之启动优化1.启动窗口优化Android系统在Activity的窗口尚未启动完成前,会先显示一个启动窗口(StartingWindow),等界面的第一帧渲染完成后再从启动窗口切换到真正的界面显示,启动窗口通常情况... 查看详情

android性能优化之启动优化(代码片段)

Android性能优化之启动优化1.启动窗口优化Android系统在Activity的窗口尚未启动完成前,会先显示一个启动窗口(StartingWindow),等界面的第一帧渲染完成后再从启动窗口切换到真正的界面显示,启动窗口通常情况... 查看详情

android面试之必问性能优化(代码片段)

对于Android开发者来说,懂得基本的应用开发技能往往是不够,因为不管是工作还是面试,都需要开发者懂得大量的性能优化,这对提升应用的体验是非常重要的。对于Android开发来说,性能优化主要围绕如下方面展开:启动优化... 查看详情

android性能优化之启动耗时测量(代码片段)

Android启动优化之启动耗时测量本文基于Android11.0源码分析,涉及如下文件frameworks/base/services/core/java/com/android/server/wm/ActivityMetricsLogger.javaframeworks/base/services/core/java/com/android/server/wm/ActivityR 查看详情

android性能优化之启动耗时测量(代码片段)

Android启动优化之启动耗时测量本文基于Android11.0源码分析,涉及如下文件frameworks/base/services/core/java/com/android/server/wm/ActivityMetricsLogger.javaframeworks/base/services/core/java/com/android/server/wm/ActivityR 查看详情

❤️android性能优化之启动优化❤️(代码片段)

...赞、收藏、评论粉丝福利:公众号「帅次」一个分享Android体系技术·相关知识·面试题库·技术互助·干货·资讯·高薪职位·教程的地方。🔥背景        用户希望应用能够快速打开。启动时间过长的应用不能满足这个... 查看详情

抖音android性能优化系列:启动优化之理论和工具篇

Rhea指占用CPU进行计算所花费的时间绝对值,中断、挂起、休眠等行为是不会增加CPUTime的,所以因CPUTime开销占比高导致的不合理耗时点往往是逻辑本身复杂冗长需要消耗较多cpu时间片才能处理完。比较常见的高CPU占用是循环,比... 查看详情

android面试-android性能优化和内存优化app启动速度一线大厂的实战案例解析

前言朋友近期面试,经常被问到:你有什么性能优化经验?虽然他在项目中有一些项目优化处理,但没有做过梳理,并且内容也都比较零散,因此在面试回答得不是很好。面试官:你有什么性能优化经... 查看详情

android性能优化之加快应用启动速度

应用的启动启动方式通常来说,在安卓中应用的启动方式分为两种:冷启动和热启动。1、冷启动:当启动应用时,后台没有该应用的进程,这时系统会重新创建一个新的进程分配给该应用,这个启动方式... 查看详情

android性能优化之启动加速35%

...表现紧密相关,从本篇文章开始,我将开启一个Android应用性能优化的专题,从理论到实战,从入门到深挖,手把手将性能优化实践到项目中,欢迎持续关注!那么第一篇文章我就从应用的启动优化开始... 查看详情

android性能优化之启动加速35%

...表现紧密相关,从本篇文章开始,我将开启一个Android应用性能优化的专题,从理论到实战,从入门到深挖,手把手将性能优化实践到项目中,欢迎持续关注!那么第一篇文章我就从应用的启动优化开始... 查看详情

android程序性能优化——anr卡顿优化内存优化耗电优化apk大小优化以及启动速度和实战项目

ANR产生的原因只有当应用程序的UI线程响应超时才会引起ANR,超时产生原因一般有两种。1,当前的事件没有机会得到处理,例如UI线程正在响应另一个事件,当前事件由于某种原因被阻塞了。2,当前的事件正... 查看详情

android面试之必问性能优化(代码片段)

对于Android开发者来说,懂得基本的应用开发技能往往是不够,因为不管是工作还是面试,都需要开发者懂得大量的性能优化,这对提升应用的体验是非常重要的。对于Android开发来说,性能优化主要围绕如下方... 查看详情

性能优化之java(android)代码优化

性能优化之Java(Android)代码优化本文为Android性能优化的第三篇——Java(Android)代码优化。主要介绍Java代码中性能优化方式及网络优化,包括缓存、异步、延迟、数据存储、算法、JNI、逻辑等优化方式。(时间仓促,后面还会... 查看详情

性能优化之java(android)代码优化

本文为Android性能优化的第三篇——Java(Android)代码优化。主要介绍Java代码中性能优化方式及网络优化,包括缓存、异步、延迟、数据存储、算法、JNI、逻辑等优化方式。(时间仓促,后面还会继续完善^_*)目前性能优化专题... 查看详情

android性能优化总提纲

Android性能优化(1)–性能优化介绍Android性能优化(2)—启动优化–1(启动优化介绍+启动时间测量)Android性能优化(2)—启动优化—2(方法耗时获取与异步初始化)Android性能优化(3)–内存优化–(内存优化工具、内存管理机制... 查看详情

爱奇艺技术分享:爱奇艺android客户端启动速度优化实践总结

本文由爱奇艺技术团队原创分享,原题《爱奇艺Android客户端启动优化与分析》。1、引言互联网领域里有个八秒定律,如果网页打开时间超过8秒,便会有超过70%的用户放弃等待,对AndroidAPP而言,要求更加严格,如果系统无响应... 查看详情