不精通则死

上一篇文章,讲到了很多Android应用开发中需要注意的性能和内存方面的技巧。这一篇文章就是从smali指令级来分析性能优化和内存优化的问题。

如何解决界面启动时间开销大的问题

我们在编写Android应用的时候,很多情况下会遇到界面启动时间过长的问题,用户体验非常的不好。所以我们在编写代码的时候,,一定要多加注意如何提高界面的启动时间。下面会讲到几个优化界面启动开销的技巧。

1.类的加载开销

当一个类的静态方法或者静态属性被调用或者类被实例化得时候,虚拟机首先做的第一件事情就是DexClassLoader将类的class文件加载到虚拟机,而加载到虚拟机的过程会触发class文件中clinit函数的执行。我们看下面一段代码

package com.example.smalidemo.foreach;import java.util.ArrayList;import java.util.List;public class OnInitTest {public static final String INIT_STRING = "initstring_fantasy";public static String INIT2_STRING = "for initstring_fantasy 2";private String INIT3_STRING = "initstring_fantasyh 3";public static final int INT_1 = 100;public static int INIT_INT = 10000;public static List list = new ArrayList();public static final ArrayList<AppBean> mAppListOnInit = new ArrayList<AppBean>();public static ArrayList mAppList = null;private static String STRING_ARRAY[] = { "jpg", "mp5", "mp4" };private static final String FINAL_STRING_ARRAY[] = { "pdf", "txt","exe" };}

反编译后的smali文件

.class public Lcom/example/smalidemo/foreach/OnInitTest;.super Ljava/lang/Object;.source "OnInitTest.java"# static fields.field private static final FINAL_STRING_ARRAY:[Ljava/lang/String; = null.field public static INIT2_STRING:Ljava/lang/String; = null.field public static INIT_INT:I = 0x0.field public static final INIT_STRING:Ljava/lang/String; = "initstring_fantasy".field public static final INT_1:I = 0x64.field private static STRING_ARRAY:[Ljava/lang/String;.field public static list:Ljava/util/List;.field public static mAppList:Ljava/util/ArrayList;.field public static final mAppListOnInit:Ljava/util/ArrayList;.annotation system Ldalvik/annotation/Signature;value = {"Ljava/util/ArrayList","<","Lcom/example/smalidemo/foreach/AppBean;",">;"}.end annotation.end field# instance fields.field private INIT3_STRING:Ljava/lang/String;# direct methods.method static constructor <clinit>()V.locals 10.prologueconst/16 v9, 0x2710const/4 v8, 0x3const/4 v7, 0x2const/4 v6, 0x1const/4 v5, 0x0.line 8const-string v3, "for initstring_fantasy 2"sput-object v3, Lcom/example/smalidemo/foreach/OnInitTest;->INIT2_STRING:Ljava/lang/String;.line 11sput v9, Lcom/example/smalidemo/foreach/OnInitTest;->INIT_INT:I.line 12new-instance v3, Ljava/util/ArrayList;invoke-direct {v3}, Ljava/util/ArrayList;-><init>()Vsput-object v3, Lcom/example/smalidemo/foreach/OnInitTest;->list:Ljava/util/List;.line 13new-instance v3, Ljava/util/ArrayList;invoke-direct {v3}, Ljava/util/ArrayList;-><init>()Vsput-object v3, Lcom/example/smalidemo/foreach/OnInitTest;->mAppListOnInit:Ljava/util/ArrayList;.line 14const/4 v3, 0x0sput-object v3, Lcom/example/smalidemo/foreach/OnInitTest;->mAppList:Ljava/util/ArrayList;.line 15new-array v3, v8, [Ljava/lang/String;const-string v4, "jpg"aput-object v4, v3, v5const-string v4, "mp5"aput-object v4, v3, v6const-string v4, "mp4"aput-object v4, v3, v7sput-object v3, Lcom/example/smalidemo/foreach/OnInitTest;->STRING_ARRAY:[Ljava/lang/String;.line 16new-array v3, v8, [Ljava/lang/String;const-string v4, "pdf"aput-object v4, v3, v5const-string v4, "txt"aput-object v4, v3, v6.line 17const-string v4, "exe"aput-object v4, v3, v7.line 16sput-object v3, Lcom/example/smalidemo/foreach/OnInitTest;->FINAL_STRING_ARRAY:[Ljava/lang/String;.line 20const/4 v1, 0x0.local v1, i:Imove v2, v1.line 21.end local v1#i:I.local v2, i:I:goto_0add-int/lit8 v1, v2, 0x1.end local v2#i:I.restart local v1#i:Iif-lt v2, v9, :cond_0.line 25return-void.line 22:cond_0new-instance v0, Lcom/example/smalidemo/foreach/AppBean;invoke-direct {v0}, Lcom/example/smalidemo/foreach/AppBean;-><init>()V.line 23.local v0, bean:Lcom/example/smalidemo/foreach/AppBean;sget-object v3, Lcom/example/smalidemo/foreach/OnInitTest;->mAppListOnInit:Ljava/util/ArrayList;invoke-virtual {v3, v0}, Ljava/util/ArrayList;->add(Ljava/lang/Object;)Zmove v2, v1.end local v1#i:I.restart local v2#i:Igoto :goto_0.end method 在上面得Java文件中,我们声明了一些变量,其中包括字符串,整数,字符串数组,其中有些声明了final,一些没有声明final。我们可以看到声明final的字符串和整数,在编译后的文件中已经成为了常量,而没有声明final的变量,我们可以看到在声明的地方,仍然是类型默认值 string的默认值是null,而int的默认值是0。所以当DexClassLoader加载class文件的时候,会在<clinit>函数里面,对以上的静态变量初始化值。我们可以看到,声明的若干个静态变量,在编译后的smali文件中,成为了更多的smali指令。

提高DexClassLoader加载class的速度,就是要提高class中<clinit>函数的执行速度。

通过以上的分析我们可以总结出以下几个规则:

声明静态的变量,一定要添加final的声明 (在编译器变量就被常量代替,就不会再类加载的时候消耗CPU时间)

2.类的创建实例开销

一个class文件中除了静态变量外,还有很多全局非静态变量。而我们在声明全局变量的时候,都会为全局变量赋值。

private String INIT3_STRING = "initstring_fantasyh 3";以上这一条Java语句,在smali文件中会变成几条指令呢 我们来看一下:勤勉是通往胜利的必经之路。要是由于胆怯艰难而去另觅佳径,

不精通则死

相关文章:

你感兴趣的文章:

标签云: