Android 性能优化方法
开发中常会做一些性能优化,主要优化内容包括布局层级优化,绘制优化,内存泄露优化(音频,视频,io等回收),响应速度优化,ListView优化,Bitmap优化,线程优化以及一些性能优化,在面试中面试官也会经常问到该点 . 前面博文我收集的各大厂等面试题
布局优化
布局优化思想,尽量减少布局文件的层级,层级少,意味Android绘制时的工作量少了,程序的性能自然提高了.
- 删除布局中无用的控件和层级
- 有选择使用性能较低的ViewGroup,如:RelativeLayout
- 优先使用LinearLayout,相对RelativeLayout,其功能比较简单,花费较少的CPU时间
- 需要复杂嵌套实现效果时,这种情况下建议采用RelativeLayout
- 采用标签在于布局重用,标签降低减少布局层级和ViewStub按需加载
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/main_background_color"
android:fitsSystemWindows="true"
android:orientation="vertical">
<include layout="@layout/layout_toolbar"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="10dp"
android:layout_weight="1"
android:orientation="vertical">
<!--个人信息-->
<RelativeLayout
android:id="@+id/rl_setting_user_message"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="@color/white">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="15dp"
android:text="个人信息"
android:textColor="@color/text_color_black"
android:textSize="16sp"/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="15dp"
android:src="@mipmap/arrow"/>
</RelativeLayout>
<ImageView
android:layout_width="match_parent"
android:layout_height="1dp"
android:src="@color/button_stroke"/>
<!--账号安全-->
<RelativeLayout
android:id="@+id/rl_setting_user_safe"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="@color/white">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="15dp"
android:text="账号安全"
android:textColor="@color/text_color_black"
android:textSize="16sp"/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="15dp"
android:src="@mipmap/arrow"/>
</RelativeLayout>
<!--消息通知-->
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_marginTop="15dp"
android:background="@color/white">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="15dp"
android:text="消息通知"
android:textColor="@color/text_color_black"
android:textSize="16sp"/>
<Switch
android:id="@+id/switch_message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="15dp"
android:showText="false"
android:textOff=""
android:textOn=""
android:thumb="@drawable/swtich_thumb_selector"
android:track="@drawable/swtich_track_selector"
/>
</RelativeLayout>
<ImageView
android:layout_width="match_parent"
android:layout_height="1dp"
android:src="@color/button_stroke"/>
<!--音效-->
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="@color/white">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="15dp"
android:switchMinWidth="40dp"
android:switchPadding="10dp"
android:text="音效"
android:textColor="@color/text_color_black"
android:textOff="开"
android:textOn="关"
android:textSize="16sp"
android:typeface="normal"/>
<Switch
android:id="@+id/switch1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="15dp"
android:gravity="center_vertical"
android:showText="false"
android:textOff=""
android:textOn=""
android:thumb="@drawable/swtich_thumb_selector"
android:track="@drawable/swtich_track_selector"
/>
</RelativeLayout>
<!--版本号-->
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_marginTop="15dp"
android:background="@color/white">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="15dp"
android:text="版本"
android:textColor="@color/text_color_black"
android:textSize="16sp"/>
<TextView
android:id="@+id/version"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="15dp"
android:textColor="@color/color_bfbfbf"
android:textSize="16sp"/>
</RelativeLayout>
</LinearLayout>
<Button
android:id="@+id/bt_login_out"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_marginBottom="15dp"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:background="#ff4a2c"
android:gravity="center"
android:text="登出账号"
android:textColor="@color/white"
android:textSize="18sp"/>
</LinearLayout>
绘制优化
绘制优化是指View的onDraw方法要避免执行大量的操作,如下三点
- onDraw中不要创建新的局部对象,因为onDraw方法可能会被频繁调用,这样就会在一瞬间产生大量的临时对象,这不仅占用了过多的内存而且还会导致系统更加频繁gc,降低了程序的执行效率
- onDraw方法中不要做耗时的任务,也不能执行复杂的循环操作,尽管每次循环都很轻量级,但是大量的循环任然十分抢占CPU的时间片,这回造成View的绘制过程不流畅.
- Google官方给出的性能优化典范中的标准,View的绘制帧率保证60fps是最佳的,这就要求每帧的绘制时间不超过16ms(16 = 1000/60),虽然程序很难保证16ms这个时间,但是尽量降低onDraw方法的复杂度总是切实有效的.
内存泄露优化
内存泄露在开发过程中是一个需要重视的问题,但是由于内存泄露问题 对开发人员的经验和开发意识有较高的要求,因此这也是开发人员最容易犯的错误之一.内存泄露的优化分为两个方面,一方面是开发过程中避免写出有内存泄露的代码.另一方面是通过一些分析工具找出潜在的内存泄露
- 静态变量导致的内存泄露,(在dalvik虚拟机中,static变量所指向的内存引用,如果不把它设置为null,GC是永远不会回收这个对象的),处理: 对象=null;
- 单例模式导致的内存泄露,如下
单例模式导致的内存泄露:Activty是间接继承于Context的,当这Activity退出时,Activity应该被回收, 但是单例中又持有它的引用,导致Activity回收失败,造成内存泄漏。
package com.kx.singleinstance;
import android.content.Context;
/**
* @ 创建: kx
* @ 时间: 2018/11/13
* @ 描述:
*/
public class AppManager {
private static AppManager instance;
private Context mContext;
public AppManager(Context context) {
mContext = context;
}
public static AppManager getInstance(Context context){
if(instance == null){
instance = new AppManager(context);
}
return instance;
}
}
单例模式导致的内存泄露改进:使用Applicaton的Context,而我们单例的生命周期和应用的一样长,这样就防止了内存泄漏。
package com.kx.singleinstance;
import android.content.Context;
/**
* @ 创建: kx
* @ 时间: 2018/11/13
* @ 描述:
*/
public class AppManager {
private static AppManager instance;
private Context mContext;
public AppManager(Context context) {
//使用Applicaton的Context,而我们单例的生命周期和应用的一样长,这样就防止了内存泄漏。
mContext = context.getApplicationContext();
}
public static AppManager getInstance(Context context){
if(instance == null){
instance = new AppManager(context);
}
return instance;
}
}
- 属性动画导致的内存泄露,属性动画无限循环动画,Activity与View相互持有,导致Activity无法释放. 解决: onDestroy 对动画 animator.cancel()来停止动画
响应速度优化
响应速度优化的核心思想是避免在主线程中做耗时操作,这里具体可参考前面的文章.耗时操作放在线程中去执行,即采用异步的方式执行耗时操作.响应速度过慢更多地体现在Activity的启动速度上面,如果在主线中做太多事情,会导致Activity启动时出现黑屏现象,甚至出现ANR, Android规定,Activity如果5秒钟之内无法响应屏幕触摸事件或者键盘输入时间就会出现ANR,而BroadcastReceiver如果10秒钟之内还未执行完操作也会出现ANR.
ListView和Bitmap优化
listview优化
-
convertView的使用,主要优化加载布局问题
-
内部类ViewHolder的使用,采用ViewHolder并避免在getView中执行耗时操作
-
滑动的时候不载入图片
在ListView滑动的时候载入图片,那样会使ListView变得卡顿,所以我们须要再监听器里面监听ListView的状态。假设滑动的时候,停止载入图片,假设没有滑动,则開始载入图片
listView.setOnScrollListener(new OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView listView, int scrollState) {
//停止载入图片
if (scrollState == AbsListView.OnScrollListener.SCROLL_STATE_FLING) {
imageLoader.stopProcessingQueue();
} else {
//開始载入图片
imageLoader.startProcessingQueue();
}
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
// TODO Auto-generated method stub
}
});
-
将ListView的scrollingCache和animateCache设置为false
A.scrollingCache: scrollingCache本质上是drawing cache,你能够让一个View将他自己的drawing保存在cache中(保存为一个bitmap),这样下次再显示View的时候就不用重画了,而是从cache中取出。默认情况下drawing cahce是禁用的。由于它太耗内存了,可是它确实比重画来的更加平滑。而在ListView中,scrollingCache是默认开启的,我们能够手动将它关闭。
B.animateCache: ListView默认开启了animateCache,这会消耗大量的内存,因此会频繁调用GC,我们能够手动将它关闭掉
<ListView
android:id="@android:id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:divider="@color/list_background_color"
android:dividerHeight="0dp"
android:listSelector="#00000000"
android:scrollingCache="false"
android:animationCache="false"
android:smoothScrollbar="true"
android:visibility="gone" />
-
降低item的布局的深度
尽量降低item布局深度,由于当滑动ListView的时候,这回直接导致測量与绘制,因此会浪费大量的时间。所以我们应该将一些不必要的布局嵌套关系去掉。
-
分批加载与分页加载相结合
线程优化
线程优化的核心思想是采用线程池,避免程序中存在大量的Thread.线程池可以重用内部的线程,从而避免了线程的创建和销毁所带来的性能开销,同时线程池还能有效地控制线程池的最大并发数,避免大量的线程因互相抢占系统资源从而导致阻塞现象的发生.因此在实际开发中,我们要尽量采用线程池,而不是每次都要创建一个Thread对象
心灵激励
激励:为自己技术增值,量变引起质变.博主依稀记得当前的语文老师说的一句话:“态度决定高度”,博主想对所有的读者说"过去的已经过去,你的未来由你现在把握".
尾言
本文如有错误或不当之处,欢迎读者留言斧正,互相交流学习,博主不胜感激.联系邮箱593584960@qq.com