Android面试——APP性能优化

Android应用性能优化基础知识。

布局优化

  • 避免OverDraw过渡绘制
  • 优化布局层级
  • 避免嵌套过多无用布局
  • 当我们在画布局的时候,如果能实现相同的功能,优先考虑相对布局,然后在考虑别的布局,不要用绝对布局。
  • 使用标签把复杂的界面需要抽取出来
  • 使用标签,因为它在优化UI结构时起到很重要的作用。目的是通过删减多余或者额外的层级,从而优化整个Android Layout的结构。核心功能就是减少冗余的层次从而达到优化UI的目的!
  • ViewStub 是一个隐藏的,不占用内存空间的视图对象,它可以在运行时延迟加载布局资源文件。

Android布局优化之Merge Include ViewStub使用与源码分析

Android抽象布局——include、merge 、ViewStub

Android LayoutInflater原理分析,带你一步步深入了解View(一)

代码优化

  • 使用AndroidLint分析结果进行相应优化
  • 不使用枚举及IOC框架,反射性能低
  • 常量加static
  • 静态方法
  • 减少不必要的对象、成员变量
  • 尽量使用线程池
  • 适当使用软引用和弱引用
  • 尽量使用静态内部类,避免潜在的内存泄露
  • 图片缓存,采用内存缓存LRUCache和硬盘缓存DiskLRUCache
  • Bitmap优化,采用适当分辨率大小并及时回收

ListView和GridView优化

  • 采用ViewHolder复用convertView
  • 避免在getView中执行耗时操作
  • 列表在滑动状态时不加载图片
  • 开启硬件加速

移动端获取网络数据优化

  • 连接复用 :节省连接建立时间,如开启 keep-alive。
    对于 Android 来说默认情况下 HttpURLConnection 和 HttpClient 都开启了 keep-alive。只是 2.2 之前 HttpURLConnection 存在影响连接池的 Bug,具体可见:Android HttpURLConnection 及 HttpClient 选择
  • 请求合并:即将多个请求合并为一个进行请求,比较常见的就是网页中的 CSS Image Sprites。如果某个页面内请求过多,也可以考虑做一定的请求合并。
  • 减少请求数据的大小:对于post请求,body可以做gzip压缩的,header也可以作数据压缩(不过只支持http 2.0)。
    返回的数据的body也可以作gzip压缩,body数据体积可以缩小到原来的30%左右。(也可以考虑压缩返回的json数据的key数据的体积,尤其是针对返回数据格式变化不大的情况,支付宝聊天返回的数据用到了)
  • 根据用户的当前的网络质量来判断下载什么质量的图片(电商用的比较多)。

相关工具

  • 使用Hierarchy Viewer查看UI布局层级
  • 使用AndroidStudio Memory Monitor查看内存使用情况
  • 使用TraceView优化App性能
  • 使用内存泄露分析工具MAT分析APP内存状态
  • 检测内存泄露的开源库:LeakCanary
  • 腾讯出品:GT

    Android中引起内存泄露的原因

内存泄漏简单地说就是申请了一块内存空间,使用完毕后没有释放掉。它的一般表现方式是程序运行时间越长,占用内存越多,最终用尽全部内存,整个系统崩溃。由程序申请的一块内存,且没有任何一个指针指向它,那么这块内存就泄露了。

  • 注册没取消造成内存泄露,如:广播
  • 静态变量持有Activity的引用
  • 单例模式持有Activity的引用
  • 查询数据库后没有关闭游标cursor
  • 构造Adapter时,没有使用 convertView 重用
  • Bitmap对象不在使用时调用recycle()释放内存
  • 对象被生命周期长的对象引用,如activity被静态集合引用导致activity不能释放
  • 使用Handler造成的内存泄露

Android中使用Handler造成的内存泄露解决方案

原文链接:Android App 内存泄露之Handler

  • 静态内部类+弱引用WeakReference
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public class HandlerActivity2 extends Activity {  

    private static final int MESSAGE_1 = 1;  
    private static final int MESSAGE_2 = 2;  
    private static final int MESSAGE_3 = 3;  
    private final Handler mHandler = new MyHandler(this);  

    @Override  
    public void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  
        mHandler.sendMessageDelayed(Message.obtain(), 60000);  

        // just finish this activity  
        finish();  
    }  

    public void todo() {  
    };  

    private static class MyHandler extends Handler {  
        private final WeakReference mActivity;  

        public MyHandler(HandlerActivity2 activity) {  
            mActivity = new WeakReference(activity);  
        }  

        @Override  
        public void handleMessage(Message msg) {  
            System.out.println(msg);  
            if (mActivity.get() == null) {  
                return;  
            }  
            mActivity.get().todo();  
        }  
    }

进一步优化

当Activity finish后 handler对象还是在Message中排队。 还是会处理消息,这些处理有必要?
正常Activitiy finish后,已经没有必要对消息处理,那需要怎么做呢?
解决方案也很简单,在Activity onStop或者onDestroy的时候,取消掉该Handler对象的Message和Runnable。
通过查看Handler的API,它有几个方法:removeCallbacks(Runnable r)和removeMessages(int what)等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**  
  * 一切都是为了不要让mHandler拖泥带水  
  */  
 @Override  
 public void onDestroy() {  
     mHandler.removeMessages(MESSAGE_1);  
     mHandler.removeMessages(MESSAGE_2);  
     mHandler.removeMessages(MESSAGE_3);  

     // ... ...  

     mHandler.removeCallbacks(mRunnable);  

     // ... ...  
 }

1
2
3
4
5
@Override  
public void onDestroy() {  
    //  If null, all callbacks and messages will be removed.  
    mHandler.removeCallbacksAndMessages(null);  
}

你可能感兴趣的:(Android面试,APP性能优化)