In my previous blog, I spoke about 6 things you must know about Android for the first time (6 things I WISH I knew before I wrote MY Android APP). One of them is: Do not have a static reference to the context. The reason I'm so warned is that a static reference to a context can cause a memory leak. But one reader points out that a static reference to a application context does not cause a memory leak, because the life cycle of application context will not end as long as the program is still running. I argue that technically you can have a static reference to the application context without causing a memory leak, but I recommend that you do so.
In this blog, I want to explain why owning and using a static reference to a application context is not an ideal choice . The "ideal choice" is emphasized because I'm not saying that using static references to application context causes the program to crash every time. In contrast, what I'm talking about here is some of the pitfalls of using context static references, so that this is not the simplest way to develop an Android app.
1. Object/method Use application context static reference is "spoofing"this is from Google's guidelines for writing testable code (Google's Guide to Writing testable code). In this guide, they point out:
Static FETCH global variables do not tell the person who read the code the dependencies of their (global variables) constructors and methods . Global variables and singleton masks their true dependencies through the API. If you want to really understand the dependencies, the developer must read the code on a row-by-line basis. (Accessing global state statically doesn ' t clarify those gkfx dependencies to readers of the constructors and methods th At use of the Global state. Global state and singletons do APIs lie about their true dependencies. To really understand the dependencies, developers must read every line of code.)
A global static reference to a application context is also said: The person reading this object cannot know that the object relies on the context just to use its API. When an object has a clear and realistic API to express its dependencies, it is easier to understand the functionality of a class or method and how it will implement it.
The following is a simple example to illustrate. Suppose you encounter a method name when you read the code:
public void displaystring (String stringtodisplay)
When you encounter this name, you have no way of knowing how this method will display the string passed in by the parameter. Now, suppose you read this method name:
public void displaystring (context context, String Stringtodisplay)
For this method name, you have a clue (translator: The thread refers to the context parameter): This method might be to display a string with a toast. Because context is a "universal class", it is not always possible for a particular object or method to display the function of the object/method or how it implements this function. However, a little hint is stronger than no hint.
(Translator: Maybe some of the translation is not fluent, here is a general explanation.) If you use static references from ApplicationContext to use some methods, you cannot tell if the method needs to use the context. If you do not use static references to ApplicationContext, you must have one more context parameter when a method needs to use a context object, such as a toast. When not needed, there is no context parameter. Reading the code can be based on this point on the implementation of the method has a certain estimate).
2. Objects that are statically referenced using the application context are not encapsulatedencapsulation, though often mentioned, does not have an accurate definition. And I'm not going to make this definition more complicated. When I say "encapsulation," I mean
Steve Freeman and
Nat Pryce in test-
based object-oriented programming (growing object oriented software Guided by Tests) The concepts mentioned:
(encapsulation) guarantees that the behavior of an object can only be affected by its API. It guarantees that no unknown references are generated between unrelated objects, which allows us to control the effect of an object's modifications on the rest of the system. ([It] ensures that the behavior of a object can only is affected through its API. It lets us control how much a change to one object would impact other parts of the system by ensuring that there is no une xpected dependencies between unrelated components. -PG. 92)
Because ApplicationContext statically referenced objects are associated with a global dependency, the behavior of these objects may be affected by the global shared application context. Because application context is not part of these object APIs, this means that changes in object behavior may not be affected by the object's API. In other words, this means that using the application context static reference destroys the encapsulation.
In most cases, breaking the encapsulation in such a way does not have much impact. In fact, I can only imagine a few examples of possible problems that seem to have been deliberately fabricated. However, I still believe that, in cases where other conditions are equal, we should choose a structure that can apply 100% in all cases, not 99%. Again, using static references to ApplicationContext and damage to encapsulation does not crash your program, but this is not the most stable structure.
3. Objects that are statically referenced using application context may be difficult to unit testif one of your objects calls a method in the application context and you want to verify that the method is called in the unit test, using a static reference will not make you feel better. As I said in why the Android unit test is so difficult, you will want to do such an operation in some cases. Suppose you already have a Servicelauncher object that launches the Android service. If you use dependency injection to pass in a context object when Servicelaucher is referenced, the unit test is simple:
public class Servicelaunchertests { @Mock Context mcontext; @Test public void Launchessessioncalendarservice () { Servicelauncher servicelauncher = new Servicelauncher ( Mcontext); Servicelauncher.launchsessioncalendarservice (); Verify (Mcontext). StartService (Any (Intent.class));} }
If the Servicelaucher uses the application context static reference, the object is difficult to unit test. In this example, you can use the test Support Library UI test to verify that intent was sent, but the UI test is slower than the unit test. Also, you may need to verify that there are also some methods in the context that do not use intent. So, injecting a context into a target object is more flexible than a global static variable, even if you can use the test support library to help you verify the intent's delivery. 4. Objects that are statically referenced using application context are more likely to violate the Dimitri rule (least known law, least-referential rule)We often use the context to get a reference to the object we need. A particular object may require resoureces, sharepreferences, or Packagemanager to implement its functionality. When we have a global application context reference, we might try to get a reference to these objects in such a way:
public class Smellysessioncolorresolver {public smellysessioncolorresolver () { } public int Resolvesessioncolor (int sessioncolor) { if (Sessioncolor = = 0) { //No Color--Use default Sessioncolor = IOA Pplication.getcontext (). Getresources (). GetColor (R.color.default_session_color); } else { //Make sure it ' s opaque sessioncolor = Uiutils.setcoloralpha (Sessioncolor, 255); } return sessioncolor;} }
This goes against the Dimitri Law. I've actually complained that violating the Dimitri rule makes it difficult for a program to perform unit tests. But even if you don't care about unit tests, violating the Dimitri rule is often considered a nasty code style. ConclusionI don't think there's too much controversy about what I'm talking about. I think I'm just using a generic programming course that I've learned from a smarter person. Of course, you are welcome to criticize and correct. If you are convinced that you need to avoid the use of application context static references, it should not be difficult to inject a context into the necessary objects and methods. You may even find that you can eliminate a lot of code that violates the Dimitri Law during refactoring. The speculation and refactoring features of Android Studio make this work easier, even a bit boring. Translator's conclusionThis article outlines several recognized drawbacks of using application context. For the use of the application context as a global variable, it may be because it is an unique method of Android, which was once considered the most reasonable method. However, Google's official documents point out that rewriting the application class is actually a deprecated practice because there is no reason to say it is better than traditional Java global variables. And it's easy to make application grow smelly and long, and you need to add a long sentence when quoting. Therefore, I still agree not to use the application context.
Defects referenced using ApplicationContext as global variables