- vừa được xem lúc

Context và Memory Leak trong Android

0 0 23

Người đăng: Dong Thi Hien

Theo Viblo Asia

1. Context

  • Context là trạng thái của ứng dụng tại một thời điểm nhất định.
  • Context là 1 lớp cơ bản chứa hầu hết các thông tin về môi trường ứng dụng của android, tức là mọi thao tác, tương tác với hệ điều hành đều phải thông qua lớp này.
  • Context là 1 abstract class, nó cung cấp cho các lớp triển khai các phương thức truy cập vào tài nguyên của ứng dụng và hệ thống. Ví dụ như nó có thể khởi tạo và chạy các activities, broadcast, các intents....
  • Sở dĩ hầu hết các lớp liên quan đến UI (layout, button, textview...) đều phải super context vì bản thân chúng đảm nhận việc truy cập resource(R.id, R.layout...). Nếu chúng ta không tham chiếu đến Context thì sẽ không dùng được các resource mà chúng ta đã tạo ra.
  • Hệ thống cấp bậc Context:

Context

| — ContextWrapper

| — — Application

| — — ContextThemeWrapper

| — — — Activity

| — — Service

| — — — IntentService

| — MockContext

Thông thường, bạn hay sử dụng 2 loại context là Application và Activity:

  • Application context: gắn liền với vòng đời của ứng dụng và luôn luôn giống nhau xuyên suốt vòng đời ứng dụng. getApplication(), getApplicationContext().
  • Activity context: gắn liền với vòng đời của Activity và nó sẽ bị hủy khi activity bị hủy. getBaseContext(), Activity.this.

Tips: Bất cứ khi nào bạn cần thao tác với Views hãy sử dụng Activity context, còn không sử dụng Application context là đủ. Ví dụ: khi bạn sử dụng Toast, bạn có thể sử dụng 1 trong 2 loại contex trên, nhưng vì nó có thể được show lên từ bất cứ nơi đâu trong ứng dụng, vì vậy bạn nên sử dụng Application context là hợp lý (Trong head-first android họ cũng sử dụng getApplicationContext());

Tránh sử dụng getBaseContext() - lớp này được triển khai khi 1 class extends từ ContextWrapper. Mà lớp này lại có khoảng 40 lớp con trực tiếp và không trực tiếp. Vì vậy, nên gọi trực tiếp đến getContext, Activity, Fragment... để tránh gây ra memory leak.

getApplicationContext() là 1 instance của class Application - được dùng để duy trì trạng thái global cho app.

Lỗi mà mọi người hay gặp khi sử dụng context là Memory Leak.

2. Memory leak

  • Memory leak là rò rỉ bộ nhớ, xảy ra khi bộ nhớ được cấp phát nhưng không bao giờ được giải phóng.
  • Trong khi làm việc với Android, đối tượng context rất hay được sử dụng, vì nó thường được sử dụng để load và truy cập vào resource.
  • Leak: được hiểu là việc bạn giữ 1 tham chiếu tới context và nó ngăn cản việc GC(Garbage Collection - trình thu gom rác) thu gom nó.
  • Khi xảy ra sự kiện xoay màn hình, activity sẽ bị destroy và recreate lại nhưng trạng thái của activity vẫn được giữ lại. Như vậy hệ thống sẽ load lại UI của ứng dụng từ resource. Trong trường hợp bạn cần load 1 cái gì đó nặng và không muốn phải load lại khi xoay màn hình thì bạn sẽ để nó là static.

Ví dụ mình có đoạn code như sau:

private statis Drawable sBackground; Override
protected void onCreate(Bundle state){ super.onCreate(state); TextView label = new TextView(this); label.setText("Leak is bad!"); if(sBackground == null) { sBackground = getDrawable(R.drawable.bit_map); } label.setBackgroundDrawable(sBackground); setContentView(label);
}
  • Đoạn code trên có vẻ khá nhanh, nhưng lại thực sự sai. Lúc này drawable sẽ giữ 1 tham chiếu đến TextView, mà chính nó lại có 1 tham chiếu đến context (activity). Đây là trường hợp đơn giản nhất dẫn đến memory leak, còn nhiều trường hợp nữa sẽ dẫn đến memory leak nhiều hơn và gây ra out of memory nhanh hơn(inner class).

Có 2 cách đơn giản để tránh memory leak trong trường hợp này:

  • Tránh thoát khỏi context trong phạm vi
  • Sử dụng Application context: context này sẽ sống khi ứng dụng sống và nó không phụ thuộc vào vòng đời của activity. Nếu bạn cần giữ 1 đối tượng lâu dài mà cần đến context thì nên dùng application context.

Tóm lại để tránh memory leak nên làm theo 1 số bước sau:

  • Không giữ reference đến context trong thời gian dài(1 reference nên đi cùng với vòng đời của activity)
  • Cố gắng sử dụng application context thay vì activity context
  • Nên để inner class là static và sử dụng WeakReference
  • Không khai báo biến static cho view hoặc activity
  • Nhớ rằng luôn unregister broadcast, timer trong activity. Cancel asyncTask, thread trong onDestroy
  • Sử dụng weakReference khi cần
  • Một Garbage collector không chống lại được memory leak.

3. Cách tránh memory leak

Có một số cách cụ thể để tránh Memory Leak như sau:

a. Broadcast receiver

  • Nếu đăng ký ở onStart() thì nên hủy đăng ký ở onStop().
  • Nếu đăng ký ở onResume() thì nên hủy đăng ký ở onPause()
  • Và nên hủy đăng ký ở onDestroy

b. Static Activity and View Reference

  • Nếu bạn khai báo view hoặc activity là static thì sẽ ngăn GC không thu hồi được bộ nhớ khi activity bị destroy. Vì vậy đừng bao giờ khai báo chúng là static.

c. Singleton class reference

  • Không nên truyền activity context vào class singleton, thay vào đó là truyền application context.
  • Hủy singleton trong onDestroy. Nếu bạn truyền activity context vào trong class singleton thì hãy đảm bảo nó được set về null. Inner class reference
  • Như đã đề cập ở trên, đừng bao giờ khai báo static cho biến inner class
  • Nên khai báo inner class là static class
  • Hoặc là sử dụng weakReference cho view/activity, vì GC có thể thu gom chúng.

d. Anonymous class reference

  • Tương tự ý trên

e. AsyncTask reference

  • Luôn cancel asyncTask trong onDestroy
  • Nếu class AsyncTask được khai báo trong activity thì nó nên để static class (như ý trên).
  • Có thể sử dụng weakReference

f. Thread reference

  • Gọi thread.interrupt trong onDestroy.

g. TimerTask reference

  • Cancel timer trong onDestroy.

Trên đây là một số cách tránh Memory Leak, mọi người tham khảo nhé. Chúc mọi người code vui vẻ.

Tham khảo

Context

What is Context in Android ?

9 Cách tránh Memory Leak

Bình luận

Bài viết tương tự

- vừa được xem lúc

Cách Swift quản lý bộ nhớ với cơ chế ARC - Automatic Reference Counting

Tổng quan về bộ nhớ Stack và Heap. Chắc hẳn bất cứ ai trong chúng ta đều đã từng nghe đến khái niệm về 2 loại bộ nhớ Stack và Heap khi tìm hiểu về cách các ngôn ngữ lập trình quản lý và phân phối bộ nhớ của máy tính.

0 0 147

- vừa được xem lúc

Truy tìm memory leak xung quanh RecyclerView sử dụng LeakCanary

Overview. Bài viết này chủ yếu dành cho các lập trình viên mới làm quen với Android, những người chưa thực sự tìm hiểu sâu về LeakCanary.

0 0 43

- vừa được xem lúc

Memory Leak và nguyên nhân

OutOfMemoryError (OOM) là thứ mà mọi Android Developer đều gặp phải. OutOfMemoryError xuất hiện trong Android do leak memory.

0 0 101

- vừa được xem lúc

Leak Memory Ruby on Rails và cài đặt jemalloc

Bối cảnh. Chào mọi người ! Mình làm một dự án cũng khá là lâu, dự án được cái cũng có số lượng người dùng tương đối, nên cũng may mắn được trải nghiệm vấn đề như thế này:.

0 0 22

- vừa được xem lúc

Leak memory do sử dụng map sai cách trong Golang?

Như các bạn đã biết thì map là một data type được dựng sẵn trong Golang và nó là một tập hợp các cặp key/value. Ủa, đơn giản như vậy mà lại còn được buildin nữa thì sao lại dẫn đến leak memory được, đ

0 0 11

- vừa được xem lúc

[Golang Common Mistakes] Sai lầm khi sử dụng slicing slice trong Golang

Chào mừng các bạn đã quay trở lại với series những common mistakes trong Golang. Trong bài này, chúng ta sẽ tìm hiểu về.

0 0 12