android常见的性能优化方面的总结

栏目: IOS · Android · 发布时间: 6年前

内容简介:年假即将结束,这篇文章也算是我自己梳理android知识的最后几篇了。文章中的整体思路是根据《android开发艺术》结合平时开发经验以及网上的资料完成的。内容用的源码都可以在GitHub上的项目中查看到,希望阅读完这篇文章能让你有所收获。在layout文件中创建在Activity的layout布局引入:

年假即将结束,这篇文章也算是我自己梳理android知识的最后几篇了。文章中的整体思路是根据《android开发艺术》结合平时开发经验以及网上的资料完成的。内容用的源码都可以在GitHub上的项目中查看到,希望阅读完这篇文章能让你有所收获。

项目源码

目录

  • 布局优化
  • 绘制优化
  • 内存泄漏优化
  • ListView和Bitmap优化

布局优化

  • 减少布局文件的层级
  • 删除布局中无用的控件和布局
  • 尽量使用简单高效的ViewGroup,比如 FrameLayoutLinaerLayout
  • 可以使用include标签复用布局,使用merge标签减少层级

include、merge标签案例

在layout文件中创建 layout/incloude_merge_memory.xml 文件内容如下:

<merge xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/mTV_incloud_merge"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@android:color/holo_red_light"
        android:gravity="center"
        android:padding="5dp"
        android:text="这是一个include的merge" />
</merge>
复制代码

在Activity的layout布局引入:

<include layout="@layout/incloude_merge_memory" />
复制代码

ViewStub

  • 它是一个轻量级的布局宽度、高度只有0,不参与绘制过程。
  • 按需加载,不占用空间。
  • 当显示ViewStub中的布局时候,ViewStub会被替换掉,并且会被从布局中移除。

xml代码:

<ViewStub
    android:id="@+id/mVS_layoutMemory"
    android:layout_width="match_parent"
    android:layout_height="80dp"
    android:background="@android:color/holo_blue_bright"
    android:inflatedId="@id/mRL_viewStubMemory"
    android:layout="@layout/viewsutub_memory"
    android:padding="10dp" />
复制代码

上面代码中id为mVS_layoutMemory为ViewStub的id,而inflatedId是引入布局 @layout/viewsutub_memory 跟布局的id。需要注意的是ViewStub中layout布局是不支持merge标签的,接下来看一下 java 代码的调用:

mVS_layoutMemory = findViewById(R.id.mVS_layoutMemory);
mVS_layoutMemory.setVisibility(View.VISIBLE);
复制代码

绘制优化

  • 不要在onDraw中创建新的布局对象
  • 不要在onDraw中做大量的耗时操作

内存泄漏优化

  • 静态变量引起的泄漏
  • 单例模式引起的泄漏
  • 非静态内部类持有外部引用导致的泄漏
  • Handler引起的内存泄漏
  • 属性动画引起的泄漏

静态变量导致的内存泄漏

这种情况常见的是Context的使用,比如我们写了一个 工具 类,里面的静态方法需要用到Context。如果我们将Activity的this传给这个方法,那么Activity在被回收的时候由于这个静态变量持有Activity的引用,导致不能被回收从而引起内存泄漏。

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_layoyt_memory);
  AppUtil.getTesLeak(this);
}

public static void getTesLeak(Context context) {
    Toast.makeText(context, "您的内存泄漏啦", Toast.LENGTH_SHORT).show();
}
复制代码

解决上面的问题也很多简单,如果我们的工具类不是一定需要Activity的Context,难么我们可以考虑使用 getApplicationContext() 。因为 getApplicationContext() 是和我们App的生命周期一样长,如果App不退出他就不会被回收。

单例模式导致的内存泄漏

单例引起的内存泄漏,大概思路上面差不多,也是因为静态变量的生命周期太长,如果程序不退出,系统就不会对其回收,这将导致本应该不用的对象不能回收,我们可以指定Context为getApplicationContext();来避免内存泄漏。

public class MemorySingle {
    //如果传入上下文
    private static Context context;
    private MemorySingle() {
    }

    public static MemorySingle getInstance(Context context) {
        //防止内存泄漏
        MemorySingle.context = context.getApplicationContext();
        return Menory.single;
    }
    
    static class Menory {
        private static final MemorySingle single = new MemorySingle();
    }
}
复制代码

非静态内部类持有外部引用引起的泄漏

因为非静态内部类的生命周期是和外部类的生命周期绑定在一起的,非静态内部类会持有外部类的引用,如果我们在内部类中做一些耗时操作,如下面内部类sleepThread()方法让线程睡10秒,在这个时候如果Activy要销毁,但是因为内部类持有外部类的引用,它的sleepThread()方法还没执行完,所以导致Activy不能被回收,引起内存泄漏。

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_layoyt_memory);
    TestLeak testLeak = new TestLeak();
    testLeak.sleepThread();
}
 class TestLeak {
    private void sleepThread() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    //睡10秒
                    Thread.sleep(10000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
}
复制代码

解决方法将TestLeak改成静态内部类

static class TestLeak {
    private void sleepThread() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    //睡10秒
                    Thread.sleep(10000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
复制代码

Handler引起的内存泄漏

我们使用Handler做消息处理的时候可能不注意会用下面这种写法:

private Handler mHanlder = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case 200:
                mTV_incloud_merge.setText((String) msg.obj);
                break;
        }
        super.handleMessage(msg);
    }
};
复制代码

上面的mHanlder是Handler的非静态匿名内部类,上面我们提到过非静态匿名内部类会持有外部引用,所以如果使用上面的写法也会引起内存泄漏。下面有两种方式可以避免泄漏。

第一种方式: 使用静态内部类+弱引用方式

static class MyHanlder extends Handler {
    //弱引用
    WeakReference<Activity> mWeakRef;
    public MyHanlder(Activity activity) {
        mWeakRef = new WeakReference<>(activity);
    }
    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        switch (msg.what) {
            case 200:
                LayoutMemoryActivity activity = (LayoutMemoryActivity) mWeakRef.get();
                activity.mTV_incloud_merge.setText((String) msg.obj);
                break;
        }
    }
}
复制代码

第二种: Handler.Callback方式处理消息

Handler mHandler = new Handler(new Handler.Callback() {
    @Override
    public boolean handleMessage(Message msg) {
        switch (msg.what) {
            case 200:
                mTV_incloud_merge.setText((String) msg.obj);
                break;
        }
        return false;
    }
})
复制代码

属性动画导致的内存泄漏

当一个Activy中有一个无限循环的属性动画,在Activy销毁的时候没有停止动画也会引起内存泄漏

ObjectAnimator oA = ObjectAnimator.ofFloat(mBnt_layoutMemory, "rotation", 0, 360).setDuration(20000);
               oA.start();
复制代码

上面的是一个按钮选装动画,20秒后执行完,如果在动画还为执行完的时候销毁Activy,将会导致Activy无法释放引起内存泄漏。下面是解决办法

@Override
protected void onDestroy() {
    super.onDestroy();
    //取消动画
    oAnimator.cancel();
}
复制代码

ListView和Bitmap优化

ListView优化

ListView的优化是一个很长见的问题,主要是通过ViewHolder实现对item的复用,这里不做过多的解释了。在这我推荐一篇文章感兴趣的可以看看,下面有一个例子:

@Override
public View getView(final int position, View convertView,        ViewGroup parent) {
    MyHolder myHolder = null;
    //判断是否有缓存布局
    if (convertView == null) {
        convertView =LayoutInflater.from(context).inflate(android.R.layout.simple_list_item_1, null);
        myHolder = new MyHolder(convertView);
        convertView.setTag(position);
    } else {
        //得到缓存布局
        myHolder = (MyHolder) convertView.getTag();
    }
    myHolder.mTV_test1.setText(textContent);
}          
class MyHolder {
    TextView mTV_test1;

    MyHolder(View view) {
        mTV_test1 = view.findViewById(android.R.id.text1);
    }
}
复制代码

Bitmap优化

我们大部分图片处理是使用 glide 、'picasso',这些框架在图片加载速度和性能优化方面已经很好了,但有些特殊情况可能需要我们自己实现图片的处理,主要注意下面几个方面。

  • 对图片进行压缩
  • 缓存策略
  • 图片不使用的时候要记得释放

总结

android的性能优化需要了解的方面还有很多比如电量的优化、包大小、启动速度的优化等等,上面列出的只是一部分常见的问题和解决办法。在开发过程中需要优化的放要远比上面写道的多,还需要我们自己多积累经验和结合实际考虑来优化。

参考

Android 内存泄漏总结 Android性能优化的浅谈


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Agile Web Development with Rails, Third Edition

Agile Web Development with Rails, Third Edition

Sam Ruby、Dave Thomas、David Heinemeier Hansson / Pragmatic Bookshelf / 2009-03-17 / USD 43.95

Rails just keeps on changing. Rails 2, released in 2008, brings hundreds of improvements, including new support for RESTful applications, new generator options, and so on. And, as importantly, we’ve a......一起来看看 《Agile Web Development with Rails, Third Edition》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具