Android开发艺术探索》综合技术,JNI和性能优化小结

1. 当crash发生时,系统就会调用UncaughtExceptionHandler的uncaughtException方法,可以读取到异常信息;

实现UncaughtExceptionHandler接口,在uncaughtException(Thread t, Throwable ex),ex.printStackTrace(PrintWriter pw)读取异常信息;

public void iinit(Context context) {

    mDefaultCrashHandler = Thread.getDefaultUnCaughtExceptionHandler();

    Thread.setDefaultUncaughtExceptionHandler(this);

    mContext = context.getApplicationContext();

}

在Application初始化时设置CrashHandler

public class TestApp extends Application {

    private static TestApp sInstance;

    public void onCreate() {

        super.onCreate();

        sInstance = this;

        CrashHandler crashHandler = CrashHandler.getInstance();

        crashHandler.init(this);

    }

    public static TestApp getInstance(){

        return sInstance;

    }

}


2. 使用multidex解决方法数越界

1)dexopt是一个程序,在安装时会使用dexopt来优化dex文件,dexopt采用固定大小的缓冲区来存储应用中所有方法的信息,LinearAlloc,大小为8M或者16M,上限为65536个方法数。

2)修改工程app目录下的build.gradle文件,在defaultConfig中添加multiDexEnabled true,在dependencies中添加multidex依赖;

3)在代码中支持multiDex,在manifest文件中指定Application为MultiDexApplication,

或者让应用的Application继承MultiDexApplication,或者重写Application.attachBaseContext方法,加入MultiDex.install(this)

4)可以指定主dex文件中包含的类,通过--main-dex-list设置加载列表,其中multidex的jar包中的9个类必须要打包到主dex中;

5)局限性:应用启动速度会降低,所以要避免产生较大的dex文件,可能有兼容性问题,比如产生大量内存消耗等;


3. 动态加载技术

解决资源访问、Activity生命周期管理和ClassLoader的管理。宿主指的是普通的apk,插件多采用经过特殊处理的apk,插件Activity的启动大多数是借助一个代理Activity来实现的。

1)Activity的工作主要是通过ContextImpl来完成的,其中有AssetManager getAssets()和Resources getResources()两个方法需要实现;首先在loadResources()中通过反射调用AssetManager的addAssetPath方法,将apk中的资源加载到Resources对象中,接着在代理Activity中实现getAssets和getResources;

2)采用反射或者接口的方式管理Activity的生命周期,然后在代理Activity中去调用插件Activity的对应生命周期的方法;反射方式代码复杂,性能有开销;

3)同一个插件采用同一个ClassLoader去加载类,避免多个ClassLoader加载同一个类时引发的类型转换错误,将不同插件的ClassLoader存储在HashMap中。


4. 反编译初步

1)Dex2jar可以将dex文件转化为jar包,再通过jd-gui查看jar包中的源码;

2)使用apktool对apk二次打包;


5. JNI开发

1)在Java中声名native方法

public native String get();

public native void set(String str);

2)javac编译java原文件得到class文件,再通过javah导出JNI头文件;其中JNIEnv *表示一个指向JNI环境的指针,可以访问各种接口方法,jobject表示Java对象中的this。

3)实现Java中的native方法:引用之前的JNI头文件,创建C++文件,实现函数定义;

4)编译C++文件生成动态链接库,在Java的静态初始化函数中加载:System.loadLibrary("jni-test");

5)JNI调用Java方法的流程是先通过类名找到类,再根据方法名找到方法id,再调用该方法;如果调用的是非静态方法,需要构造出类的对象后才能调用它。


6. Android性能优化

1)布局优化:不增加嵌套层级的情况下用LinearLayout代替RelativeLayout,用include标签加载布局文件,merge标签和include一起使用减少布局层级;ViewStub继承了View且宽高都是0,用来按需加载所需的布局文件,当调用它的setVisibility或者inflate方法加载后,ViewStub就会被它内部的布局替换掉;

2)绘制优化:View的onDraw不要创建新的局部对象和进行大量的操作,不要做耗时任务,每一帧保持在16ms以内;静态变量或者单例的引用和无限循环动画导致内存不能释放;

3)在/data/anr目录下保存着ANR的日志;

4)ListView和Bitmap优化:采用ViewHolder并避免在getView中执行耗时操作,快速滑动时不适合开启大量异步任务,开启硬件加速,Bitmap的加载用inSampleSize修改采样率;

5)用线程池代替大量线程,避免创建过多对象,常量用static final修饰,用尽量采用静态内部类,适当使用软引用和弱引用,采用内存和磁盘缓存,使用安卓自带数据结构如SparseArray和Pair等。

6)MAT内存泄露分析

你可能感兴趣的:(Android)