I have simple code snippet to implement custom list view.
In this code, I have CustomAdapter class which extends ArrayAdapter:
CustomAdapter adapter = new CustomerAdapter(getApplicationContext(),R.layout.listview_item_row, weather_data);
The constructor of CustomAdapter is as below:
public CustomerAdapter(Context context, int layoutResourceId, weather[] data) {
super(context, layoutResourceId, data);
mlayoutResourceId = layoutResourceId;
mcontext = context;
mdata = data;
}
If I write this, the logcat shows following error:
Java.lang.ClassCastException: android.app.Application context can not be cast to android.app.Activity
So I changed getApplicationContext() to this. and it worked fine:
CustomAdapter adapter = new CustomerAdapter(this,R.layout.listview_item_row, weather_data);
So, my question is : 1. why we can't pass Application context here? (for the customadapter). and
2. Which are the scenarios in which we must have to pass Activity context instead of Application context?
[Note: I have already read some answers here and here, but they do not concern with specific issue here. All are saying that 'you can use any of them', but in specific situation like this, it does not work. So, please do not mark as duplicate.]
You should pass the context of your activity while creating an adapter object. Application context is different from the activity context and they should never be interchanged. Using application context gives you the entire context for the application which depends on how you have set up your Application subclass is set up. While it can still compile, it may produce results that you do not expect. The reason for your crash is because of what has gone into your Application subclass and is likely specific to your case.
Simply put, adapter objects should use the local Activity context as this is the one that it is bound to.
Adapters should never get the Application context during initialization. As the link codeMagic mentioned, you should always pass along the Activity to a class object if it directly relates to the life of the Activity...of which adapters do.
Now, it's certainly possible to give the ArrayAdapter an application context. It won't crash or throw an error. However what it will do is render your views differently then expected. Mainly because the application context lacks the theming you may or may not have supplied for your App and/or specifically for a given activity.
As to why the crash occurs? Somethings specifically wrong with your code. My guess, you are defining mcontext as an Activity so its crashing in the custom constructor...or It's defined as a Context but being used somewhere that as an Activity context which is causing the crash.
Related
So this my inner class of a base adapter implementation. Note it is for an expandable list view but I use the same process of instantiation for all my list views
class GamesAdapter extends BaseExpandableListAdapter
{
private Context context;
public GamesAdapter(Context context)
{
this.context = context;
}
}
My question is , how do I dispose of this context because after some reading holding a context is a reference to activity so when I rotate the old instance may not be GC'ed thus a memory leak. Please help me
When the screen orientation changes the system will (by default) destroy the current activity and create a new one while giving you a chance to maintain its state. Cant you just set the context again ? im not sure if your handling the config change yourself.
me personally, I'd just pass in getApplicationContext() anytime i need a context since it does not depend on the activity lifecycle ( its not an activity context). But you can also get the context from a View in your getChildView() etc.
Further, if your list is going to be rebuilt on the config change anyway cant you just make its constructor take in the activity context you want ? that way it gets renewed ? So im not seeing where the leak would be yet.
If you rotate the screen the Activity is destroyed but also your BaseExpandableListAdapter implementation. So Android will create a new instance of the Activity and a new instance of your adapter, you don't have to worry about it.
i am trying to set up a helper class that does not extend the Activity class. How ever i need to get a packagemanager object with getPackageManager(). How can i do this?
Why I am needing this? Well i am trying to setup this Helper class and I tried doing it with my Helper class that extended Activity. However I always got a nullpointerexceptions since my helper object was null.
Any tips?
Usually the best way to do what you're trying to do it pass the Context to the constructor of your new class. That way you can then use that to call methods which belong to the Activity.
An example is below, it should help you work out your problem:
private Context context;
// ...
public HelperClass(Context c){
context = c;
}
// ...
context.getPackageManager();
You can then call it by just adding your Context when you initialize the new class:
new HelperClass(this);
Although in certain situations, such as from a Fragment, you may have to provide getActivity();.
new HelperClass(getActivity());
Try edit your class as shown above and let us know if you see any improvements.
As mentioned in the comments, unless you're planning on using your context to edits views etc. you'd be better off with context = c.getApplicationContext(); in your constructor.
I am working on an android app and am currently having a problem with passing contexts to a standard Java class from a ListFragment.
I have a class called Common and in the constructor I pass the context so I can do various common tasks, such as displaying an alert dialogue, so that I can keep reusing the code instead of having to write the code out each time for every alert dialog box I need. To initialise the class in a standard activity I am using.
Common common = new Common(this);
The code above works fine if this is done in a class that extends an Activity. However, if I want to do the same sort of thing but in a class that extends a ListFragment, this doesn't work, so I use the following code in order initialise the class
Common common = new Common(getActivity().getApplicationContext());
When the above code is executed in the ListFragment, when a function is used to display a Yes/No alert dialogue I get a force close with the exception
FATAL EXCEPTION: main
android.view.WindowManager$BadTokenException: Unable to add window
--token null is not for an application
Below is the code for the constructor for the class
public Common(Context context)
{
this.context = context;
}
Just to reiterate, all of the functions within the Common class, including the Yes/No dialogue work fine without problems if the Common class is initialised from a class that extends Activity using the this argument passed to the constructor. Its only if I getActivity().getApplicationContext() as an argument passed to the constructor that I get this error.
As a test I have also changed one my classes that extends an activity and used the getApplicationContext instead of using this, and I get the same error, so its not necessarily specific to me using a ListFragment.
Thanks for any help you can provide.
You can not use ApplicationContext in your case. Instead use just getActivity(). Activity is a Context so your Common class constructor will be satisfied.
But your Common class should really have Common(Activity a) constructor instead.
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 created an ExpandableListAdapter class and I need to send it the context from the activity that is accessing it.
MyActivity.class:
MenuExpandableListAdapter.useInstanceContext(getApplicationContext());
MyExpandableListAdapter.class:
static Context context;
public static void useInstanceContext(Context applicationContext) {
context = applicationContext;
}
The above code works, but this also works:
MenuExpandableListAdapter.useInstanceContext(this.getApplicationContext());
What's the difference? Is this a good way to pass context? I'm still trying to fully understand context.
Context is necessary in order to get access to the resources and some other things. So, both - application and activity contexts work. But a good practice is tight to the smallest thing, which works, which is activity in your case. So, I would suggest new way for you:
MenuExpandableListAdapter.useInstanceContext(this);
Also, in your example, there is no difference between the calls. this is just the reference to the current object.
this refers to the object that is currently executing code, if the method is declared in the same class, and is not static, it is the same to call:
getApplicationContext()
and
this.getApplicationContext()
(The same applies to class members)
MenuExpandableListAdapter.useInstanceContext(getApplicationContext());
The getApplicationContext() method will called by using calling/current object implicitly.
in second you are giving calling/current object explicitly because this is special object that is always refer to calling object.
i suggest you to use this
MenuExpandableListAdapter.useInstanceContext(this.getApplicationContext());
because as per my reading it's good practice.