Android高级之十二讲之如何下降应用内存消耗



安卓应用的内存每每是有限的,从开始的8M到16M,24M,32M,48M,64M等逐步变大,但内存的变大是因为分辨率的提升致使,并不意味着能够随意声明使用内存,而不及时回收(即便Java有本身的垃圾回收机制,但内存太高会引发应用变卡,体验流畅性降低)。java

下降应用内存消耗的办法有如下几种常见办法:android

一、图片声明使用的context使用Application,回收时清除ImageView的drawableweb

二、使用viewStub占位,避免常用gone方法,减小对象的加载和初始化数据库

三、使用merge把能合并的布局通通合并,在hierachyviewer里面能够看到布局的复杂度canvas

四、去掉decorView和window的背景,每每因为应用有自身的色调搭配app

五、经过canvas的clip方法,避免在看不到的地方画图,经过quickReject方法来在肯定的区域好比矩形内绘制,ide

跳过非既定区域内绘制工具

六、使用9path文件和自定义图片,以及透明背景,来防止过分绘制布局

七、列表能够给定一个高度(根据item的高度来动态设置),来防止重复计算高度和执行布局方法优化

八、合理选择组件,选择简单的而非复杂的组件(缘由,若是你自定义过复杂组件本身就会明白)

九、开启新进程做为服务进程和工具进程-最大招,有效下降当前应用的内存消耗


避免内存泄露的几个办法:

一、及时清除对象或回调引用的context,下降引用链长度

    /**
     * 清除页面的ImageView的引用链
     * @param view
     */
    public static void unbindDrawables(View view) {
        if (view.getBackground() != null) {
            view.getBackground().setCallback(null);
        }
        if (view instanceof ViewGroup) {
            for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
                unbindDrawables(((ViewGroup) view).getChildAt(i));
            }
            ((ViewGroup) view).removeAllViews();
        }
    }


二、Bitmap用前根据屏幕dpi或自定义要求进行压缩,事后及时回收

三、Cursor对象及时关闭,避免对数据库对象的长期引用

四、关键地方作空判断,页面关闭时及时回收对象

五、context尽可能使用application,避免页面关闭时,因为引用存在而不能及时回收对象

六、避免在for循环中声明对象(一会儿无数个对象产生,内存暴增),引用能写在外面最好,如array.length,直接用

int size获取值,再遍历

七、打开开发者模式中的CPU绘制选项,根据屏幕显示的红黄蓝来辨别页面的绘制状况

八、handler每每引用context,使用弱引用的方式处理

    public WeakHandler handler = new WeakHandler(this);

    public class WeakHandler extends Handler {
        WeakReference<Context> mContextWeakReference;

        public WeakHandler(Context context) {
            mContextWeakReference = new WeakReference<Context>(context);
        }

        @Override
        public void handleMessage(Message msg) {
            if (mContextWeakReference.get() == null || msg == null) {
                return;
            }
            boolean handled = !handleMessageDelegate(msg.what, msg.obj);
            if (handled) {
                if (msg.what < 0) {
                    handleErrorMessage(msg);
                } else {
                    handlePtrMessage(msg);
                }
            }
        }
    }

九、通常webView也会有内存泄露的问题出现,每每因为引用未删除,自身的view仍然存在,在进程一系列操做后,仍可使用开启新进程来下降应用内存

    /**
     * 优化内存最后一招-开启新进程
     */
    @Override
    protected void onDestroy() {
        if (mWebView != null) {// remove webView, prevent chromium to crash
            ViewParent parent = mWebView.getParent();
            if (parent != null) {
                ((ViewGroup) parent).removeView(mWebView);
            }
            // 退出时调用此方法,移除绑定的服务,不然某些特定系统会报错
            mWebView.getSettings().setJavaScriptEnabled(false);
            // 解决Receiver not registered:
            // android.widget.ZoomButtonsController
            mWebView.setVisibility(View.GONE);
            mWebView.removeAllViews();
            mWebView.clearCache(false);
            mWebView.stopLoading();
            mWebView.destroy();
            mWebView = null;
            setConfigCallback(null);
        }
        super.onDestroy();
    }

    /**
     * 删除引用
     * @param windowManager
     */
    public void setConfigCallback(WindowManager windowManager) {
        try {
            Field field = WebView.class.getDeclaredField("mWebViewCore");
            field = field.getType().getDeclaredField("mBrowserFrame");
            field = field.getType().getDeclaredField("sConfigCallback");
            field.setAccessible(true);
            Object configCallback = field.get(null);
            if (null == configCallback) {
                return;
            }
            field = field.getType().getDeclaredField("mWindowManager");
            field.setAccessible(true);
            field.set(configCallback, windowManager);
        } catch(Exception e) {
        }
    }


检查内存泄露的工具备:Lint(inspect code-performance)、Mat(case gc-分析hprof文件)、LeakMemory(Log日志弹窗)、As自带(Monitor-Dump Java Heap),更多介绍

图片更多:Android ImageView设置图片原理(下)

相关文章
相关标签/搜索