43

Gần đây, tôi đã đọc bài viết này trên Managing Your App's Memory, tôi khuyên bạn nên đọc nó nếu bạn là AndroidDev và không bao giờ làm.sự hiểu biết vềTrimMemory (cấp int)

Có rất nhiều phương pháp hay và một điều mà tôi chưa bao giờ biết là phương pháp onTrimMemory(int level) được gọi bởi hệ thống trên mọi Hoạt động/Phân đoạn để thông báo sự kiện trên bộ nhớ nào cần hoặc có thể được phát hành.

Dưới đây là một trích dẫn từ bài viết rằng:

ý rằng ứng dụng của bạn nhận được callback onTrimMemory() với TRIM_MEMORY_UI_HIDDEN chỉ khi tất cả các thành phần giao diện người dùng của quá trình ứng dụng của bạn trở nên ẩn từ người sử dụng. Điều này khác với cuộc gọi lại sốonStop(), được gọi khi phiên bản Hoạt động trở thành bị ẩn, xảy ra ngay cả khi người dùng chuyển sang hoạt động khác trong ứng dụng của bạn. Vì vậy, mặc dù bạn nên triển khai onStop() để phát hành tài nguyên hoạt động như kết nối mạng hoặc hủy đăng ký bộ thu phát sóng, bạn thường không nên giải phóng tài nguyên UI cho đến khi bạn nhận được onTrimMemory (TRIM_MEMORY_UI_HIDDEN). Điều này đảm bảo rằng nếu người dùng điều hướng trở lại từ một hoạt động khác trong ứng dụng của bạn, tài nguyên UI của bạn vẫn có sẵn để tiếp tục hoạt động nhanh chóng.

Tôi thực sự quan tâm đến việc thực hiện quản lý bộ nhớ tốt trong ứng dụng của mình vì vậy tôi mong muốn triển khai onTrimMemory() theo đúng cách.

tôi chỉ có một vài câu hỏi về nó:

  • onTrimMemory(TRIM_MEMORY_UI_HIDDEN) gọi ngay sau khi onStop()?

  • điều gì "giải phóng tài nguyên giao diện người dùng của bạn" có nghĩa là trong ngữ cảnh đó? ví dụ như làm sạch bộ nhớ cache Bitmap, hoặc thực sự loại bỏ và tiêu diệt mọi View trong cây View? tôi thường phá hủy Chế độ xem trong các phương thức onDestroy() hoặc onDestroyView(), bây giờ tôi tự hỏi liệu tôi có làm đúng không.

  • là có một cuộc gọi lại 2/phóng viên để onTrimMemory(TRIM_MEMORY_UI_HIDDEN)? như onCreate-onDestroy, onStart-onStop, onCreateView-onDestroyView. Tôi yêu cầu để hiểu được nơi và làm thế nào tôi nên khôi phục lại trạng thái giao diện người dùng sau khi một Activity/Fragment được đưa vào nền trước sau khi onTrimMemory(TRIM_MEMORY_UI_HIDDEN) đã được gọi.

+0

Lưu ý rằng onTrimMemory (mức) được gọi bởi hệ thống trên tất cả các thành phần Android - không chỉ Hoạt động/Phân đoạn. – Tom

+0

xem mẫu Thực hiện tại đây http://stackoverflow.com/a/28210326/185022 –

Trả lời

23
  • onTrimMemory với mức TRIM_MEMORY_UI_HIDDEN là thực sự gọi trước khi onStop. Khi onStop được gọi, điều đó có nghĩa là hoạt động thực sự dừng và hệ điều hành Android có thể giết ngay lập tức nếu cần, vì vậy bạn không nên mong đợi thêm bất kỳ cuộc gọi nào gọi lại hoạt động đó, ngoại trừ onRestart và đôi khi onDestroy.

  • "phát hành tài nguyên giao diện người dùng của bạn" thực sự là về những thứ như bộ nhớ cache.Bạn thường không phải lo lắng về việc quản lý các khung nhìn hoặc các thành phần giao diện người dùng vì hệ điều hành đã làm điều đó, và đó là lý do tại sao có tất cả các callbacks đó để tạo, bắt đầu, tạm dừng, dừng và hủy một hoạt động. Tuy nhiên, đôi khi để cải thiện hiệu suất, bạn phải tăng mức sử dụng bộ nhớ, chẳng hạn như bộ nhớ đệm một số dữ liệu được sử dụng bởi các hoạt động của bạn. Đó là loại tài nguyên bạn nên phát hành khi onTrimMemory được gọi, vì vậy ứng dụng của bạn sử dụng ít bộ nhớ hơn, ngay cả khi nó ảnh hưởng đến hiệu suất. Bạn nên lo lắng về rò rỉ bộ nhớ mặc dù. Nếu hoạt động của bạn dừng lại, hãy đảm bảo không giữ bất kỳ tham chiếu nào đến chế độ xem của nó, vì điều đó sẽ ngăn hoạt động thu thập rác, điều này sẽ ngăn toàn bộ bối cảnh bị thu thập và điều đó rất tệ, chủ yếu là nếu bạn muốn giữ cho ứng dụng của mình chạy cho giờ hoặc ngày (như khi bạn triển khai dịch vụ).

  • Không, không có thư nào gọi lại đối với onTrimMemory. Tuy nhiên, bạn không nên cần. Như tôi đã nói trước đây, nếu bạn giữ một bộ nhớ cache của một số tài nguyên để cải thiện hiệu suất, chỉ cần làm trống đó, và để cho nó phát triển trở lại nếu nó cần. Nếu mức bộ nhớ vẫn còn thấp, onTrimMemory có thể được gọi lại sớm, với cùng mức bộ nhớ đó. Nhân tiện, hãy nhớ rằng onTrimMemory sẽ được gọi với nhiều cấp độ bộ nhớ khác nhau, không chỉ TRIM_MEMORY_UI_HIDDEN.

+0

Bạn có thể giải thích rằng 'Nếu hoạt động của bạn dừng lại, hãy đảm bảo không giữ bất kỳ tham chiếu nào đến chế độ xem của nó'? –

7

mẫu thực hiện

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) { 

     } 
    } 

More Info:

Khi ứng dụng của bạn đang chạy: TRIM_MEMORY_RUNNING_MODERATE Thiết bị này sắp hết bộ nhớ. Ứng dụng của bạn đang chạy và không thể giết được.

TRIM_MEMORY_RUNNING_LOW Thiết bị đang chạy thấp hơn nhiều trên bộ nhớ. Ứng dụng của bạn đang chạy và không thể giết được, nhưng vui lòng giải phóng tài nguyên chưa sử dụng để cải thiện hiệu suất hệ thống (tác động trực tiếp đến hiệu suất của ứng dụng).

TRIM_MEMORY_RUNNING_CRITICAL Thiết bị đang chạy rất thấp trên bộ nhớ. Ứng dụng của bạn vẫn chưa được coi là quá trình giết người, nhưng hệ thống sẽ bắt đầu giết chết các quá trình nền nếu ứng dụng không phát hành tài nguyên, vì vậy bạn nên phát hành tài nguyên không quan trọng ngay bây giờ để ngăn chặn sự xuống cấp hiệu suất.

Khi ứng dụng của bạn tầm nhìn thay đổi về giao diện TRIM_MEMORY_UI_HIDDEN của ứng dụng của bạn không còn có thể nhìn thấy, vì vậy đây là thời điểm tốt để giải phóng nguồn lực lớn mà chỉ được sử dụng bởi giao diện người dùng của bạn.

Khi quá trình ứng dụng của bạn nằm trong danh sách LRU nền: TRIM_MEMORY_BACKGROUND Hệ thống đang ở mức thấp vào bộ nhớ và quá trình của bạn là gần đầu danh sách LRU. Mặc dù quy trình ứng dụng của bạn không có nguy cơ bị giết cao, hệ thống có thể đã bị giết trong danh sách LRU, do đó bạn nên giải phóng tài nguyên dễ khôi phục để quy trình của bạn vẫn còn trong danh sách và tiếp tục nhanh chóng khi người dùng trở lại ứng dụng của bạn.

TRIM_MEMORY_MODERATE Hệ thống sắp hết bộ nhớ và quá trình của bạn nằm gần giữa danh sách LRU. Nếu hệ thống trở nên bị ràng buộc hơn nữa đối với bộ nhớ, có khả năng quá trình của bạn sẽ bị giết.

TRIM_MEMORY_COMPLETE Hệ thống sắp hết bộ nhớ và quá trình của bạn là một trong những người đầu tiên bị giết nếu hệ thống không khôi phục bộ nhớ ngay bây giờ. Bạn nên phát hành tuyệt đối mọi thứ không quan trọng để tiếp tục trạng thái ứng dụng của bạn. Để hỗ trợ mức API thấp hơn 14, bạn có thể sử dụng phương thức onLowMemory() làm dự phòng tương đương với mức TRIM_MEMORY_COMPLETE.

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

+1

cảm ơn lời giải thích. Nếu tôi sử dụng onTrimMemory (int level) trong Activity, nó sẽ được gọi tự động? –

1

tôi đã buộc các vấn đề mà onTrimMemory() chưa từng được gọi khi màn hình tắt. Vì vậy tôi đã cố gắng một cách giải quyết bằng ActivityLifecycleCallbacks: tôi đã sử dụng một bộ đếm đơn giản:

onActivityStarted(){ 
    i++; 
} 

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

Nó làm việc cho tôi nhưng im không chắc chắn nếu nó là một cách an toàn. RFC

CẬP NHẬT: Bắt đầu từ mục đích của máy ảnh, ứng dụng đã đóng, do đó nó không hoạt động chính xác như mong muốn.

Đã sử dụng mã này để thay thế. chỉ hoạt động tốt:

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); 
} 
Các vấn đề liên quan