draft

//WeakHashMap的Key-Value回收原理 还是依赖ref+Queue
class MemoryLeakTrack private constructor() : ITracker {
private val mHandler = Handler(CollieHandlerThread.looper)
private val mActivityStringWeakHashMap = WeakHashMap<Activity, String>()
private val mSimpleActivityLifecycleCallbacks: SimpleActivityLifecycleCallbacks =
object : SimpleActivityLifecycleCallbacks() {
override fun onActivityDestroyed(activity: Activity) {
super.onActivityDestroyed(activity)
mActivityStringWeakHashMap[activity] = activity.javaClass.simpleName
}

        override fun onActivityStopped(activity: Activity) {
            super.onActivityStopped(activity)
            //  退后台,GC 找LeakActivity
            if (!isInBackGround()) {
                return
            }
            mHandler.postDelayed({
                mallocBigMem()
                Runtime.getRuntime().gc()
            }, 1000)
            mHandler.postDelayed(Runnable {
                try {
                    if (!isInBackGround()) {
                        return@Runnable
                    }
                    //  分配大点内存促进GC
                    mallocBigMem()
                    Runtime.getRuntime().gc()
                    SystemClock.sleep(100)
                    System.runFinalization()
                    val hashMap = HashMap<String, Int>()
                    for ((key) in mActivityStringWeakHashMap) {
                        val name = key.javaClass.simpleName
                        val value = hashMap[name]
                        if (value == null) {
                            hashMap[name] = 1
                        } else {
                            hashMap[name] = value + 1
                        }
                    }
                    if (mMemoryListeners.size > 0) {
                        for ((key, value) in hashMap) {
                            for (listener in mMemoryListeners) {
                                listener.onLeakActivity(key, value)
                            }
                        }
                    }
                } catch (ignored: Exception) {
                }
            }, 10000)
        }
    }

override fun destroy(application: Application) {
    Collie.instance.removeActivityLifecycleCallbacks(mSimpleActivityLifecycleCallbacks)
    mHandler.removeCallbacksAndMessages(null)
}

override fun startTrack(application: Application) {
    Collie.instance.addActivityLifecycleCallbacks(mSimpleActivityLifecycleCallbacks)
    mHandler.postDelayed(object : Runnable {
        override fun run() {
            if (mMemoryListeners.size > 0 && !isInBackGround()) {
                val trackMemoryInfo = collectMemoryInfo(application)
                for (listener in mMemoryListeners) {
                    listener.onCurrentMemoryCost(trackMemoryInfo)
                }
            }
            mHandler.postDelayed(this, (30 * 1000).toLong())
        }
    }, (30 * 1000).toLong())
}

override fun pauseTrack(application: Application) {}
private val mMemoryListeners: MutableSet<ITrackMemoryListener> = HashSet()
fun addOnMemoryLeakListener(leakListener: ITrackMemoryListener) {
    mMemoryListeners.add(leakListener)
}

fun removeOnMemoryLeakListener(leakListener: ITrackMemoryListener) {
    mMemoryListeners.remove(leakListener)
}

interface ITrackMemoryListener {
    fun onLeakActivity(activity: String?, count: Int)
    fun onCurrentMemoryCost(trackMemoryInfo: TrackMemoryInfo?)
}

private fun collectMemoryInfo(application: Application): TrackMemoryInfo {
    if (TextUtils.isEmpty(display)) {
        display =
            "" + application.resources.displayMetrics.widthPixels + "*" + application.resources.displayMetrics.heightPixels
    }
    val activityManager =
        application.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
    // 系统内存
    val memoryInfo = ActivityManager.MemoryInfo()
    activityManager.getMemoryInfo(memoryInfo)
    val systemMemory = SystemMemory()
    systemMemory.availMem = memoryInfo.availMem shr 20
    systemMemory.totalMem = memoryInfo.totalMem shr 20
    systemMemory.lowMemory = memoryInfo.lowMemory
    systemMemory.threshold = memoryInfo.threshold shr 20

    //java内存
    val rt = Runtime.getRuntime()

    //进程Native内存
    val appMemory = AppMemory()
    val debugMemoryInfo = Debug.MemoryInfo()
    Debug.getMemoryInfo(debugMemoryInfo)
    appMemory.nativePss = (debugMemoryInfo.nativePss shr 10).toLong()
    appMemory.dalvikPss = (debugMemoryInfo.dalvikPss shr 10).toLong()
    appMemory.totalPss = (debugMemoryInfo.totalPss shr 10).toLong()
    appMemory.mMemoryInfo = debugMemoryInfo
    val trackMemoryInfo = TrackMemoryInfo()
    trackMemoryInfo.systemMemoryInfo = systemMemory
    trackMemoryInfo.appMemory = appMemory
    trackMemoryInfo.procName = getProcessName(application)
    trackMemoryInfo.display = display
    trackMemoryInfo.activityCount = getSize()
    return trackMemoryInfo
}

private fun mallocBigMem() {
    val leakHelpBytes = ByteArray(4 * 1024 * 1024)
    var i = 0
    while (i < leakHelpBytes.size) {
        leakHelpBytes[i] = 1
        i += 1024
    }
}

companion object {
    @Volatile
    private var sInstance: MemoryLeakTrack? = null
    @JvmStatic
    val instance: MemoryLeakTrack?
        get() {
            if (sInstance == null) {
                synchronized(MemoryLeakTrack::class.java) {
                    if (sInstance == null) {
                        sInstance = MemoryLeakTrack()
                    }
                }
            }
            return sInstance
        }
    private var display: String? = null
}

class Collie private constructor() {
private val mHandler: Handler = Handler(CollieHandlerThread.looper)
private val mITrackListener: ITrackFpsListener
private val mITrackMemoryLeakListener: ITrackMemoryListener
private val mIBatteryListener: IBatteryListener
private val mCollieListeners: MutableList = ArrayList()
private val mActivityLifecycleCallbacks = HashSet<Application.ActivityLifecycleCallbacks>()
fun addActivityLifecycleCallbacks(callbacks: Application.ActivityLifecycleCallbacks) {
mActivityLifecycleCallbacks.add(callbacks)
}

fun removeActivityLifecycleCallbacks(callbacks: Application.ActivityLifecycleCallbacks) {
    mActivityLifecycleCallbacks.remove(callbacks)
}

private val mActivityLifecycleCallback: Application.ActivityLifecycleCallbacks =
    object : Application.ActivityLifecycleCallbacks {
        override fun onActivityCreated(activity: Activity, bundle: Bundle?) {
            push(activity)
            for (item in mActivityLifecycleCallbacks) {
                item.onActivityCreated(activity, bundle)
            }
        }

        override fun onActivityStarted(activity: Activity) {
            markStart()
            for (item in mActivityLifecycleCallbacks) {
                item.onActivityStarted(activity)
            }
        }

        override fun onActivityResumed(activity: Activity) {
            for (item in mActivityLifecycleCallbacks) {
                item.onActivityResumed(activity)
            }
        }

        override fun onActivityPaused(activity: Activity) {
            for (item in mActivityLifecycleCallbacks) {
                item.onActivityPaused(activity)
            }
        }

        override fun onActivityStopped(activity: Activity) {
            markStop()
            for (item in mActivityLifecycleCallbacks) {
                item.onActivityStopped(activity)
            }
        }

        override fun onActivitySaveInstanceState(activity: Activity, bundle: Bundle) {
            for (item in mActivityLifecycleCallbacks) {
                item.onActivitySaveInstanceState(activity, bundle)
            }
        }

        override fun onActivityDestroyed(activity: Activity) {
            for (item in mActivityLifecycleCallbacks) {
                item.onActivityDestroyed(activity)
            }
            pop(activity)
        }
    }

fun init(
    application: Application,
    config: Config,
    listener: CollieListener
) {
    application.registerActivityLifecycleCallbacks(mActivityLifecycleCallback)
    mCollieListeners.add(listener)
    if (config.useTrafficTrack) {
        trafficStatsListener = object : ITrackTrafficStatsListener {
            override fun onTrafficStats(activity: Activity, value: Long) {
                for (collieListener in mCollieListeners) {
                    collieListener.onTrafficStats(activity, value)
                }
            }
        }
        TrafficStatsTracker.startTrack(application)
    }
    // 开始内存监测
    if (config.useMemTrack) {
        MemoryLeakTrack.instance!!.startTrack(application)
        MemoryLeakTrack.instance!!.addOnMemoryLeakListener(mITrackMemoryLeakListener)
    }
    if (config.useFpsTrack) {
        FpsTracker.getInstance().setTrackerListener(mITrackListener)
        FpsTracker.getInstance().startTrack(application)
    }
    if (config.showDebugView) {
        DebugHelper.instance!!.startTrack(application)
    }
    if (config.useBatteryTrack) {
        BatteryStatsTracker.instance!!.addBatteryListener(mIBatteryListener)
        BatteryStatsTracker.instance!!.startTrack(application)
    }
    if (config.useStartUpTrack) {
        iLaunchTrackListener = object : ILaunchTrackListener {
            override fun onActivityFocusableCost(
                activity: Activity?,
                duration: Long,
                finishNow: Boolean
            ) {
                for (collieListener in mCollieListeners) {
                    collieListener.onActivityFocusableCost(activity, duration, finishNow)
                }
            }

            override fun onAppColdLaunchCost(duration: Long, processName: String?) {
                for (collieListener in mCollieListeners) {
                    collieListener.onAppColdLaunchCost(duration, processName)
                }
            }

            override fun onActivityLaunchCost(
                activity: Activity?,
                duration: Long,
                finishNow: Boolean
            ) {
                for (collieListener in mCollieListeners) {
                    collieListener.onActivityLaunchCost(activity, duration, finishNow)
                }
            }
        }
        LauncherTracker.startTrack(application)
    }
}

fun stop(application: Application) {
    application.unregisterActivityLifecycleCallbacks(mActivityLifecycleCallback)
    CollieHandlerThread.quitSafely()
}

companion object {
    @Volatile
    private var sInstance: Collie? = null

    @JvmStatic
    val instance: Collie
        get() {
            if (sInstance == null) {
                synchronized(Collie::class.java) {
                    if (sInstance == null) {
                        sInstance = Collie()
                    }
                }
            }
            return sInstance!!
        }
}

init {
    mITrackListener = object : ITrackFpsListener {
        override fun onFpsTrack(
            activity: Activity,
            currentCostMils: Long,
            currentDropFrame: Long,
            isInFrameDraw: Boolean,
            averageFps: Long
        ) {
            val currentFps =
                if (currentCostMils == 0L) 60 else Math.min(60, 1000 / currentCostMils)
            mHandler.post {
                if (currentDropFrame > 1) DebugHelper.instance!!.update(
                    """实时fps $currentFps

丢帧 $currentDropFrame
1s平均fps $averageFps
本次耗时 $currentCostMils"“”
)
for (collieListener in mCollieListeners) {
collieListener.onFpsTrack(
activity,
currentCostMils,
currentDropFrame,
isInFrameDraw,
averageFps
)
}
}
}

        override fun onANRAppear(activity: Activity?) {
            for (collieListener in mCollieListeners) {
                collieListener.onANRAppear(activity)
            }
        }
    }
    mITrackMemoryLeakListener = object : ITrackMemoryListener {
        override fun onLeakActivity(activity: String?, count: Int) {

// Log.v(“Collie”, "内存泄露 " + activity + " 数量 " + count);
for (collieListener in mCollieListeners) {
collieListener.onLeakActivity(activity, count)
}
}

        override fun onCurrentMemoryCost(trackMemoryInfo: TrackMemoryInfo?) {

// Log.v(“Collie”, "内存 " + trackMemoryInfo.procName + " java内存 "
// + trackMemoryInfo.appMemory.dalvikPss + " native内存 " +
// trackMemoryInfo.appMemory.nativePss);
for (collieListener in mCollieListeners) {
collieListener.onCurrentMemoryCost(trackMemoryInfo)
}
}
}
mIBatteryListener = object : IBatteryListener {
override fun onBatteryCost(batteryInfo: BatteryInfo?) {
for (collieListener in mCollieListeners) {
collieListener.onBatteryCost(batteryInfo)
}
}
}
}
}

public class LabApplication extends Application {

public static long sLaunchCost;
@Override
public void onCreate() {
    super.onCreate();
    sApplication = this;
    Router.initBrowserRouter(this);
    Router.initActivityRouter(getApplicationContext());
    Collie.getInstance().init(this, new Config(false, true, true, true, true, true), new CollieListener() {

        @Override
        public void onActivityFocusableCost(Activity activity, long duration, boolean finishNow) {
            Log.v("Collie", "Activity 获取焦点" + activity + " "+ duration   );

        }

        @Override
        public void onTrafficStats(Activity activity, long value) {
            Log.v("Collie", "" + activity.getClass().getSimpleName() + " 流量消耗 " + value * 1.0f / (1024 * 1024) + "M");

        }

        @Override
        public void onBatteryCost(BatteryInfo batteryInfo) {
            Log.v("Collie", " 电量流量消耗 " + batteryInfo.cost);

        }

        @Override
        public void onAppColdLaunchCost(long duration, String processName) {
            Log.v("Collie", "启动耗时 " + duration + " processName " + processName);
            sLaunchCost = duration;
        }

        @Override
        public void onActivityLaunchCost(Activity activity, long duration, boolean finishNow) {
            Log.v("Collie", "activity启动耗时 " + activity + " " + duration + " finishNow " + finishNow);
        }

        @Override
        public void onLeakActivity(String activity, int count) {
            Log.v("Collie", "内存泄露 " + activity + " 数量 " + count);
        }

        @Override
        public void onCurrentMemoryCost(TrackMemoryInfo trackMemoryInfo) {
            Log.v("Collie", "内存  " + trackMemoryInfo.procName + " java内存  "
                    + trackMemoryInfo.appMemory.dalvikPss + " native内存  " +
                    trackMemoryInfo.appMemory.nativePss);
        }

        @Override
        public void onFpsTrack(Activity activity, long currentCostMils, long currentDropFrame, boolean isInFrameDraw, long averageFps) {
            if (currentDropFrame >= 2)
                Log.v("Collie", "Activity " + activity + " 掉帧 " + currentDropFrame + " 是否因为Choro 绘制掉帧 " + isInFrameDraw + " 1s 平均帧率" + averageFps);
        }

        @Override
        public void onANRAppear(Activity activity) {
            Log.v("Collie", "Activity " + activity + " ANR  ");

        }

    });
}

private static Application sApplication;

public static Application getContext() {
    return sApplication;
}

public static void startTrace(Context context) {
    File file = new File(context.getExternalFilesDir("android"), SystemClock.uptimeMillis()+"methods.trace");
    Debug.startMethodTracing(file.getAbsolutePath(), 300 * 1024 * 1024);
}

}

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值