Leakcanary主页
由于最新的v1.5.1支持到了O版本,使用了O版本的API,在N上各种编译错误,所以本文用到的版本是v1.5。下载地址
本文以development/samples/HelloActivity为示例。示例下载地址,
包含本文提到的所以文件。
将Leakcanary文件夹放到development/samples目录,需要修改HelloActivity的Android.mk、AndroidManifest.xml和对应的Application.java
由于依赖haha这个库,所以需要另外下载 下载地址
放到leakcanary工程的libs目录下。在示例代码中已经包含。
准备好就开动吧。
1.修改Android.mk
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := samples
# Only compile source java files in this apk.
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_RESOURCE_DIR += $(LOCAL_PATH)/res
LOCAL_AAPT_FLAGS := --auto-add-overlay
LOCAL_AAPT_FLAGS += --extra-packages com.squareup.leakcanary
LOCAL_STATIC_JAVA_LIBRARIES += libhaha
LOCAL_RESOURCE_DIR += $(LOCAL_PATH)/../leakcanary-1.5/leakcanary-android/src/main/res
LOCAL_SRC_FILES += $(call all-java-files-under, ../leakcanary-1.5/leakcanary-analyzer/src/main/java)
LOCAL_SRC_FILES += $(call all-java-files-under, ../leakcanary-1.5/leakcanary-android/src/main/java)
LOCAL_SRC_FILES += $(call all-java-files-under, ../leakcanary-1.5/leakcanary-watcher/src/main/java)
LOCAL_SRC_FILES += $(call all-java-files-under, ../leakcanary-1.5/leakcanary-android-gen/src/main/java)
LOCAL_PROGUARD_ENABLED := disabled
LOCAL_PACKAGE_NAME := HelloActivity
LOCAL_SDK_VERSION := current
include $(BUILD_PACKAGE)
include $(CLEAR_VARS)
LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES := libhaha:../leakcanary-1.5/libs/haha-2.0.3.jar
include $(BUILD_MULTI_PREBUILT)
# Use the following include to make our test apk.
include $(call all-makefiles-under,$(LOCAL_PATH))
修改Android.mk,编译后会报几个错误。
development/samples/HelloActivity/../leakcanary-1.5/leakcanary-android/src/main/res/values/leak_canary_public.xml:19: error: No 'id' attribute supplied , and no previous id defined in this file.
development/samples/HelloActivity/../leakcanary-1.5/leakcanary-android/src/main/res/values/leak_canary_public.xml:20: error: No 'id' attribute supplied , and no previous id defined in this file.
development/samples/HelloActivity/../leakcanary-1.5/leakcanary-android/src/main/res/values/leak_canary_public.xml:21: error: No 'id' attribute supplied , and no previous id defined in this file.
ERROR: /work2/mtk6737_N_gerrit/development/samples/leakcanary-1.5/leakcanary-android/src/main/java/com/squareup/leakcanary/internal/DisplayLeakActivity.java:66: The import com.squareup.leakcanary.BuildConfig cannot be resolved
ERROR: /work2/mtk6737_N_gerrit/development/samples/leakcanary-1.5/leakcanary-android/src/main/java/com/squareup/leakcanary/internal/DisplayLeakActivity.java:67: The import com.squareup.leakcanary.BuildConfig cannot be resolved
ERROR: /work2/mtk6737_N_gerrit/development/samples/leakcanary-1.5/leakcanary-android/src/main/java/com/squareup/leakcanary/internal/DisplayLeakActivity.java:271: LIBRARY_VERSION cannot be resolved to a variable
ERROR: /work2/mtk6737_N_gerrit/development/samples/leakcanary-1.5/leakcanary-android/src/main/java/com/squareup/leakcanary/internal/DisplayLeakActivity.java:273: GIT_SHA cannot be resolved to a variable
ERROR: /work2/mtk6737_N_gerrit/development/samples/leakcanary-1.5/leakcanary-android/src/main/java/com/squareup/leakcanary/LeakCanary.java:28: The import com.squareup.leakcanary.BuildConfig cannot be resolved
ERROR: /work2/mtk6737_N_gerrit/development/samples/leakcanary-1.5/leakcanary-android/src/main/java/com/squareup/leakcanary/LeakCanary.java:29: The import com.squareup.leakcanary.BuildConfig cannot be resolved
ERROR: /work2/mtk6737_N_gerrit/development/samples/leakcanary-1.5/leakcanary-android/src/main/java/com/squareup/leakcanary/LeakCanary.java:95: LIBRARY_VERSION cannot be resolved to a variable
ERROR: /work2/mtk6737_N_gerrit/development/samples/leakcanary-1.5/leakcanary-android/src/main/java/com/squareup/leakcanary/LeakCanary.java:95: GIT_SHA cannot be resolved to a variable
ERROR: /work2/mtk6737_N_gerrit/development/samples/leakcanary-1.5/leakcanary-android/src/main/java/com/squareup/leakcanary/LeakCanary.java:121: LIBRARY_VERSION cannot be resolved to a variable
ERROR: /work2/mtk6737_N_gerrit/development/samples/leakcanary-1.5/leakcanary-android/src/main/java/com/squareup/leakcanary/LeakCanary.java:123: GIT_SHA cannot be resolved to a variable
ERROR: /work2/mtk6737_N_gerrit/development/samples/HelloActivity/src/com/example/android/helloactivity/HelloActivity.java:38: hello_activity cannot be resolved or is not a field
BuildConfig是在IDE进行编译生成的,因此只能手动创建一个BuildConfig.java。在leakcanary工程新建一个leakcanary-android-gen/src/main/java/com/squareup/leakcanary目录,接着新建一个BuildConfig.java。
内容包含以下代码 (没研究过这个两个字符串的影响,随意赋值了):
package com.squareup.leakcanary;
public final class BuildConfig {
public static String GIT_SHA = "GIT_SHA";
public static String LIBRARY_VERSION = "LIBRARY_VERSION";
}
记得修改Android.mk,添加LOCAL_SRC_FILES += $(call all-java-files-under,../leakcanary-1.5/leakcanary-android-gen/src/main/java
com.android.sched.scheduler.RunnerProcessException: Error during 'TypeGenericSignatureSplitter' runner on 'class com.squareup.haha.guava.collect.AbstractMapBasedMultimap$WrappedSortedSet (AbstractMapBasedMultimap.java:0-0)'
at com.android.sched.scheduler.ScheduleInstance.runWithLog(ScheduleInstance.java:163)
at com.android.sched.scheduler.MultiWorkersScheduleInstance$SequentialTask.process(MultiWorkersScheduleInstance.java:442)
at com.android.sched.scheduler.MultiWorkersScheduleInstance$Worker.run(MultiWorkersScheduleInstance.java:162)
Caused by: java.lang.reflect.GenericSignatureFormatError
at com.android.jack.signature.GenericSignatureParser.expect(GenericSignatureParser.java:371)
at com.android.jack.signature.GenericSignatureParser.parseClassTypeSignature(GenericSignatureParser.java:236)
at com.android.jack.signature.GenericSignatureParser.parseClassSignature(GenericSignatureParser.java:136)
at com.android.jack.signature.GenericSignatureParser.parseClassSignature(GenericSignatureParser.java:99)
at com.android.jack.transformations.ast.string.TypeGenericSignatureSplitter.getSplittedSignature(TypeGenericSignatureSplitter.java:70)
at com.android.jack.transformations.ast.string.TypeGenericSignatureSplitter.run(TypeGenericSignatureSplitter.java:47)
at com.android.jack.transformations.ast.string.TypeGenericSignatureSplitter.run(TypeGenericSignatureSplitter.java:37)
at com.android.sched.scheduler.ScheduleInstance.runWithLog(ScheduleInstance.java:161)
... 2 more
Internal compiler error (version 1.2-rc4 'Carnac' (298900 f95d7bdecfceb327f9d201a1348397ed8a843843 by [email protected])).
Warning: This may have produced partial or corrupted output.
需要在mk里关掉代码混淆,LOCAL_PROGUARD_ENABLED := disabled
2. 修改AndroidManifest.xml
需要注意几个点:
- 添加读写外部存储的权限,在安装应用后手动打开权限。
- 将新添加leakcanary的activity和service属性android:enabled修改为true
- 如果没有自定义application,需要手动创建一个。
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.android.helloactivity">
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application android:label="Hello, Activity!"
android:name="com.example.android.helloactivity.MyApp">
<activity android:name="HelloActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
intent-filter>
activity>
<service
android:name="com.squareup.leakcanary.internal.HeapAnalyzerService"
android:process=":leakcanary"
android:enabled="true"
/>
<service
android:name="com.squareup.leakcanary.DisplayLeakService"
android:enabled="true"
/>
<activity
android:theme="@style/leak_canary_LeakCanary.Base"
android:name="com.squareup.leakcanary.internal.DisplayLeakActivity"
android:enabled="true"
android:label="@string/leak_canary_display_activity_label"
android:icon="@drawable/leak_canary_icon"
android:taskAffinity="com.squareup.leakcanary"
>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
intent-filter>
activity>
<activity
android:theme="@style/leak_canary_Theme.Transparent"
android:name="com.squareup.leakcanary.internal.RequestStoragePermissionActivity"
android:taskAffinity="com.squareup.leakcanary"
android:enabled="true"
android:icon="@drawable/leak_canary_icon"
android:label="@string/leak_canary_storage_permission_activity_label"
/>
application>
manifest>
3. 修改Application
package com.example.android.helloactivity;
import android.app.Application;
import com.squareup.leakcanary.LeakCanary;
public class MyApp extends Application{
@Override
public void onCreate() {
super.onCreate();
if (LeakCanary.isInAnalyzerProcess(this)) {
// This process is dedicated to LeakCanary for heap analysis.
// You should not init your app in this process.
return;
}
LeakCanary.install(this);
}
}
4.测试
在HelloActivity.java:onCreate()方法里添加
new Handler().postDelayed(new Runnable(){
public void run(){
new Handler().postDelayed(this, 1000);
}
}, 1000);
使Activity实例一直被Runnable持有,导致内存泄露。
打开应用后退出,过一会就会生成报告了。
有时候一直无法生成报告,输出如下log,
D LeakCanary: Could not dump heap, previous analysis still is in progress.
删除/sdcard/Download/leakcanary-com.example.android.helloactivity/目录下包含pending字符串的文件,再重新抓取一次。