理解onTrimMemory(int level)
我最近读了这篇关于pipe理你的应用程序内存的文章 ,我强烈build议阅读它,如果你是一个AndroidDev,并从来没有这样做。
有很多好的做法,我从来没有碰到过的一件事是系统在每个Activity / Fragment上调用的onTrimMemory(int level)方法来通知应该释放或释放内存的事件。
这篇文章的引用如下:
请注意,只有在您的应用程序进程的所有UI组件被用户隐藏后,您的应用才会收到带有TRIM_MEMORY_UI_HIDDEN的onTrimMemory()callback 。 这与onStop()callback截然不同,当Activity实例变为隐藏时会调用该callback,即使用户移动到应用中的其他活动时也会发生这种情况。 因此,尽pipe您应该实现onStop()来释放活动资源(如networking连接)或取消注册广播接收器, 但通常不应释放您的UI资源,直到您收到onTrimMemory(TRIM_MEMORY_UI_HIDDEN) 。 这确保了如果用户从应用中的其他活动导航回来,您的UI资源仍然可以快速恢复活动。
我真的很有兴趣在我的应用程序中实现一个良好的内存pipe理,所以我期待以正确的方式实现onTrimMemory() 。
我只有几个问题:
-
在onStop()之后调用onTrimMemory(TRIM_MEMORY_UI_HIDDEN )?
-
在这种情况下,“释放你的UI资源”是什么意思? 只是为了清理Bitmapcaching,或者实际上删除并销毁视图树中的每个视图? 我通常在onDestroy()或onDestroyView()方法中销毁视图,我现在想知道如果我做对了。
-
是否有一个双/记者回到onTrimMemory(TRIM_MEMORY_UI_HIDDEN) ? 像onCreate-onDestroy , onStart-onStop , onCreateView-onDestroyView 。 我要求了解在应用程序onTrimMemory(TRIM_MEMORY_UI_HIDDEN)被调用之后,在Activity / Fragment之后如何恢复UI状态。
-
具有TRIM_MEMORY_UI_HIDDEN级别的onTrimMemory实际上是在onStop之前调用的。 当onStop被调用的时候,这意味着这个活动真的停止了,如果需要的话,Android操作系统可能会立刻杀掉它,所以除了onRestart和有时候onDestroy之外,你不应该期待更多的调用这个activity的callback函数。
-
“释放你的UI资源”实际上是关于caching的东西。 您通常不必担心pipe理视图或UI组件,因为操作系统已经这样做了,这就是创build,启动,暂停,停止和销毁活动的所有callback的原因。 但是,有时为了提高性能,您必须增加内存使用量,例如caching活动使用的一些数据。 这是在调用onTrimMemory时应释放的资源types,所以即使影响性能,您的应用程序也会使用更less的内存。 你应该担心内存泄漏。 如果您的活动停止,请确保不要保留对其视图的任何引用,因为这会使活动不被垃圾收集,从而不会收集整个上下文,而这很糟糕,大多数情况下,如果要让应用程序保持运行几个小时或几天(如当你实现服务)。
-
不,没有记者回复onTrimMemory。 但是,你不应该需要一个。 正如我之前所说,如果您保留一些资源的caching来提高性能,只需将其清空,并在需要时再次增长。 如果内存级别保持低,onTrimMemory可能会很快被调用,具有相同的内存级别。 顺便说一下,请记住,onTrimMemory将被调用几个不同的内存级别,而不仅仅是TRIM_MEMORY_UI_HIDDEN。
示例实现
public class AppContext extends Application { //This my introduce OutOfMemoryException if you don't handle register and removal quiet well, better to replace it with weak reference private static List<IMemoryInfo> memInfoList = new ArrayList<AppContext.IMemoryInfo>(); public static abstract interface IMemoryInfo { public void goodTimeToReleaseMemory(); } @Override public void onTrimMemory(int level) { super.onTrimMemory(level); //don't compare with == as intermediate stages also can be reported, always better to check >= or <= if (level >= ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW) { try { // Activity at the front will get earliest than activity at the // back for (int i = memInfoList.size() - 1; i >= 0; i--) { try { memInfoList.get(i).goodTimeToReleaseMemory(); } catch (Exception e) { e.printStackTrace(); } } } catch (Exception e) { e.printStackTrace(); } } } /** * * @param implementor * interested listening in memory events */ public static void registerMemoryListener(IMemoryInfo implementor) { memInfoList.add(implementor); } public static void unregisterMemoryListener(IMemoryInfo implementor) { memInfoList.remove(implementor); } }
public class ActivityParent extends Activity implements AppContext.IMemoryInfo { protected ActivityParent child; @Override protected void onStop() { super.onStop(); try { if (child != null) AppContext.unregisterMemoryListener(child); } catch (Exception e) { } } }
public class ActivityChild extends ActivityParent { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); child = this; } /---move following onResume() in parent as following eg: /* *@Override * protected void onResume() { * super.onResume(); * if(null != child){ * AppContext.registerMemoryListener(this); * } * } */ @Override protected void onResume() { super.onResume(); AppContext.registerMemoryListener(this); } @Override public void goodTimeToReleaseMemory() { super.goodTimeToReleaseMemory(); //remove your Cache etc here } //--NO Need because parent implementation will be called first, just for the sake of clarity @Override protected void onStop() { super.onStop(); try { if (null != child) AppContext.unregisterMemoryListener(child); } catch (Exception e) { } }
更多信息:
当您的应用程序正在运行时: TRIM_MEMORY_RUNNING_MODERATE设备开始在内存中运行不足。 你的应用程序正在运行,而不是可利用的。
TRIM_MEMORY_RUNNING_LOW设备在内存上的运行要低得多。 您的应用程序正在运行,而不是可用的,但请释放未使用的资源以提高系统性能(这直接影响您的应用程序的性能)。
TRIM_MEMORY_RUNNING_CRITICAL设备运行时内存极低。 你的应用程序还没有被认为是一个可以支持的过程,但是如果应用程序不释放资源,系统将开始杀死后台进程,所以你现在应该释放非关键资源来防止性能下降。
当您的应用的可见性发生变化时: TRIM_MEMORY_UI_HIDDEN您的应用的用户界面不再可见,因此这是发布仅由您的用户界面使用的大型资源的好时机。
当应用程序的进程驻留在后台LRU列表中时: TRIM_MEMORY_BACKGROUND系统内存不足,进程接近LRU
列表的开始处。 虽然你的应用程序进程没有被杀死的高风险,但是系统可能已经在LRU
列表中查杀进程,所以你应该释放容易恢复的资源,这样你的进程将会保留在列表中,并且当用户返回到您的应用程序。
TRIM_MEMORY_MODERATE系统内存不足,进程接近LRU列表的中间位置。 如果系统进一步受限于内存,那么你的进程就有可能被杀死。
TRIM_MEMORY_COMPLETE系统内存不足,如果系统现在没有恢复内存,那么你的进程是第一个被终止的进程。 你应该释放绝对不重要的一切,以恢复你的应用程序状态。 要支持低于14的API级别,可以使用onLowMemory()
方法作为大致等同于TRIM_MEMORY_COMPLETE
级别的回退。
http://developer.android.com/reference/android/content/ComponentCallbacks2.html
当显示器closures时,我强迫onTrimMemory()从未被调用的问题。 因此我尝试了一个使用ActivityLifecycleCallbacks的解决方法:我使用了一个简单的计数器:
onActivityStarted(){ i++; } onActivityStopped(){ i--; if(i==0) // no more open activities, thus screen probably turned off }
它为我工作,但我不知道如果这是一个安全的方式。 RFC
更新:启动相机意图,应用程序closures,所以它不完全按照所需的行为。
使用这个代码。 工作得很好:
private void registerBroadcastReceiver() { final IntentFilter theFilter = new IntentFilter(); theFilter.addAction(Intent.ACTION_SCREEN_OFF); BroadcastReceiver screenOnOffReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String strAction = intent.getAction(); if (strAction.equals(Intent.ACTION_SCREEN_OFF)) { // do sth } } }; getApplicationContext() .registerReceiver(screenOnOffReceiver, theFilter); }