I'll try really hard to turn this into one comprehensive question:
I'm writing a method to get a String that contains the name of an Android device's city, as determined by the LocationManager and getLastKnownLocation() and all that.
Then I realized I'd need to do the same thing again in another activity, so why not just make an entirely separate class (LocationFinder) that I could use across my program, instead of writing duplicate code everywhere?
But I've run into problems that confuses me. For instance, if I make this class (LocationFinder), should it extend Activity, even though it is never actually visualized? All this class would do is have a variety of getters like getLastKnownCity() or getCurrentCity() and return strings. I assumed it wouldn't HAVE to extend the Activity class, since it's really not an activity.
But then what Context do I use for:
Geocoder geocoder = new Geocoder(Context context, Locale locale)
?
This made me assume it MUST be an activity. So I extended Activity, and replaced the constructor with
#Override
protected void onCreate(..............
but for some reason, that never ends up getting called, even when I put
String city = new LocationFinder().getLastKnownCity();
My very first line of LocationFinder's onCreate() is
System.out.println("HEY!")
and it never even gets to that. I get a null pointer at android.internal.os.LoggingPrintStream.println() and other stuff.
Plus, there's a bunch of system constants that come from Activity classes. For instance, I need to get at LOCATION_SERVICE, which is a String, which I can't get without extending Activity. Sure, I could cheat and just put in the literal string, but that feels wrong.
EDIT: If possible, use frogmanx's answer. This should only be used when his answer is not possible to use. (ie. singletons that need a context right off the bat.)
Sounds like you should extend Application and not Activity.
Make your Application something like this:
public class MyApplication extends Application {
private static MyApplication instance;
public MyApplication() {
instance = this;
}
public static MyApplication getInstance() {
return instance;
}
Then add this attribute to the application tag of the manifest:
<application android:name=".your.package.MyApplication" ... />
After all that, you can get a Context by calling MyApplication.getInstance() from anywhere.
When constructing your class, you can have a constructor that takes in a Context and assigns it a local Context object within your class.
public class LocationFinder {
private Context myContext;
private Geocoder geocoder;
public LocationFinder(Context context)
{
myContext = context;
geocoder = new Geocoder(myContext);
}
}
And then when you try to access this class, make sure you initialise it like:
public class TestActivity extends Activity {
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
LocationFinder lFinder = new LocationFinder(getApplication());
}
}
Of course, you can't access a context from every class that you will be running. So a reference to a View can suffice.
LocationFinder lFinder = new LocationFinder(anyView.getApplication());
should it extend Activity, even though it is never actually visualized?
No. From the Android docs
An activity is a single, focused thing that the user can do. Almost
all activities interact with the user, so the Activity class takes
care of creating a window for you in which you can place your UI with
setContentView(View)
Think of an Activity as a screen the user sees.
But then what Context do I use for
Geocoder geocoder = new Geocoder(Context context, Locale locale)
The Activity class extends Context, as do a lot of other classes including Application. A context provides access to resources associated with the class which extends the context.
You only need, and should only use, an Activity context when required to interact with resources associated with that Activity and methods implemented by the concrete Activity class. When you do need that access to that context, then you would pass it to the class needing access, typically as an argument to a constructor of that class.
If you ever do pass an Activity context outside of the activity extending it, make sure that the scope and lifecycle of the reference is less than or equal to the extending activity otherwise you will leak large amounts of memory if the activity is destroyed since the garbage collector cannot free the memory since there is a reference to the context.
If you take a look at the constructor for Geocoder you will see that it takes a Context as an argument, as you know. There is a clue as to why the Context is needed in the description:
Geocoder(Context context, Locale locale)
Constructs a Geocoder whose responses will be localized for the given Locale. [1]:
The reason the Context is required is to gain access to system information about the platform locales and the current system locale.
So in your example, you could simply pass the Application context to the constructor, which you can get a reference to with getApplicationContext()
For instance, I need to get at LOCATION_SERVICE, which is a String, which I can't get without extending Activity
You can get it from the application context.
Related
I've wondering if it's okay to do this: whenever we pass a Context variable around, could we just get a singleton reference from the Application class instead
For example here is a subclass of Application class with a single static variable pointing to its own instance
public class App extends Application {
public static mApp;
#Override
public void onCreate(){
mApp = this;
}
}
Then when we need to pass a Context to a method from somewhere, can we just do
foo(App.mApp);
Isn't it okay to treat Context as an application variable?
Well it depends on the context in which you are using it. Many times a context is meant to keep hold of things until it's lifescope is complete and then allow garbage collection to take back whatever it was owning.
Other times the context needs to be an activity to handle life cycle call backs such as onNewIntent or onActivityResult.
Keeping a static instance in the parent is just a shortcut to avoid having to getApplication() and cast it as your type of application. I typically make a method for MyApplication.getApplication().doSomething which will return it's own reference of itself as opposed to ((MyApplication)getApplication()).doSomething
Just seems cleaner for coding purposes. But I would be very leary of using the application context everywhere you need a context, it will come back to bite you eventually.
But yes you can certainly store yourself as a static variable to be shared, I do it in most applications, but typically for a specific shortcut purpose of clean maintainable code, not for cheating on getting context from various crevices.
How do I call the functions provided by Activity class from a class that does not extend Activity? Theoretically, yes, if I don't extend Activity I cannot directly use the functions provided by it. But is there a workaround provided for this? If not, are there replacements or alternative ways for these functions?
For example,
If my class extends Activity, I can call setContentView() to instantiate my layout xml file. But if my class extends some other class and doesn't extend Activity, then I can use the LayoutInflater to do the task. But what about other functions like registerReceiver() ? How do I get the functionality of 'registerReceiver()' from any other class , obviously I wouldn't want every such class to extend Activity. Static access by "Activity.function_name" is also not possible as these functions are not static.
Certain services can be accessed from anywhere. For example 'println()' or Log.e(),System functions can be called from anywhere, whenever needed. Is there a similar way for other critical functions?
Conclusion:
Pass Context to destination class. For accessing some functions however, type-casting the passed Context to Activity is required.
Both Changdeo's and BT's answers are correct.
Thanks.
Although I have not found any documentation explicitly stating why, in every case where I have ever needed to do this, simply passing the Activity's Context is sufficient.
For a Context called contextActivity passed into any function, the following will allow access to these member functions you require:
((Activity) contextActivity).<anyMemberFunction>
Or if you need these functions in multiple cases it might be simplest just to do the following:
Activity myActivity = (Activity) contextActivity;
From there you can access these Activity member functions whenever you like by using:
myActivity.<desiredFunction>;
As I mentioned, I have never found any case where this hasn't worked, but also no solid documentation saying this will always work. This is the trick I have seen consistently used though. If anyone has more to add, please do.
For Ex
Class XYZActivity extends Activity
{
......
......
MyClass myClass = new MyClass(this);
// OR you can pass just context
// MyClass myClass = new MyClass(getContext());
}
Class MyClass
{
Context context;
Myclass(Context context)
{
this.context = context;
context.registe....//Or any function
}
}
In some places we were giving like "DatabaseUtil db=new DatabaseUtil(DailyPlanView.this);" where DatabaseUtil is the class with the constructor argument is context. But if we create the object for the DatabaseUtil class in the DailyPlanVIew class we are using the above code. My doubt is what is the use of the context and instead of passing the context object as argument why we are passing "this".
Whenever you are dealing with Context, its important to understand its used in everything. From using a database to obtaining system services. This is required by the way android works with Context. Specifically when you are passing this you are basically passing the class that encapsulates this statement.
class MyActivity extends Activity
{
onCreate(Bundle bundle)
{
View v = new View(this);
}
}
passing this refers to the object that encapsulates it. This is a Object oriented concept... Where this is reffering to MyActivity. One thing to keep in mind when passing context is ensure that you are passing the correct kind. Some Context objects have a longer lifespan than others and if not managed properly can lead to Context leaking. Specifically in this example, this works because Activity extends Context.
The differences occur in the View class.
getApplicationContext()
getBaseContext()
this, which in the Context of an activity has the life span of an Activity (Example above)
One thing to add about Context is that it is basically a reference to the current Application and it's specific data.
Some more information about context can be found in this thread:
What is 'Context' on Android?
I have been working with android for a little while now and feel pretty comfortable with the platform, but I have gotten a little confused with the Lifecycle of Context Objects. Looking at the hierarchy it is easy to see that Activity and Service both extend Context, and while this is convenient, it is concerning. I have avoided making helper classes that need a shared resource have a static field holding a context (since just about all resources come through some interaction with a Context object) so that way when an activity is destroyed, the GC is free to free it at any time, but I am wondering about resources fetched from a Context.
For example, if I have a static field that holds a File inside of a class. Then make this class's constructor take the current context and assign the File a File resource fetched through the Context passed in, the do nothing else with the Context in my 2ndary class, am I still holding on in some way to the Context?
class testClass{
private static File someFile;
public testClass(Context context){
synchronized(testClass.class){
if(someFile!=null){
//even though I am holding a File, or a SharedPreference Object generated from this context, am I correctly preventing this utility class from holding the Activity object in memory for no reason?
someFile = context.openFileOutput("Some_File.txt", Context.MODE_PRIVATE);
}
}
}
}
I did just read about Context.getApplicationContext() (Sadly not static). It says it returns a context relative to the process and not the activity so if I need to keep a context around, use that one. But the question above still remains.
I remembered I asked this question and thought I would answer it.
Though there may be more kinds of contexts, the primary ones developers use are the Activity Context, and the Application Context (and other things like Service Context). The Activity context is created and destroyed with the activity, so it is not a good idea to use as a constant reference stored between activity creation and destruction. The Application Context doesn't have some of the things an Activity Context has, but everything you would want a static context reference for is there (file IO, preferences...). The application context is also created and destroyed with the application, so you can guarantee that as long as your application code is running, the context is valid.
Because of this, the Application context should be used for things like worker threads that may need a constant access point to a context but not need access to an activity. The best way I have learned to do this is to extend the android Application class. This class is created when the application is created in memory, and as soon as the Application onCreate method is called, the Application Context is valid. This means you can create a static function in your custom application class that gives access to the context.
public class CustomApplication extends Application {
private static Context context;
public void onCreate() {
super.onCreate();
context = getApplicationContext();
}
public Context getAppContext() {
return context;
};
}
The only other thing you need to make this work is a modification to your manifest file so android knows to use your application class instead of the default.
<application
android:icon="#drawable/icon"
android:label="#string/app_name"
android:name=".CustomApplication" >
I have some classes within my application that need to call Android functions that require the Context as a parameter.
I don't have it as the class is not a subclass of the Activity class.
What is the correct way to tackle this problem?
Pass it as a parameter on each call?
Pass it at class instantiation and keep it?
It depends on the role of the class. But anyway pass ApplicationContext but not Activity one. If you pass Activity context gc can't remove it from the memory when after you don't need activity anymore. But application context is used while application was not finished by OS.Refer Avoid Memory Leaks
Pass it as a parameter. Or better yet, get the application context to avoid memory leaks.
public class Example {
protected Context context;
public Example(Context context){
this.context = context.getApplicationContext();
}
}
I'm pretty much always going with a constructor parameter approach. I pass it in the instantiation and keep a private reference in the instantiated class.
You have to think about one important thing. If the class you pass the Context will exist longer than the Activity instantiating it then you should use the application context. If that class is doing UI stuff you will need an activity context.
Make sure that the class you are passing an activity context to won't last longer than the Activity or you'll leak the entire activity.
If you don't do UI stuff then go with the application context.
I pass it as a parameter, i think its de best form to do it
Pass it at class instantiation and keep it.
One typical example is when you create a db helper. See this link
I've answered this question here also.
You can do that using ContextWrapper, as described here.
For example:
public class MyContextWrapper extends ContextWrapper {
public MyContextWrapper(Context base) {
super(base);
}
}
and use that class as it were Context
The best way is to follow Bean approach:
public class Example {
protected Context getContext() {
...
}
...
}
Then it depends on possibilities to access context. If class is fully independent then constructor parameter and private field seems best approach.
But that bean property way shields you from further code changes.