IT story

onTrimMemory (int level) 이해

hot-time 2020. 12. 31. 22:57
반응형

onTrimMemory (int level) 이해


최근에 앱의 메모리 관리에 대한 이 기사 를 읽었습니다. AndroidDev이고 한 번도 읽지 않았다면 읽어 보는 것이 좋습니다.

많은 좋은 관행이 있으며 내가 결코 알지 못하는 한 가지는 모든 활동 / 조각에서 시스템이 호출하여 메모리를 해제해야하거나 해제 할 수있는 이벤트를 알리는 onTrimMemory (int level) 메서드입니다.

다음은 그 기사의 인용문입니다.

앱 프로세스의 모든 UI 구성 요소가 user에게 숨겨 질 때만 앱이 TRIM_MEMORY_UI_HIDDEN과 함께 onTrimMemory () 콜백을 수신합니다 . 이것은 사용자가 앱의 다른 활동으로 이동할 때에도 발생하는 Activity 인스턴스가 숨겨 질 때 호출되는 onStop () 콜백과 다릅니다. 따라서 네트워크 연결과 같은 활동 리소스를 해제하거나 브로드 캐스트 수신기를 등록 취소하려면 onStop ()을 구현해야하지만 일반적으로 onTrimMemory (TRIM_MEMORY_UI_HIDDEN)를 수신 할 때까지 UI 리소스를 해제해서는 안됩니다 . 이렇게하면 사용자가 앱의 다른 활동에서 뒤로 이동하는 경우 UI 리소스를 사용하여 활동을 빠르게 재개 할 수 있습니다.

나는 내 응용 프로그램에서 좋은 메모리 관리를 구현하는 데 정말로 관심이 있으므로 onTrimMemory () 를 올바른 방법으로 구현하기를 고대하고 있습니다.

이에 대한 몇 가지 질문 만 있습니다.

  • 한다 onTrimMemory (TRIM_MEMORY_UI_HIDDEN은) ) (오른쪽 이동 중지 후에 호출?

  • 그 맥락에서 "UI 리소스 해제"는 무엇을 의미합니까? 예를 들어 비트 맵 캐시를 정리하거나 실제로보기 트리의 모든보기를 제거하고 파괴 하시겠습니까? 나는 일반적으로 onDestroy () 또는 onDestroyView () 메서드 에서 뷰를 파괴합니다. 이제 제대로하고 있는지 궁금합니다.

  • onTrimMemory (TRIM_MEMORY_UI_HIDDEN)에 대한 Twin / 해당 콜백이 있습니까? 같은 에서 onCreate-들의 OnDestroy , ONSTART-중지시 , onCreateView-onDestroyView . onTrimMemory (TRIM_MEMORY_UI_HIDDEN) 가 호출 된 후 전경으로 가져온 활동 / 조각 후 UI 상태를 어디서 어떻게 복원해야하는지 이해하기를 요청합니다 .


  • TRIM_MEMORY_UI_HIDDEN 수준의 onTrimMemory는 실제로 onStop 전에 호출됩니다. onStop이 호출되면 활동이 실제로 중지되고 있음을 의미하며, 필요한 경우 Android OS에서 즉시 중지 할 수 있으므로 onRestart 및 때때로 onDestroy를 제외하고 해당 활동의 콜백에 대한 더 이상 호출을 기 대해서는 안됩니다.

  • "UI 리소스 해제"는 실제로 캐시와 같은 것입니다. OS가 이미 그렇게하고 있기 때문에 일반적으로 뷰 또는 UI 구성 요소 관리에 대해 걱정할 필요가 없으며 활동을 생성, 시작, 일시 중지, 중지 및 제거하기위한 콜백이 모두있는 이유입니다. 그러나 때로는 성능을 향상시키기 위해 활동에 사용되는 일부 데이터를 캐싱하는 것과 같이 메모리 사용량을 늘려야합니다. 이것이 onTrimMemory가 호출 될 때 해제해야하는 리소스 유형이므로 앱은 성능에 영향을 주더라도 메모리를 덜 사용합니다. 그래도 메모리 누수에 대해 걱정해야합니다. 활동이 중지되면 해당 뷰에 대한 참조를 유지하지 마십시오. 그러면 활동이 가비지 수집되지 않고 전체 컨텍스트가 수집되지 않으며 이는 나쁘기 때문입니다.

  • 아니요, onTrimMemory에 대한 대응 콜백이 없습니다. 그러나 필요하지 않습니다. 앞서 말했듯이 성능 향상을 위해 일부 리소스의 캐시를 유지하는 경우 해당 캐시를 비우고 필요한 경우 다시 커지게하십시오. 메모리 수준이 낮게 유지되면 동일한 메모리 수준으로 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 The device is running much lower on memory. Your app is running and not killable, but please release unused resources to improve system performance (which directly impacts your app's performance).

TRIM_MEMORY_RUNNING_CRITICAL The device is running extremely low on memory. Your app is not yet considered a killable process, but the system will begin killing background processes if apps do not release resources, so you should release non-critical resources now to prevent performance degradation.

When your app's visibility changes: TRIM_MEMORY_UI_HIDDEN Your app's UI is no longer visible, so this is a good time to release large resources that are used only by your UI.

When your app's process resides in the background LRU list: TRIM_MEMORY_BACKGROUND The system is running low on memory and your process is near the beginning of the LRU list. Although your app process is not at a high risk of being killed, the system may already be killing processes in the LRU list, so you should release resources that are easy to recover so your process will remain in the list and resume quickly when the user returns to your app.

TRIM_MEMORY_MODERATE The system is running low on memory and your process is near the middle of the LRU list. If the system becomes further constrained for memory, there's a chance your process will be killed.

TRIM_MEMORY_COMPLETE The system is running low on memory and your process is one of the first to be killed if the system does not recover memory now. You should release absolutely everything that's not critical to resuming your app state. To support API levels lower than 14, you can use the onLowMemory() method as a fallback that's roughly equivalent to the TRIM_MEMORY_COMPLETE level.

http://developer.android.com/reference/android/content/ComponentCallbacks2.html


I was forcing the problem that onTrimMemory() was never called when the display turned off. Thus I tried a workaround using ActivityLifecycleCallbacks: I used a simple counter:

onActivityStarted(){
    i++;
}

onActivityStopped(){
    i--;
    if(i==0) // no more open activities, thus screen probably turned off
}

It worked for me but im not sure if it is a safe way. RFC

UPDATE: Starting a camera intent, the application closed, too so it is not exactly behaving as desired.

Used this code instead. works just fine:

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);
}

ReferenceURL : https://stackoverflow.com/questions/19398827/understanding-ontrimmemory-int-level

반응형