一:手机启动
这个时候会启动HomeActivity;而各种APP图标就是HomeActivity中的控件,这些控件是可以点击的。与之对应的是,Launcher(继承了Activity)中有onClick(View view)方法。我们点击这个onClick方法的时候,就会把这个应用的相关信息传入传入到一个Intent里面。Object tag=v.getTag(); final Intent intent =((ShortCutInfo)tag).intent;
点击哪个应用,哪个应用就是v,v.getTag();就是获得这个应用的tag.。
然后调用startActivity(intent);启动对应的app.,在这里的intent是一个进程信息。这个时候会通知我们的系统,我要打开这个进程。系统中的AMS会把该进程装进虚拟机的内存中,并且开辟堆、栈、常量池、方法区等等内存。还记得不,后台有一个孵化器(zygote)进程,zygote通过fork的方式开启一个叫SystemServer,SystemServer开启ActivityThread进程。注意:此之前的操作是由系统完成的,我们是无法优化的(当然,你如果足够的牛,可以重新写一个android系统优化)。
ActivityThread里面有一个main(String[] args)方法,该方法有如下代码
ActivityThread thread=new ActivityThread();
thread.attach(false)
自己启动了自己,在thread.attach(false)方法里会绑定application(此时的application在makeapplication方法中创建并且已经有了包等信息,紧接着会执行application的onCreate方法)。我们从这里就可以进行优化了。 这个时候会做一系列事情,最后创建Activity(Activity的onCreate方法执行)。我们的启动优化过程就是从Application的初始化,到Activity的onCreate()结束。
如果不做启动优化我们可能出现很多问题,比如白屏问题,我们启动一个app的时候会出现一个白屏。白屏持续数秒,这是一个很不好的用户体验。另外还有黑屏问题,与白屏相似。
我们来看下黑白屏的根源在哪里?
当我们新建一个项目的时候,app会有一个默认的主题。
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
如果代码里没有parent="Theme.AppCompat.Light.DarkActionBar"
,就是黑屏,如果有这句代码就是白屏。如果你手机性能很好,看不出来,也有办法,你在Application类的onCreate()方法里延迟三秒Thread.sleep(3000);
我们查找Theme.AppCompat.Light.DarkActionBar
的父类,一直查找下去,会发现他有一个叫Platform.AppCompat.Light的父类。在该父类的部分代码如下:
<style name="Platform.AppCompat.Light" parent="android:Theme.Light">
<item name="android:windowNoTitle">true</item>
<!-- Window colors -->
<item name="android:colorForeground">@color/foreground_material_light</item>
<item name="android:colorForegroundInverse">@color/foreground_material_dark</item>
<item name="android:colorBackground">@color/background_material_light</item>
<item name="android:colorBackgroundCacheHint">@color/abc_background_cache_hint_selector_material_light</item>
<item name="android:disabledAlpha">@dimen/abc_disabled_alpha_material_light</item>
<item name="android:backgroundDimAmount">0.6</item>
<item name="android:windowBackground">@color/background_material_light</item>
我们看最后一个属性
<item name="android:windowBackground">@color/background_material_light</item>
白屏的颜色就是这个@color/background_material_light颜色。问题出在这里。
先在我们修改下,在styles里增加一个属性
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
//在这里定义自己的颜色,你也可以定义自己的图片
<item name="android:windowBackground">@color/colorAccent</item>
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
京东就是这么干的,启动的时候加载一张图片,这张图片要显示几秒钟,他们在Application类的onCreate()中Thread.sleep( );
了几秒钟。这样起到了一个打广告的效果
也可以改成透明颜色
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
//改成透明
<item name="android:windowIsTranslucent">true</item>
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
改成透明效果后会有一个等待。但即使改成透明,也是会消耗内存的。我们看下腾讯QQ是怎么解决这个问题的。
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="android:windowBackground">@null</item>
//禁止预览为真
<item name="android:windowDisablePreview">true</item>
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
这种效果和我们的透明效果是一样的,会有一个等待效果。但不消耗内存。
但这样也有不好的地方,肯能导致每个启动activity都出现等待结果,我们可以单独抽出来一个主题,运用到入口Activity.
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
//声明启动的style,注意style必须继承AppCompat
<style name="AppTheme.LauncherStyle">
<item name="android:windowBackground">@null</item>
<item name="android:windowDisablePreview">true</item>
</style>
</resources>
在xml文件中配置
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.acer.testfanshe">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity"
android:theme="@style/AppTheme.LauncherStyle">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>
还没有完,还需要在代码中设置
package com.example.acer.testfanshe;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//设置主题,注意要加下划线
setTheme(R.style.AppTheme_LauncherStyle);
}
}
二:我们启动优化可以从三个地方入手,一个是Application的onCreate(),一个是Activity的onCreate(),一个是xml文件。
介绍一个性能测试方法
@Override
public void onCreate() {
super.onCreate();
Debug.startMethodTracing("文件路径");
/**
* do something
*/
Debug.stopMethodTracing();
}
会生成一个文件,这个文件可以在as中打开。查看执行时间长的那些方法,然后进行优化。在onCreate()方法里不要做过多的事情,向开启OkHttpClient这些事情可以使用懒加载,下载图片等网络请求可以开启一个线程。
注意开启线程的时候可能会报这个错误,java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
在Application的onCreate()中,如果我们想开启线程节约时间,需要注意以下几个问题
(1)里面使用到的网络请求夹包可能会创建Handler,这是不允许的。不能在这个方法里创建Handler.
(2)不能有UI操作
(3)对异步要求不高;如果我们开启的线程执行时间较长,这个时候主线程已经执行完Application 的onCreate();去执行其它的代码,比如 Activity的onCreate();这个时候,在纸箱Activity的onCreate()方法里可能就会报空指针异常。
介绍一个查看Activity启动耗时的方法:Dispalayed关键字
另外也可以在命令行中输入如下命令查看
adb shell am start -W 包名/.xxxActivity
输入该命令后启动Activity,cmd会打印输出如下
C:\Users\acer>adb shell am start -W com.example.acer.testfanshe/.MainActivity
Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=com.ex
mple.acer.testfanshe/.MainActivity }
Warning: Activity not started, its current task has been brought to the front
Status: ok
Activity: com.example.acer.testfanshe/.MainActivity
ThisTime: 5791
TotalTime: 5791
WaitTime: 20043
Complete
ThisTime表示最后一个Activity启动的时间,TotalTime表示所有Activity启动的时间,因为我们程序里只有一个MainActivity,所有他们两个是相等的。waitTime包括系统启动+Activity启动的时间
热启动与冷启动的区别
冷启动:app的信息加载到内存
热启动:app的信息不需要加载到内存,app信息已经在内存中存在了。因为后台进程一直存在。app shell ps命令可以查看该进程是否在内存中。