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設置圖片原理(下)

相關文章
相關標籤/搜索