一、内存泄漏
1、什么是内存泄漏
内存泄漏指在程序运行过程中分配的内存空间没有及时释放,导致内存空间占用过多,造成程序的崩溃或者系统的崩溃的现象。一般体现为App启动后,内存不断增加,操作时间越长,内存越大,容易造成ANR或者崩溃。
2、常见的内存泄漏场景
a.静态变量被持有:
“`
public class Singleton{
private static Singleton instance;
public static Singleton getInstance(){
if(instance ==null){
instance =new Singleton();
}
return instance;
}
//…
}
“`
在单例模式中,只要有一个对象持有了该类的引用,那么这个对象和其中的所有成员信息都不会被回收,从而引发了内存泄漏。
b.handler引起内存泄漏:
“`
public class MainActivity extends Activity{
private Handler mHandler =new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
//…
}
“`
在Activity中使用了handler,由于handler持有外部类Activity的引用,那么当Activity被摧毁时,由于handler还持有Acitivity的引用,会导致Activity无法被回收。此时,建议在Activity退出时清除handler的消息队列。
c.监听器泄漏:
“`
public class MainActivity extends Activity{
private MyOnClickListener mListener =new MyOnClickListener(){
@Override
public void onClick(View view) {
}
};
//…
@Override
protected void onDestroy() {
super.onDestroy();
mButton.setOnClickListener(null);
}
}
“`
在Activity中使用监听器时,如果不及时销毁,会造成Activity的内存泄漏,同样的,在Activity销毁时,需要及时清除持有监听器的引用。
二、Bitmap优化
1、Bitmap内存计算
Bitmap在内存中占用的大小=图片的宽度*图片的高度*每个像素点的字节数。
2、Bitmap内存优化
a.采样率缩放
“`
public static Bitmap decodeSampledBitmapFromFile(String filename,int width,int height){
final BitmapFactory.Options options =new BitmapFactory.Options();
options.inJustDecodeBounds =true;
BitmapFactory.decodeFile(filename,options);
options.inSampleSize =calculateInSampleSize(options,width,height);
options.inJustDecodeBounds =false;
return BitmapFactory.decodeFile(filename,options);
}
public static int calculateInSampleSize(BitmapFactory.Options options,int reqWidth,int reqHeight){
final int height =options.outHeight;
final int width =options.outWidth;
int inSampleSize =1;
if(height> reqHeight|| width >reqWidth ){
final int heightRatio =Math.round((float)height/ (float)reqHeight);
final int widthRatio =Math.round((float)width/ (float)reqWidth);
inSampleSize =heightRatio<widthRatio? heightRatio:widthRatio;
}
return inSampleSize;
}
“`
b.使用软引用和弱引用
“`
public HashMap<String, SoftReference> imageCache =new HashMap<String, SoftReference>();
//…
SoftReference reference = new SoftReference(bitmap);
imageCache.put(url, reference);
“`
c.LruCache
“`
public class MemoryCache extends LruCache {
public MemoryCache(int maxSize) {
super(maxSize);
}
@Override
protected int sizeOf(String key, Bitmap value) {
return value.getRowBytes()*value.getHeight();
}
@Override
protected void entryRemoved(boolean evicted, String key, Bitmap oldValue, Bitmap newValue) {
super.entryRemoved(evicted, key, oldValue, newValue);
//释放oldValue的内存空间
oldValue.recycle();
}
}
//…
int maxMemory = (int)(Runtime.getRuntime().maxMemory()/1024);
int cacheSize =maxMemory/8;
mMemoryCache =new MemoryCache(cacheSize);
“`
三、布局优化
1、Layout XML的优化
a.使用include标签
“`
“`
b.使用RelativeLayout,减少deep-level嵌套
“`
“`
c.不使用过于复杂的布局文件
2、代码布局优化
a.手动布局时,减少measure和layout的操作次数
“`
private LinearLayout layoutExample;
layoutExample.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.WRAP_CONTENT));
layoutExample.setOrientation(LinearLayout.VERTICAL);
TextView textView=new TextView(context);
textView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT));
textView.setText(“Custom Text”);
layoutExample.addView(textView);
setContentView(layoutExample);
“`
b.使用自定义View,复用已有的控件
四、资源文件优化
1、资源文件分类
将资源文件按不同的类型进行分类,方便开发和维护。
2、资源文件压缩
a.使用lint工具
打开Android Studio中的预编译检查功能,可检测和提示不必要的资源文件,方便开发时的及时优化。
b.使用TinyPNG或者PngQuant工具
可以无损或者有损地对图片资源进行压缩,减小apk的大小。
五、线程优化
1、线程池的使用
a.避免反复地创建和销毁线程,提高线程的重复利用率。
b.通过Executors类创建线程池,来控制线程的数量和资源。
“`
//使用newFixedThreadPool来创建线程池
ExecutorService threadPool = Executors.newFixedThreadPool(THREAD_POOL_SIZE);
//提交任务
threadPool.execute(new Runnable() {
@Override
public void run() {
//…
}
});
“`
2、AsyncTask的使用
通过AsyncTask来处理UI线程和后台线程的交互,避免在主线程中进行长时间的操作,从而导致ANR。
“`
public class DownloadTask extends AsyncTask{
@Override
protected String doInBackground(String… params) {
//这里进行耗时操作
return result;
}
@Override
protected void onProgressUpdate(Integer… values) {
super.onProgressUpdate(values);
//更新进度条
}
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
//更新UI
}
}
“`
3、使用Handler和ThreadLocal减少内存占用
a.Handler
“`
private static class MyHandler extends Handler{
private final WeakReference mActivity;
public MyHandler(Activity activity){
mActivity =new WeakReference(activity);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if(mActivity.get()!=null){
//执行UI操作或者其他操作
}
}
}
private MyHandler mHandler =new MyHandler(this);
“`
b.ThreadLocal
“`
private ThreadLocal threadLocal =new ThreadLocal(){
@Override
protected SimpleDateFormat initialValue() {
return new SimpleDateFormat(“yyyy-MM-dd HH:mm:ss”);
}
};
private class SimpleThread extends Thread{
@Override
public void run() {
SimpleDateFormat sdf =threadLocal.get();
//…
}
}
“`
六、APP启动优化
1、延迟加载
a.使用Fragment或者ViewPager可以延迟加载不必要的资源或者页面。
“`
public class MyFragment extends Fragment{
//…
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if(isVisibleToUser){
//加载数据或者页面
}else{
//释放资源
}
}
}
“`
b.通过线程池进行延迟加载和预加载,提高App启动速度。
2、懒加载
延迟加载过后,还可以通过懒加载的方式加载不必要的资源,提高App的启动速度。
“`
public class LazyLoadFragment extends Fragment{
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView =inflater.inflate(R.layout.fragment_lazy,container,false);
return rootView;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if(getUserVisibleHint()){
//加载数据或者页面
}
}
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if(isVisibleToUser&&isAdded()){
//加载数据或者页面
}
}
}
“`
七、总结
内存优化是Android开发中的一个重要环节,在开发过程中,多注意内存泄漏的问题,对Bitmap进行优化和管理,对布局和资源文件进行分类和压缩,选用合适的线程池和AsyncTask,延迟和懒加载,可以大大提高App的启动速度和运行效率。
原创文章,作者:小蓝,如若转载,请注明出处:https://www.506064.com/n/249551.html