Android 通过OnConfiguration更改的MemoryLeak()

Android 通过OnConfiguration更改的MemoryLeak(),android,memory-leaks,Android,Memory Leaks,我有一个AsyncTask,如果用户执行诸如切换颜色之类的配置,我需要重新启动该任务 当他这样做时,我会像这样开始异步任务: myWorkerClass.clearMemory(); myWorkerClass = new WorkerClass(getApplicationContext(), gv, searchbar, width, scaleButtonText); myWorkerClass.execute(); 在AsyncTask中,我向EditText添加了一个

我有一个AsyncTask,如果用户执行诸如切换颜色之类的配置,我需要重新启动该任务

当他这样做时,我会像这样开始异步任务:

myWorkerClass.clearMemory();
    myWorkerClass = new WorkerClass(getApplicationContext(), gv, searchbar, width, scaleButtonText);
    myWorkerClass.execute();
在AsyncTask中,我向EditText添加了一个onTextChangeListener!这会导致后面的内存崩溃

为了防止内存丢失,我的AsyncTask中有一个方法可以删除ContextChangedListener:

除了旋转设备外,其他一切都正常工作。旋转设备时,仅在OnConfiguration Changed中执行此操作:

正如你所看到的,我做的和用户改变颜色一样。但在旋转设备上,我正在泄漏内存,在切换颜色时,我没有

这是在切换颜色之后:

这是在旋转屏幕几次后,记得我做的与切换颜色完全相同:

以下是堆转储中的泄漏嫌疑犯:

这是我的支配树:

为什么我知道问题出在ContextChangeListener上

因为如果我在我的EditText out中添加一个ContextChangedListener,一切都正常。没有内存泄漏

我的问题:

当我以完全相同的方式启动asynctask并在asynctask中执行完全相同的操作时,为什么旋转更改会泄漏内存,而颜色更改不会泄漏内存

我搜索了一下:

但我不知道这是否是我的问题。旋转必须做一些不同的事情,比如创建一个新的活动,因为它创建了一个对我的edittext的新引用。正因为如此,他无法删除旧的ontextchangeelistener

请理解。我不想公开我的全部代码。但我认为在这种情况下,这是没有必要的

旋转必须做一些不同的事情,比如创建一个新的活动,因为它创建了一个对我的edittext的新引用

确切地说,它会破坏您当前的活动并创建一个新的活动。如果搜索栏是您的异步任务的成员变量,那么考虑将其放入弱引用:

WeakReference<SearchBar> searchbarPtr; 
然后使用searchBarPtr.get进行访问,但检查其是否为null,如果为null,则表示由于配置更改而对其进行了垃圾收集

还请记住,不要将AsyncTask作为活动的内部类。如果是嵌套的,则将其设置为静态。否则,asynctask将保留对活动的引用,并防止其被销毁,直到其线程结束

不幸的是,在所有情况下都能正确地工作是相当困难和耗时的


希望没有人会建议通过android:configChanges阻止您的活动被破坏,在轮换期间实施正确的活动行为将防止它在不太常见的活动生命周期中崩溃/泄漏,而android:configChanges无法阻止这些情况。

在android中,轮换会破坏您当前的活动以开始新的活动。 为了避免这种情况,您可以在清单文件中添加android:configChanges=orientation | screenSize

以下是避免旋转更改时内存泄漏的提示

不要保留对上下文活动的长期引用对活动的引用应具有与活动本身相同的生命周期 尝试使用上下文应用程序而不是上下文活动 避免活动中的非静态内部类如果不控制它们的生命周期,请使用静态内部类并对内部活动进行弱引用。这个问题的解决方案是使用一个静态的内部类和外部类的WeakReference,例如在ViewRoot及其W内部类中 垃圾收集器不是防止内存泄漏的保险
来源:

谢谢您的回复。是的,我将searchbarfrom my activity的引用放在AsyncTask上,它不是我activity的内部类。所以我从来没有和WeakReference一起工作过。你能给我一个快速的解决方案吗?如何实现这一点?我知道这并不容易,因为我没有提供任何代码。但也许我们可以试一试?不管怎么说,如果他正在我的搜索栏上搜索,那么我的清晰记忆一定是无用的,对吧?因为通过收集搜索栏,他还收集了ContextChangeListener,对吗?@MMike我添加了关于WeakReference用法的简短伪代码表示。同样在Activity.onCreate中,您可以在AsyncTask中更新搜索栏引用,但您必须以某种方式保留对AsyncTask的引用,方法是使用不推荐的OnRetainOnConfiguration实例,或使用带有保留片段的新aproach。这对我来说太大了,我将尝试使用WeakReference并将WeakReference放在AsyncTask中,并检查它是否为null。如果为空,我需要对搜索栏进行新的引用,并在必要时将其再次放入WeakReference?@MMike Yes,在Activity.onCreate内进行新引用。根据异步任务正在执行的操作,您可以放弃它并在Activity.onCreate after rotation中创建一个新的异步任务——这是我的首选。在onDestroy cancel current AsyncTask中,如果当前AsyncTask已被取消,则可以在其中使用isCancelled进行检查
如果为true,则在onPostExecute中停止所有操作并取消处理。如果您的异步任务正在做一些事情,那么考虑使用服务——IE.ItnService,和I.使用广播来显示活动的进展。谢谢您的响应Lazy Ninja。我只传递ApplicationContext,我的AsyncTask不是活动的内部类,我唯一的内存泄漏是EditTextsearchbar的addTextChangeListener。我不想消除旋转,我想消除泄漏。但我不知道该怎么做。在活动被销毁和重新创建之前,是否没有调用get的方法?更新:=方向|屏幕大小没有帮助。我又在泄漏内存了@MMike在活动被销毁和重新创建之前是否没有调用get的方法?onDestroy->在它被销毁之前,onCreate->将为新的重新创建的活动调用。
myWorkerClass.clearMemory();
            myWorkerClass = new WorkerClass(getApplicationContext(), gv, searchbar, width, scaleButtonText);
            myWorkerClass.execute();
WeakReference<SearchBar> searchbarPtr;