getApplication () so với getApplicationContext ()


417

Tôi không thể tìm thấy câu trả lời thỏa mãn cho vấn đề này, vì vậy chúng ta đi: thỏa thuận này là gì Activity/Service.getApplication()Context.getApplicationContext()?

Trong ứng dụng của chúng tôi, cả hai trả về cùng một đối tượng. ActivityTestCaseTuy nhiên, trong một chế độ giả, ứng dụng sẽ getApplication()quay trở lại với giả, nhưng getApplicationContextvẫn trả về một thể hiện bối cảnh khác (một phiên bản được tiêm bởi Android). Đó có phải là một lỗi không? Có mục đích không?

Tôi thậm chí không hiểu sự khác biệt ở nơi đầu tiên. Có trường hợp nào bên ngoài một bộ kiểm tra mà cả hai cuộc gọi có thể quay lại với các đối tượng khác nhau không? Khi nào và tại sao? Hơn nữa, tại sao được getApplicationđịnh nghĩa trên ActivityService, nhưng không phải trên Context? Không phải luôn luôn có một ví dụ ứng dụng hợp lệ có sẵn từ bất cứ đâu ?


8
Câu hỏi hay. Các công cụ kiểm tra là một chút bí ẩn (như bạn cũng biết). Nhưng tôi tự hỏi nếu có bất kỳ sự khác biệt nào thể hiện trong hai cuộc gọi phương thức này nếu bạn không rõ ràng tạo một Applicationđối tượng trong ứng dụng của mình.
Christopher Orr

Câu trả lời:


366

Câu hỏi rất thú vị. Tôi nghĩ rằng nó chủ yếu là một ý nghĩa ngữ nghĩa, và cũng có thể là do lý do lịch sử.

Mặc dù trong các triển khai Hoạt động và Dịch vụ Android hiện tại getApplication()getApplicationContext()trả về cùng một đối tượng, không có gì đảm bảo rằng điều này sẽ luôn luôn như vậy (ví dụ: trong một triển khai nhà cung cấp cụ thể).

Vì vậy, nếu bạn muốn lớp Ứng dụng mà bạn đã đăng ký trong Bản kê khai, bạn không bao giờ nên gọi getApplicationContext()và chuyển nó sang ứng dụng của mình, vì đó có thể không phải là phiên bản ứng dụng (mà bạn rõ ràng đã trải nghiệm với khung kiểm tra).

Tại sao getApplicationContext()tồn tại ở nơi đầu tiên?

getApplication()chỉ khả dụng trong lớp Activity và lớp Service, trong khi getApplicationContext()được khai báo trong lớp Context.

Điều đó thực sự có nghĩa là một điều: khi viết mã trong một máy thu quảng bá, không phải là một bối cảnh nhưng được cung cấp một bối cảnh trong phương thức onReceive của nó, bạn chỉ có thể gọi getApplicationContext(). Điều đó cũng có nghĩa là bạn không được đảm bảo có quyền truy cập vào ứng dụng của mình trong BroadcastReceiver.

Khi nhìn vào mã Android, bạn sẽ thấy rằng khi được đính kèm, một hoạt động sẽ nhận được một bối cảnh cơ bản và một ứng dụng và đó là những tham số khác nhau. getApplicationContext()đại biểu nó gọi tới baseContext.getApplicationContext().

Một điều nữa: tài liệu nói rằng hầu hết các trường hợp, bạn không cần phải phân lớp Ứng dụng:

Thông thường không cần phải phân lớp Application. Trong hầu hết các tình huống, singletons tĩnh có thể cung cấp chức năng tương tự theo cách mô đun hơn. Nếu singleton của bạn cần một bối cảnh toàn cầu (ví dụ để đăng ký máy thu quảng bá), chức năng truy xuất nó có thể được cung cấp Contexttrong đó sử dụng nội bộ Context.getApplicationContext()khi lần đầu tiên xây dựng singleton.

Tôi biết đây không phải là một câu trả lời chính xác và chính xác, nhưng vẫn trả lời câu hỏi của bạn?


89
@ Piwaï: Đừng nghe tài liệu. Phân lớp android.app.Applicationlà siêu trợ giúp đầy đủ. Ví dụ, tôi gặp vấn đề vô tận khi khởi tạo cơ sở dữ liệu. Một khi chuyển vào Application.onCreatenó làm việc như một lá bùa. Bây giờ tôi thực hiện tất cả các khởi tạo trên toàn hệ thống Applicationvà tôi sẽ không viết một Ứng dụng khác mà không có.
Martin

9
@Martin Không nghe các tài liệu nói chung có nghĩa là mã của bạn có thể bị hỏng trong tương lai hoặc thậm chí bây giờ trong điều kiện không mong muốn, mất tính di động, hoạt động kém, ngăn các nhà phát triển nền tảng thực hiện thay đổi có lợi (phá vỡ giả định bạn đã thực hiện không chính xác mặc dù đó là chỉ dựa trên việc thực hiện hiện tại, không phải tài liệu). Tôi nghĩ rằng đây là hành vi khá xấu và lời khuyên khá tệ.
Palec

17
@Palec: Thông thường không cần phải phân lớp Ứng dụng. - Đó chỉ là gợi ý. Tôi vẫn sử dụng chức năng tài liệu chính thức theo cách dự định. - Lúc đầu tôi thường sử dụng những singletons tĩnh đó và họ hóa ra là một nỗi đau trong một trò chơi - khởi tạo lười biếng có vấn đề. Đặc biệt là khi được sử dụng với các bài kiểm tra thiết bị. - Tôi vẫn có các Singletons cho tính mô đun nhưng tôi khởi tạo chúng theo khối trong onCreate của một lớp con android.app.Application. - hoạt động như một lá bùa.
Martin

9
@Martin Tôi nên nói rõ: Phản ứng của tôi chỉ liên quan đến câu đầu tiên. Không được nghe tài liệu. Đây thường là lời khuyên rất nguy hiểm. Tuy nhiên, đây chỉ là một gợi ý - bạn có thể bỏ qua tài liệu trong trường hợp này nếu bạn có lý do và tôi sẽ chỉ cho bạn một âm thanh rất hay đối với tôi.
Palec

3
. " . Vậy chúng ta có thể làm gì để truy cập vào lớp ứng dụng của mình trong BroadcastReceiver?
Dr.jacky

30

So sánh getApplication()getApplicationContext().

getApplicationtrả về một Applicationđối tượng sẽ cho phép bạn quản lý trạng thái ứng dụng toàn cầu của mình và phản ứng với một số tình huống của thiết bị như onLowMemory()onConfigurationChanged().

getApplicationContexttrả về bối cảnh ứng dụng toàn cầu - sự khác biệt so với các bối cảnh khác là ví dụ, bối cảnh hoạt động có thể bị phá hủy (hoặc nếu không có sẵn) bởi Android khi hoạt động của bạn kết thúc. Bối cảnh Ứng dụng vẫn có sẵn trong khi đối tượng Ứng dụng của bạn tồn tại (không gắn với một cụ thể Activity), do đó bạn có thể sử dụng bối cảnh này cho những thứ như Thông báo yêu cầu bối cảnh sẽ có sẵn trong thời gian dài hơn và độc lập với các đối tượng UI tạm thời.

Tôi đoán nó phụ thuộc vào những gì mã của bạn đang làm cho dù những thứ này có thể giống nhau hay không - mặc dù trong sử dụng bình thường, tôi hy vọng chúng sẽ khác nhau.


19
nhưng an Application một Context(nó kế thừa từ nó) và tại thời gian chạy, cả hai phương thức đều trả về cùng một thể hiện. Vậy sự khác biệt là gì?
Matthias

3
Sự khác biệt là phạm vi. Bối cảnh Ứng dụng của bạn sẽ có hiệu lực lâu hơn nhiều so với bối cảnh Hoạt động vì hoạt động chỉ có thể được sử dụng trong một thời gian rất ngắn, trong khi Ứng dụng của bạn có thể bao gồm nhiều Hoạt động. Bối cảnh hoạt động của bạn sẽ có hiệu lực ít nhất là với thời lượng bắt đầu khi hoạt động đầu tiên được bắt đầu và kết thúc khi hoạt động cuối cùng. Chúng đều là các bối cảnh, nhưng một bối cảnh tồn tại lâu hơn và không thay đổi, nhưng các bối cảnh khác chỉ tồn tại trong thời gian ngắn và các trường hợp khác nhau có thể có các bối cảnh khác nhau.
RivieraKid

16
Tôi nghĩ rằng bạn có thể đang đọc sai câu hỏi của tôi. Tôi không yêu cầu sự khác biệt giữa Activitybối cảnh và Applicationbối cảnh. Tôi đang cân nhắc sự khác biệt giữa Application(đó là bối cảnh ứng dụng toàn cầu, duy nhất) và bất kỳ getApplicationContextlợi nhuận nào. Cái thứ hai trong thực tế là không hoạt động trước Android 1.6; nó được sử dụng để luôn luôn trở lại null.
Matthias

1
@Matthias Theo tôi nó vẫn có liên quan. Bối cảnh được chính hệ thống Android đưa vào (triển khai), trong khi Ứng dụng kế thừa và mở rộng Ngữ cảnh. Lớp ứng dụng có thể dễ dàng bị chế giễu (như bạn đã nói) sau đó không phải là đặt cược an toàn mà nó cho thấy rằng lớp Ứng dụng thực hiện một số "phép thuật" (trong dự án thử nghiệm) để đạt được nó, có thể bỏ qua Ngữ cảnh được tiêm?
Audrius

3
Lại nữa à? Tôi xin lỗi, tôi vẫn không thấy câu trả lời của mình như thế nào.
Matthias

30

Nó dường như phải làm với gói bối cảnh. Hầu hết các lớp có nguồn gốc Contextthực sự là một ContextWrapper, mà về cơ bản là ủy nhiệm cho một bối cảnh khác, có thể với các thay đổi của trình bao bọc.

Bối cảnh là một sự trừu tượng chung hỗ trợ cho việc chế nhạo và ủy quyền. Vì nhiều bối cảnh bị ràng buộc với một đối tượng có giới hạn như một đối tượng Activity, nên cần có một cách để có được bối cảnh tồn tại lâu hơn, cho các mục đích như đăng ký thông báo trong tương lai. Đó là đạt được bởi Context.getApplicationContext(). Việc triển khai logic là trả về Applicationđối tượng toàn cục , nhưng không có gì ngăn cản việc thực hiện ngữ cảnh trả lại trình bao bọc hoặc proxy với thời gian phù hợp thay thế.

Các hoạt động và dịch vụ được liên kết cụ thể hơn với một Applicationđối tượng. Tôi tin rằng sự hữu ích của điều này là bạn có thể tạo và đăng ký trong bảng kê khai một lớp tùy chỉnh xuất phát từ Applicationvà chắc chắn rằng Activity.getApplication()hoặc Service.getApplication()sẽ trả về đối tượng cụ thể của loại cụ thể đó, mà bạn có thể Applicationsử dụng cho lớp dẫn xuất của mình và sử dụng cho bất cứ điều gì mục đích tùy chỉnh.

Nói cách khác, getApplication()được đảm bảo trả lại một Applicationđối tượng, trong khi đó getApplicationContext()có thể tự do trả lại proxy.


Khi bạn nói "bối cảnh là một sự trừu tượng chung hỗ trợ cho việc chế giễu và ủy quyền", ý của bạn là "ủy quyền" chính xác là gì? Bạn có thể chỉ cho tôi một số tài liệu tham khảo? Tôi thấy toàn bộ điều bối cảnh khá phức tạp.
Tiago

@Tiago Câu trả lời này có thể giúp bạn hiểu rõ hơn: stackoverflow.com/questions/10641144/
siêu người dùng

-13

Để trả lời câu hỏi, getApplication () trả về một đối tượng Ứng dụng và getApplicationContext () trả về một đối tượng Ngữ cảnh. Dựa trên các quan sát của riêng bạn, tôi sẽ giả sử rằng Bối cảnh của cả hai giống hệt nhau (tức là đằng sau hậu trường, lớp Ứng dụng gọi hàm sau để điền vào phần Ngữ cảnh của lớp cơ sở hoặc một số hành động tương đương diễn ra). Nó thực sự không quan trọng với chức năng mà bạn gọi nếu bạn chỉ cần một Ngữ cảnh.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.