beg*_*ner 6 android memory-leaks in-app-billing leakcanary play-billing-library
MainActivity对于新项目来说很简单
public class MainActivity extends AppCompatActivity {\n BillingClient billingClient;\n PurchasesUpdatedListener purchasesUpdatedListener = new PurchasesUpdatedListener() {\n @Override\n public void onPurchasesUpdated(@NonNull BillingResult billingResult, @Nullable List<Purchase> list) {\n\n }\n};\n@Override\nprotected void onCreate(Bundle savedInstanceState) {\n super.onCreate(savedInstanceState);\n setContentView(R.layout.activity_main);\n}\n\n\n@Override\nprotected void onStart() {\n super.onStart();\n billingClient = BillingClient.newBuilder(this)\n .enablePendingPurchases()\n .setListener(purchasesUpdatedListener)\n .build();\n billingClient.startConnection(new BillingClientStateListener() {\n @Override\n public void onBillingSetupFinished(@NonNull BillingResult billingResult) {\n\n }\n\n @Override\n public void onBillingServiceDisconnected() {\n\n }\n });\n}\n\n@Override\nprotected void onStop() {\n super.onStop();\n billingClient.endConnection();\n}\nRun Code Online (Sandbox Code Playgroud)\n在 Gradle 文件中:
\n ....\n implementation 'com.android.billingclient:billing:3.0.2'\n debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.5'\nRun Code Online (Sandbox Code Playgroud)\n金丝雀输出(1 个不同的泄漏):
\n\xe2\x94\xac\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\n\xe2\x94\x82 GC Root: Input or output parameters in native code\n\xe2\x94\x82\n\xe2\x94\x9c\xe2\x94\x80 android.os.MessageQueue instance\n\xe2\x94\x82 Leaking: NO (MessageQueue#mQuitting is false)\n\xe2\x94\x82 HandlerThread: "main"\n\xe2\x94\x82 \xe2\x86\x93 MessageQueue.mMessages\n\xe2\x94\x82 ~~~~~~~~~\n\xe2\x94\x9c\xe2\x94\x80 android.os.Message instance\n\xe2\x94\x82 Leaking: UNKNOWN\n\xe2\x94\x82 Retaining 116109 bytes in 1346 objects\n\xe2\x94\x82 Message.what = 0\n\xe2\x94\x82 Message.when = 104320925 (14773 ms after heap dump)\n\xe2\x94\x82 Message.obj = null\n\xe2\x94\x82 Message.callback = instance @315501888 of com.android.billingclient.api.zzr\n\xe2\x94\x82 \xe2\x86\x93 Message.callback\n\xe2\x94\x82 ~~~~~~~~\n\xe2\x94\x9c\xe2\x94\x80 com.android.billingclient.api.zzr instance\n\xe2\x94\x82 Leaking: UNKNOWN\n\xe2\x94\x82 Retaining 116024 bytes in 1344 objects\n\xe2\x94\x82 \xe2\x86\x93 zzr.zzb\n\xe2\x94\x82 ~~~\n\xe2\x94\x9c\xe2\x94\x80 com.android.billingclient.api.zzag instance\n\xe2\x94\x82 Leaking: UNKNOWN\n\xe2\x94\x82 Retaining 115980 bytes in 1342 objects\n\xe2\x94\x82 \xe2\x86\x93 zzag.zza\n\xe2\x94\x82 ~~~\n\xe2\x94\x9c\xe2\x94\x80 com.android.billingclient.api.zzah instance\n\xe2\x94\x82 Leaking: UNKNOWN\n\xe2\x94\x82 Retaining 115968 bytes in 1341 objects\n\xe2\x94\x82 \xe2\x86\x93 zzah.zza\n\xe2\x94\x82 ~~~\n\xe2\x94\x9c\xe2\x94\x80 com.android.billingclient.api.BillingClientImpl instance\n\xe2\x94\x82 Leaking: UNKNOWN\n\xe2\x94\x82 Retaining 115939 bytes in 1339 objects\n\xe2\x94\x82 zze instance of android.app.Application\n\xe2\x94\x82 zzf instance of android.app.Application\n\xe2\x94\x82 \xe2\x86\x93 BillingClientImpl.zzd\n\xe2\x94\x82 ~~~\n\xe2\x94\x9c\xe2\x94\x80 com.android.billingclient.api.zze instance\n\xe2\x94\x82 Leaking: UNKNOWN\n\xe2\x94\x82 Retaining 115881 bytes in 1338 objects\n\xe2\x94\x82 zza instance of android.app.Application\n\xe2\x94\x82 \xe2\x86\x93 zze.zzb\n\xe2\x94\x82 ~~~\n\xe2\x94\x9c\xe2\x94\x80 com.android.billingclient.api.zzd instance\n\xe2\x94\x82 Leaking: UNKNOWN\n\xe2\x94\x82 Retaining 115865 bytes in 1337 objects\n\xe2\x94\x82 \xe2\x86\x93 zzd.zzb\n\xe2\x94\x82 ~~~\n\xe2\x94\x9c\xe2\x94\x80 com.example.billingclientleak.MainActivity$1 instance\n\xe2\x94\x82 Leaking: UNKNOWN\n\xe2\x94\x82 Retaining 115841 bytes in 1336 objects\n\xe2\x94\x82 Anonymous class implementing com.android.billingclient.api.\n\xe2\x94\x82 PurchasesUpdatedListener\n\xe2\x94\x82 this$0 instance of com.example.billingclientleak.MainActivity with\n\xe2\x94\x82 mDestroyed = true\n\xe2\x94\x82 \xe2\x86\x93 MainActivity$1.this$0\n\xe2\x94\x82 ~~~~~~\n\xe2\x95\xb0\xe2\x86\x92 com.example.billingclientleak.MainActivity instance\n\xe2\x80\x8b Leaking: YES (ObjectWatcher was watching this because com.example.\n\xe2\x80\x8b billingclientleak.MainActivity received Activity#onDestroy() callback and\n\xe2\x80\x8b Activity#mDestroyed is true)\n\xe2\x80\x8b Retaining 115829 bytes in 1335 objects\n\xe2\x80\x8b key = d55540b8-a7aa-4fa1-9eb1-ed14135a9a8d\n\xe2\x80\x8b watchDurationMillis = 5135\n\xe2\x80\x8b retainedDurationMillis = 133\n\xe2\x80\x8b mApplication instance of android.app.Application\n\xe2\x80\x8b mBase instance of androidx.appcompat.view.ContextThemeWrapper, not\n\xe2\x80\x8b wrapping known Android context\n\nMETADATA\n\nBuild.VERSION.SDK_INT: 27\nBuild.MANUFACTURER: Google\nLeakCanary version: 2.5\nApp process name: com.example.billingclientleak\nStats: LruCache[maxSize=3000,hits=634,misses=23227,hitRate=2%]\nRandomAccess[bytes=1191354,reads=23227,travel=6396792403,range=8851265,size=1152\n9733]\nAnalysis duration: 7997 ms```\nRun Code Online (Sandbox Code Playgroud)\n