Android App優化之提升你的App啓動速度之實例挑戰

1, 代碼分析

以之前寫的Github App爲例.

因爲這個App集成了Bugly, Push, Feedback等服務, 所以Application的onCreate有很多第三方平臺的初始化工作…

public class GithubApplication extends MultiDexApplication {

@Override
public void onCreate() {
    super.onCreate();

    // init logger.
    AppLog.init();

    // init crash helper
    CrashHelper.init(this);

    // init Push
    PushPlatform.init(this);

    // init Feedback
    FeedbackPlatform.init(this);

    // init Share
    SharePlatform.init(this);

    // init Drawer image loader
    DrawerImageLoader.init(new AbstractDrawerImageLoader() {
        @Override
        public void set(ImageView imageView, Uri uri, Drawable placeholder) {
            ImageLoader.loadWithCircle(GithubApplication.this, uri, imageView);
        }
    });
}

}
當前冷啓動效果:
這裏寫圖片描述
code_start_before_optimize
可以看到啓動時白屏了很長時間.

2, Traceview上場

接下來我們結合我們上文的理論知識, 和介紹的Traceview工具, 來分析下Application的onCreate耗時.

在onCreate開始和結尾打上trace.

Debug.startMethodTracing(“GithubApp”);

Debug.stopMethodTracing();
運行程序, 會在sdcard上生成一個”GithubApp.trace”的文件.

注意: 需要給程序加上寫存儲的權限:

通過adb pull將其導出到本地

adb pull /sdcard/GithubApp.trace ~/temp
廣告: adb的衆多用法, 可以參考我的另一篇文

打開DDMS分析trace文件
這裏寫圖片描述
ddms_open_trace

分析trace文件
這裏寫圖片描述
traceview_ui
在下方的方法區點擊”Real Time/Call”, 按照方法每次調用耗時降序排.
耗時超過500ms都是值得注意的.
看左邊的方法名, 可以看到耗時大戶就是我們用的幾大平臺的初始化方法, 特別是Bugly, 還加載native的lib, 用ZipFile操作等.
點擊每個方法, 可以看到其父方法(調用它的)和它的所有子方法(它調用的).
點擊方法時, 上方的該方法執行時間軸會閃動, 可以看該方法的執行線程及相對時長.

3, 調整Application onCreate再試

既然已經知道了哪些地方耗時長, 我們不妨調整下Application的onCreate實現, 一般來說我們可以將這些初始化放在一個單獨的線程中處理, 爲了方便今後管理, 這裏我用了一個InitializeService的IntentService來做初始化工作.

明確一點, IntentService不同於Service, 它是工作在後臺線程的.
InitializeService.java代碼如下:

package com.anly.githubapp.compz.service;

import android.app.IntentService;
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.widget.ImageView;

import com.anly.githubapp.common.wrapper.AppLog;
import com.anly.githubapp.common.wrapper.CrashHelper;
import com.anly.githubapp.common.wrapper.FeedbackPlatform;
import com.anly.githubapp.common.wrapper.ImageLoader;
import com.anly.githubapp.common.wrapper.PushPlatform;
import com.anly.githubapp.common.wrapper.SharePlatform;
import com.mikepenz.materialdrawer.util.AbstractDrawerImageLoader;
import com.mikepenz.materialdrawer.util.DrawerImageLoader;

/**
* Created by mingjun on 16/8/25.
*/
public class InitializeService extends IntentService {

private static final String ACTION_INIT_WHEN_APP_CREATE = "com.anly.githubapp.service.action.INIT";

public InitializeService() {
    super("InitializeService");
}

public static void start(Context context) {
    Intent intent = new Intent(context, InitializeService.class);
    intent.setAction(ACTION_INIT_WHEN_APP_CREATE);
    context.startService(intent);
}

@Override
protected void onHandleIntent(Intent intent) {
    if (intent != null) {
        final String action = intent.getAction();
        if (ACTION_INIT_WHEN_APP_CREATE.equals(action)) {
            performInit();
        }
    }
}

private void performInit() {
    AppLog.d("performInit begin:" + System.currentTimeMillis());

    // init Drawer image loader
    DrawerImageLoader.init(new AbstractDrawerImageLoader() {
        @Override
        public void set(ImageView imageView, Uri uri, Drawable placeholder) {
            ImageLoader.loadWithCircle(getApplicationContext(), uri, imageView);
        }
    });

    // init crash helper
    CrashHelper.init(this.getApplicationContext());

    // init Push
    PushPlatform.init(this.getApplicationContext());

    // init Feedback
    FeedbackPlatform.init(this.getApplication());

    // init Share
    SharePlatform.init(this.getApplicationContext());

    AppLog.d("performInit end:" + System.currentTimeMillis());
}

}
GithubApplication的onCreate改成:

public class GithubApplication extends MultiDexApplication {

@Override
public void onCreate() {
    super.onCreate();

    // init logger.
    AppLog.init();

    InitializeService.start(this);
}

}
看看現在的效果:
這裏寫圖片描述
improved-1.gif
可以看到提升了很多, 然後還有一點瑕疵, 就是起來的時候會有一個白屏, 如果手機較慢的話, 這個白屏就會持續一段時間, 不太友好.

那麼還有沒有什麼辦法優化呢?

4, 給我們的應用窗口弄一個PlaceHolder

Android最新的Material Design有這麼個建議的. 建議我們使用一個placeholder UI來展示給用戶直至App加載完畢.

怎麼做呢?

給Window加上背景

如第3節所言, 當App沒有完全起來時, 屏幕會一直顯示一塊空白的窗口(一般來說是黑屏或者白屏, 根據App主題).

前文理論基礎有說到, 這個空白的窗口展示跟主題相關, 那麼我們是不是可以從首屏的主題入手呢? 恰好有一個windowBackground的主題屬性, 我們來給Splash界面加上一個主題, 帶上我們想要展示的背景.

做一個logo_splash的背景:

5, 最終的效果

讓我們來看下最終的效果:
這裏寫圖片描述
improved-2.gif
相比之前, 呈現給用戶的不再是一個白屏了, 帶上了logo, 當然這個背景要顯示什麼, 我們可以根據實際情況來自定義.

這種優化, 對於有些Application內的初始化工作不能移到子線程做的情況, 是非常友好的. 可以避免我們的App長時間的呈現給用戶一個空白的窗口.

6, 結語

照例, 總結下.
這次關於App啓動時間的優化, 寫了兩篇. 寫這麼多, 還是想傳達下個人做技術的思想, 也算是個人的經驗回顧, 拋磚引玉.

實際場景可能遠比這個複雜,在此更多的提供一種分析思路~歡迎擴展
矯情了, 還是總結下本文相關的吧:

Application的onCreate中不要做太多事情.
首屏Activity儘量簡化.
善用工具分析.
多閱讀官方文檔, 很多地方貌似無關, 實際有關聯, 例如這次就用了Material Design文檔中的解決方案.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章