1. 程式人生 > >Android微信登入引起的記憶體洩漏

Android微信登入引起的記憶體洩漏

近日公司需求跟得不緊,就自己找事優化,重構,找記憶體洩漏(如有錯誤,煩請拍磚大笑)

記憶體洩漏工具之前的寫的部落格也有介紹 記憶體洩漏檢測工具很好用,下面用LeakCanary找一個微信登入引起的記憶體洩漏(其實微信是有做釋放操作,但是文件和demo中沒有見到)

洩漏資訊


圖中可以看出自己應用的WeChatLoginActivity的例項沒有回收掉導致的記憶體洩漏,再往上是WXApiImpV10中的一個內部類ActivityLifecycleCb中持有WeChatLoginActivity的例項導致的

不多說看微信SDK原始碼

檢視createWXAPI的方法(因為WeChatLoginActivity

的context是從這裡傳入的)

    public static IWXAPI createWXAPI(Context var0, String var1, boolean var2) {
        b.e("MicroMsg.PaySdk.WXFactory", "createWXAPI, appId = " + var1 + ", checkSignature = " + var2);
        return new WXApiImplV10(var0, var1, var2);
    }

比較簡單直接進入WXApiImplV10,繼續看WXApiImplV10


構造方法儲存了context,registerApp方法中建立了activitycb,而且我們的洩漏最終是activitycb

導致,registerActivityLifecycleCallbacks這個方法我不瞭解,也沒看過大概實現,不過一般註冊都有登出,這個暫時擱置。繼續看ActivityLifecycleCb類

   private static final class ActivityLifecycleCb implements ActivityLifecycleCallbacks {
        private static final String TAG = "MicroMsg.SDK.WXApiImplV10.ActivityLifecycleCb";
        private static final int DELAYED = 800;
        private boolean isForeground;
        private Handler handler;
        private Context context;
        private Runnable onPausedRunnable;
        private Runnable onResumedRunnable;

        private ActivityLifecycleCb(Context var1) {
            this.isForeground = false;
            this.handler = new Handler(Looper.getMainLooper());
            this.onPausedRunnable = new Runnable() {
                public void run() {
                    if(WXApiImplV10.activityCb != null && ActivityLifecycleCb.this.isForeground) {
                        Log.v("MicroMsg.SDK.WXApiImplV10.ActivityLifecycleCb", "WXStat trigger onBackground");
                        StatService.trackCustomKVEvent(ActivityLifecycleCb.this.context, "onBackground_WX", (Properties)null);
                        ActivityLifecycleCb.this.isForeground = false;
                    }

                }
            };
            this.onResumedRunnable = new Runnable() {
                public void run() {
                    if(WXApiImplV10.activityCb != null && !ActivityLifecycleCb.this.isForeground) {
                        Log.v("MicroMsg.SDK.WXApiImplV10.ActivityLifecycleCb", "WXStat trigger onForeground");
                        StatService.trackCustomKVEvent(ActivityLifecycleCb.this.context, "onForeground_WX", (Properties)null);
                        ActivityLifecycleCb.this.isForeground = true;
                    }

                }
            };
            this.context = var1;
        }

        public final void onActivityCreated(Activity var1, Bundle var2) {
        }

        public final void onActivityDestroyed(Activity var1) {
        }

        public final void onActivityPaused(Activity var1) {
            Log.v("MicroMsg.SDK.WXApiImplV10.ActivityLifecycleCb", var1.getComponentName().getClassName() + "  onActivityPaused");
            this.handler.removeCallbacks(this.onResumedRunnable);
            this.handler.postDelayed(this.onPausedRunnable, 800L);
        }

        public final void onActivityResumed(Activity var1) {
            Log.v("MicroMsg.SDK.WXApiImplV10.ActivityLifecycleCb", var1.getComponentName().getClassName() + "  onActivityResumed");
            this.handler.removeCallbacks(this.onPausedRunnable);
            this.handler.postDelayed(this.onResumedRunnable, 800L);
        }

        public final void onActivitySaveInstanceState(Activity var1, Bundle var2) {
        }

        public final void onActivityStarted(Activity var1) {
        }

        public final void onActivityStopped(Activity var1) {
        }

        public final void detach() {
            this.handler.removeCallbacks(this.onResumedRunnable);
            this.handler.removeCallbacks(this.onPausedRunnable);
            this.context = null;
        }
    }
注意他在onActivityPaused和onActivityResumed進行了一個延時,如果短時間再次啟動  就會造成洩漏,如果registerActivityLifecycleCallbacks是有登出方法,也基本再次開啟頁面也會有記憶體洩漏。繼續看你會發現一個detach方法,也就是微信寫了釋放,但是demo和文件沒有說這個事。看到這裡你應該就明白怎麼解決

WeChatLoginActivity中的onDestroy中呼叫IWXAPI.detach();即可

因為微信登入正常就開啟第一次然後就不會再開啟,所以這個記憶體洩漏基本不會遇到。