/** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ package com.facebook.litho; import android.app.Activity; import android.content.Context; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import java.util.WeakHashMap; /** * Callbacks that must be invoked to avoid leaking memory if using Components * below ICS (API level 14). */ public class ComponentsLifecycles { private static class LeakDetector { private Context mContext; LeakDetector(Context context) { mContext = context; } void clear() { mContext = null; } @Override public void finalize() { if (mContext != null) { final Context context = mContext; // Post the error to the main thread to bring down the process - // exceptions on finalizer threads are ignored by default. new Handler(Looper.getMainLooper()).post(new Runnable() { @Override public void run() { throw new RuntimeException("onContextDestroyed method not called for: " + context); } }); } } } private static WeakHashMap<Context, LeakDetector> mTrackedContexts; public static void onActivityCreated(Activity activity, Bundle savedInstanceState) { onContextCreated(activity); } public static void onActivityDestroyed(Activity activity) { onContextDestroyed(activity); } public static void onContextCreated(Activity activity) { ComponentsPools.sIsManualCallbacks = true; onContextCreated((Context) activity); } public static void onContextCreated(Context context) { if (mTrackedContexts == null) { mTrackedContexts = new WeakHashMap<>(); } LeakDetector old = mTrackedContexts.put(context, new LeakDetector(context)); if (old != null) { throw new RuntimeException("Duplicate onContextCreated call for: " + context); } ComponentsPools.onContextCreated(context); } public static void onContextDestroyed(Context context) { if (mTrackedContexts == null) { throw new RuntimeException( "onContextDestroyed called without onContextCreated for: " + context); } LeakDetector removed = mTrackedContexts.remove(context); if (removed == null) { throw new RuntimeException( "onContextDestroyed called without onContextCreated for: " + context); } else { removed.clear(); } ComponentsPools.onContextDestroyed(context); } }