Android系统App中使用Leakcanary

转载自:http://blog.csdn.net/abc_1234d/article/details/72478385

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:= (callmydir)include ( c a l l m y − d i r ) i n c l u d e (CLEAR_VARS)

LOCAL_MODULE_TAGS := samples

Only compile source java files in this apk.

LOCAL_SRC_FILES := (callalljavafilesunder,src)LOCALRESOURCEDIR+= ( c a l l a l l − j a v a − f i l e s − u n d e r , s r c ) L O C A L R E S O U R C E D I R + = (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 += (LOCALPATH)/../leakcanary1.5/leakcanaryandroid/src/main/resLOCALSRCFILES+= ( L O C A L P A T H ) / . . / l e a k c a n a r y − 1.5 / l e a k c a n a r y − a n d r o i d / s r c / m a i n / r e s L O C A L S R C F I L E S + = (call all-java-files-under, ../leakcanary-1.5/leakcanary-analyzer/src/main/java)
LOCAL_SRC_FILES += (callalljavafilesunder,../leakcanary1.5/leakcanaryandroid/src/main/java)LOCALSRCFILES+= ( c a l l a l l − j a v a − f i l e s − u n d e r , . . / l e a k c a n a r y − 1.5 / l e a k c a n a r y − a n d r o i d / s r c / m a i n / j a v a ) L O C A L S R C F I L E S + = (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 (CLEARVARS)LOCALPREBUILTSTATICJAVALIBRARIES:=libhaha:../leakcanary1.5/libs/haha2.0.3.jarinclude ( C L E A R V A R S ) L O C A L P R E B U I L T S T A T I C J A V A L I B R A R I E S := l i b h a h a : . . / l e a k c a n a r y − 1.5 / l i b s / h a h a − 2.0.3. j a r i n c l u d e (BUILD_MULTI_PREBUILT)

Use the following include to make our test apk.

include (callallmakefilesunder, ( c a l l a l l − m a k e f i l e s − u n d e r , (LOCAL_PATH))

修改Android.mk,编译后会报几个错误。

资源错误,直接删除leak_canary_public.xml。
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.

找不到BuildConfig、LIBRARY_VERSION 和GIT_SHA。
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

报RunnerProcessException。
com.android.sched.scheduler.RunnerProcessException: Error during ‘TypeGenericSignatureSplitter’ runner on ‘class com.squareup.haha.guava.collect.AbstractMapBasedMultimap WrappedSortedSet(AbstractMapBasedMultimap.java:00)atcom.android.sched.scheduler.ScheduleInstance.runWithLog(ScheduleInstance.java:163)atcom.android.sched.scheduler.MultiWorkersScheduleInstance W r a p p e d S o r t e d S e t ( A b s t r a c t M a p B a s e d M u l t i m a p . j a v a : 0 − 0 ) ′ a t c o m . a n d r o i d . s c h e d . s c h e d u l e r . S c h e d u l e I n s t a n c e . r u n W i t h L o g ( S c h e d u l e I n s t a n c e . j a v a : 163 ) a t c o m . a n d r o i d . s c h e d . s c h e d u l e r . M u l t i W o r k e r s S c h e d u l e I n s t a n c e 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 android-jack-team@google.com)).
Warning: This may have produced partial or corrupted output.

需要在mk里关掉代码混淆,LOCAL_PROGUARD_ENABLED := disabled

  1. 修改AndroidManifest.xml

需要注意几个点:
- 添加读写外部存储的权限,在安装应用后手动打开权限。
- 将新添加leakcanary的activity和service属性android:enabled修改为true
- 如果没有自定义application,需要手动创建一个。

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.android.helloactivity">
    <!-- To store the heap dumps and leak analysis results. -->
    <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>
  1. 修改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字符串的文件,再重新抓取一次。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值