欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Android代码优化

程序员文章站 2024-03-17 17:40:46
...

1、避免使用静态的变量尤其是静态的Context、View、Drawable等消耗内存的对象,如果一定要使用可以使用弱引用,即WeakReference这个类,如下:

    private static WeakReference<Context> context;
    @Override
    public void onCreate() {
        super.onCreate();
        context = new WeakReference<Context>(this);
    }

    public static Context getContext() {
        return context.get();
    }

2、避免非静态内部类引用外部类,因为静态内部类会引用外部类的对象或View对象,造成内存泄露,最典型的是handler使用,如下:

private Handler handler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        Toast.makeText(Act.this, "I am handler", Toast.LENGTH_SHORT).show();
    }
};

private TextView textView;
private Handler handler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        textView.setText("text from handler");
    }
};

替代为:

private Handler handler = new MyHandler(this);
private static class MyHandler extends Handler {
    private WeakReference<Act> activity;
    public MyHandler(Act activity) {
        this.activity = new WeakReference<>(activity);
    }
    @Override
    public void handleMessage(Message msg) {
        Toast.makeText(activity.get(), "show toast from handler", Toast.LENGTH_SHORT).show();
    }
}

3、避免使用枚举,在Android中官方已经不推荐使用枚举,可以使用android.support包提供的annotation编译期注解配合常量来替代,可以参考系统的Toast类源码如下:

    public static final int LENGTH_SHORT = 0;
    public static final int LENGTH_LONG = 1;

    @IntDef({LENGTH_SHORT, LENGTH_LONG})
    @Retention(RetentionPolicy.SOURCE)
    public @interface Duration {

    }

4、在大部分情况下,使用增强的foreach替代for循环,如下:

  int[] num = new int[]{1, 3, 5, 6, 9};
  int sum = 0;
  for (int j = 0; j < num.length; j++) {
    sum += num[j];
  }

可以替代为:

 int[] num = new int[]{1, 3, 5, 6, 9};
 int sum = 0;
 for (int j : num) {
     sum += j;
 }

5、避免在循环语句内部反复创建和销毁对象,避免内存抖动,影响性能,如下:

 int[] numArray1 = new int[]{1, 3, 5, 6, 9};
 int[] numArray2 = new int[]{1, 3, 5, 6, 9};
 int sum = 0;
 for (int j = 0; j < numArray1.length; j++) {
     int num1 = numArray1[j];
     int num2 = numArray2[j];
     sum += num1 + num2;
 }

可以替代为:

int[] numArray1 = new int[]{1, 3, 5, 6, 9};
int[] numArray2 = new int[]{1, 3, 5, 6, 9};
int sum = 0;
int num1;
int num2;
for (int j = 0; j < numArray1.length; j++) {
    num1 = numArray1[j];
    num2 = numArray2[j];
    sum += num1 + num2;
}

6、使用更加高效的数据结构,在Java中如Map、HashMap等,在Android中有专门的设计类都是以Sparsexx开头,如下:

 Map<Integer, String> map1 = new HashMap<>();
 Map<Integer, File> map2 = new HashMap<>();

可以替代为:

SparseArray<String> s1 = new SparseArray<>();
SparseArray<File> s2 = new SparseArray<>();

SparseArray内部定义了一个int类型的数组用于存储key,所以如果map的key是int类型,就可以使用SparseArray替代,下面是类定义:

Android代码优化当然除了这个类还有其他的类,如:SparseBooleanArray、SparseIntArray、SparseLongArray,这三个类内部都定义了int类型的数组来存储key。

7、字符串大量拼接时,使用StringBuilder替代+,且StringBuilder效率比StringBuffer高,如下:

String str = "我";
List<String> names = new ArrayList<>();
names.add("小明");
names.add("小王");
names.add("小刘");
names.add("小赵");
for (String s : names) {
    str += s;
}

可以替代为:

StringBuilder str = new StringBuilder("我");
List<String> names = new ArrayList<>();
names.add("小明");
names.add("小王");
names.add("小刘");
names.add("小赵");
for (String s : names) {
    str.append(s);
}

注意:不要在使用了StringBuilder中又同时使用字符串+,如这样:str.append(s+"\n"),可以这样:str.append(s).append("\n")。

8、避免在自定义View的onDraw方法中重复申请和释放内存,如下:

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    Paint paint = new Paint();
    paint.setColor(Color.RED);
    paint.setTypeface(Typeface.DEFAULT_BOLD);
    paint.setAntiAlias(true);
    paint.setTextSize(28);
}

改为在onDraw方法之前申明:

Paint paint = new Paint();
@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    paint.setColor(Color.RED);
    paint.setTypeface(Typeface.DEFAULT_BOLD);
    paint.setAntiAlias(true);
    paint.setTextSize(28);
}

9、避免使用系统已经过时的方法,如果要使用要对系统API版本进行判断处理,如下:

getResources().getColor(R.color.color_0d0d0d);

getColor带一个参数的这个方法已经标注为过时,替代为:

if (Build.VERSION.SDK_INT >= 23) {
    getResources().getColor(R.color.color_0d0d0d, getTheme());
} else {
    getResources().getColor(R.color.color_0d0d0d);
}

10、使用泛型的时候如果明确知道类型最好限制泛型类型,如下:

public <VIEW> VIEW findViewById(int resId) {
    return (VIEW) contentView.findViewById(resId);
}

替代为:

public <VIEW extends View> VIEW findViewById(int resId) {
    return (VIEW) contentView.findViewById(resId);
}

11、使用android.support.annotation包改进代码,增强代码健壮性,如下:

import android.support.annotation.IdRes;
public View findViewById(@IdRes int resId) {
    return contentView.findViewById(resId);
}

@IdRes是一个编译期注解,代码会在编译阶段进行检查,这样做的好处是外部要调用findViewById方法时不可以随便传入数值,必须是R.id.xx中的某一个,当然传入0和-1也是没问题,一般会用来做默认判断处理,如:

public View findViewById(@IdRes int resId) {
    if (resId <= 0) {
        throw new IllegalArgumentException("传入的参数不对,只能是资源ID.");
    }
    return contentView.findViewById(resId);
}

12、使用ListView时Adapter一定要复用convertView并使用ViewHolder,如下:

public class MyAdapter extends BaseAdapter {
    private List<String> data;
    private final LayoutInflater layoutInflater;

    private class MyViewHolder {
        public TextView textView;

        public MyViewHolder(View itemView) {
            textView = (TextView) itemView.findViewById(R.id.text);
        }
    }

    public MyAdapter(Context context, List<String> data) {
        layoutInflater = LayoutInflater.from(context);
        this.data = data;
    }

    @Override
    public int getCount() {
        return data == null ? 0 : data.size();
    }

    @Override
    public Object getItem(int position) {
        return data.get(position);
    }

    @Override
    public long getItemId(int position) {
        return 0;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        MyViewHolder viewHolder;
        if (convertView == null) {
            convertView = layoutInflater.inflate(R.layout.item_text, parent, false);
            viewHolder = new MyViewHolder(convertView);
            convertView.setTag(viewHolder);
        } else {
            viewHolder = (MyViewHolder) convertView.getTag();
        }
        viewHolder.textView.setText(getItem(position).toString());
        return convertView;
    }
}

13、使用RecyclerView替代ListView,Android 5.0推出了RecyclerView,RecyclerView更加强大、灵活、可扩展性强,简单用法如下:

private class MyViewHolder extends RecyclerView.ViewHolder {
    public final TextView textView;
    public MyViewHolder(View itemView) {
        super(itemView);
        textView = (TextView) itemView.findViewById(R.id.text);
    }
}
private class MyAdapter extends RecyclerView.Adapter<MyViewHolder> {
    private final LayoutInflater layoutInflater;
    private List<String> data;
    public MyAdapter(Context context, List<String> data) {
        layoutInflater = LayoutInflater.from(context);
        this.data = data;
    }
    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        return new MyViewHolder(layoutInflater.inflate(R.layout.item_text, parent, false));
    }
    @Override
    public void onBindViewHolder(MyViewHolder holder, int position) {
        holder.textView.setText(getItem(position));
    }
    public String getItem(int position) {
        return data.get(position);
    }
    @Override
    public int getItemCount() {
        return data == null ? 0 : data.size();
    }
}

RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
List<String> languages = new ArrayList<>();
languages.add("C");
languages.add("C++");
languages.add("Java");
languages.add("Kotlin");
languages.add("Python");
MyAdapter adapter = new MyAdapter(this, languages);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setAdapter(adapter);

注意:RecyclerView一定要调用setLayoutManager来指定item布局排列,否则无法展示列表数据。具体详细用法,请移步。

14、如果成员变量的值是固定不变的,改用final static修饰,如下:

private String TAG = "MyAdapter";

改为:

private final static String TAG = "MyAdapter";

15、使用Timer或TimerTask时要记得取消,在Activity的onDestroy或Fragment的onDetach方法中调用cancel方法取消。

16、使用TypedArray完毕后及时调用typedArray.recycle()方法释放资源。

17、文件或流操作时要在finally语句块中关闭而不要在catch语句块中关闭,因为如果发生异常程序就不会往下执行,如下:

FileInputStream fis;
try {
    fis = new FileInputStream(Environment.getExternalStorageDirectory() + "aa.txt");
    fis.close();
} catch (FileNotFoundException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
}

改为:

FileInputStream fis = null;
try {
    fis = new FileInputStream(Environment.getExternalStorageDirectory() + "aa.txt");
} catch (FileNotFoundException e) {
    e.printStackTrace();
} finally {
    if (fis != null) {
        try {
            fis.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

作者:Shyky
链接:https://juejin.im/post/5a24ae816fb9a044fb07960e
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
相关标签: android开发