How many LayoutInflater are instantiated in an application? - android

I am using the Factory interface on LayoutInflater to be able to set a custom typeface on all my TextView in my application. Unfortunately there are places in my application where it doesn't work. After investigation, it seems that in the adapter of my ListView for example, the LayoutInflater used to inflate the cells is different from the one that has been used fo the rest of the application (my activity has a complex structure with Fragments).
Is this behaviour normal ? How can I make sure that the same LayoutInflater is always used, whatever the way I retrieve it ?
Thanks

as You get reference to LayoutInflater from Context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) (ViewGroup.inflate and Activity.getLayoutInflater are just convenient wrappers) i presume it always returns reference to the same inflater service, until it is destroyed and recreated, and then this newly created is returned, and so on... I presume that manager object aquired from getSystemService method are sth like "normal" service's binder objects.
EDIT:
And saying above i was wrong ;)
i checked out the source code and in android.view.ContextThemeWrapper (which is activitie's super class):
#Override public Object getSystemService(String name) {
if (LAYOUT_INFLATER_SERVICE.equals(name)) {
if (mInflater == null) {
mInflater = LayoutInflater.from(mBase).cloneInContext(this);
}
return mInflater;
}
return mBase.getSystemService(name);
}
and in android.app.ContextImpl which is probably mBase Context implementation:
public Object getSystemService(String name) {
ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name);
return fetcher == null ? null : fetcher.getService(this);
}
where :
private static final HashMap SYSTEM_SERVICE_MAP =
new HashMap();
and ServiceFetcher is an inner class for caching and retrieving "system service instances".
What is sure there is one LayoutInflater per activity/ContextWrapper. For more observations study sources, please ;)

I don't think the quantity of LayoutInflaters really matters (unless you are literally thousands). But, yes, using multiple Inflaters is indeed normal. I use quite a few when working with my adapter views (as in I don't use one static one. Each adapter still only uses one).
If there are places in your code that the adapter doesn't work, you are probably missing something. I would post the code where the Inflater doesn't work.

Related

Many "getContext()" or one private context = getContext() and use it?

I need context many times in my fragment:
...
account.restore(getContext());
...
dbHelper = new DBHelper(getContext());
...
DiskLruBasedCache.ImageCacheParams cacheParams = new DiskLruBasedCache.ImageCacheParams(getContext(), "CacheDirectory");
...
mImageLoader = new SimpleImageLoader(getContext(), cacheParams);
...
Toast.makeText(getContext(), "err: " + error, Toast.LENGTH_LONG).show();
...
RecyclerView.LayoutManager layoutManager = new CustomLayoutManager(getContext());
...
Or should I initialize it once and then use it.
What is best way ?
This is mostly a matter of preference. You can call getContext() wherever you need one -- no cause to be worried about perf overhead. Or you can assign a private Context context field in your onCreate method. Or, if a particular method has multiple uses, create a local variable.
If getContext was potentially slow, then you should definitely have stashed it, but it's really just a simple accessor (almost -- it does one bit of indirection internally).
Go with whatever you find most readable.
In this case, it would be best to call it once and use it. This is due to the fact that the execution will be faster without the extraneous function calls.
It would be common to see
Context context = getContext();
I have done this many times and stored it to a variable in a class. In that case though it looks like this:
class SomeClass {
Context context;
#Override
void onCreate(){
context = getContext();
}
}

How can Main Activity call another Activity A and send its context to it?

My MainActivity calls another Activity A which needs to access some members of MainActivity.
What is the best way to send a reference to Main Activity (or its context) to Activity A without resorting to complicated methods like parcelables etc?
There are some heavyweight android wrestling matches here but I am not sure that it is relevant to my problem.
details
I have Alert and Alerted objects in a one-to-many relationship (Alerted represents the various times an Alert was rung).
AlertsListActivity extends ListActivity which displays a list of Alert objects from a SQLite database table (primary key: alertId). It has an AlertsListAdapter.
AlertedsListActivity has a ListFragment which displays a list of Alerted objects from Alerted table (foreign key is alertId from Alert table).
It has an AlertedsListAdapter.
AlertsListActivity needs to call AlertedsListActivity to display the list of Alerted objects. I used startActivityForResult().
Inside AlertedsListAdapter
public View getView(int position, View convertView, ViewGroup parent) {
final Alert alertItem = (Alert) mainActivity.alertsListAdapter.getItem(position);
final Alerted alertedItem = (Alerted) getItem(position);
...
I do need the Alert objects also, in order to display some identifying information from them with each Alerted list item. Hence I need the reference to mainActivity.alertsListAdapter
How can AlertedsListActivity access AlertsListActivity?
Update: Since I did not get any solutions, I implemented a workaround. The data that I needed to access from Main Activity, I modified. So the Alert object was made a parcelable, and the SQLOpenHelper was made a singleton.
This allows the data to be accessed from Activity A.
Here's the simple, common way to do it:
singletons typically have variables like the below example, "useThisContext" or "mainFeedIsHere".
public class Cloud
{
private static Cloud ourInstance = new Cloud();
private Cloud() { Utils.Log("cloud singleton launched"); }
public synchronized static Cloud getInstance()
{
return ourInstance;
}
/////////////////////////////////////////////////
public Context useThisContext;
another example ...
public class Feed
{
private static Feed ourInstance = new Feed();
private Feed()
{
Utils.Log("feed singleton launched");
freshestPostsForDisplay = new ArrayList<ParseObject>();
}
public synchronized static Feed getInstance()
{
return ourInstance;
}
public List<ParseObject> freshestPosts;
public MainActivity mainFeedIsHere;
Quite simply when everything launches (or when it changes), those "things" need to set those variables in the singleton. In other words, those things "tell the singleton, where they are." It's that simple.
So, in the MainActivity perhaps, in onCreate, it might say something like...
CLOUD.useThisContext = this;
FEED.mainFeedIsHere = this;
Then for example inside Feed.java you may have say
mainFeedIsHere.feedReload();
It goes without saying you have to check that they are not null (but how else could it be?) and you have to keep them up-to-date as it were. (i.e., for whatever reason you may want to change "useThisContext" -- again how else could it be?)
{Sometimes you'll have one "centralised" singleton .. perhaps "State" .. to sort of combine all these together - so that anyone can "get to" any of those "exposed" things as needed. This is, really, how game engines go; so that you can say more or less SoundEffects.Booms() or Tanks.Faster() or AI.FindVillains() at any time anywhere.}
Cheers!
Since I did not get any solutions, I implemented a workaround. The data that I needed to access from Main Activity, I modified. So the Alert object was made a parcelable, and the SQLOpenHelper was made a singleton.
This allows the data to be accessed from Activity A.

How can I get a view from a Context in Android?

in my project I am passing a context of an activity to a helper class. Now, is it possible to use that context and find the views from that activity? Basically, I would like to find the views by id, but just using a context object.
How can I achieve this?
Provided you stored your context in a private reference, do this (MonoDroid)
View parent = ((Activity)_context).Window.DecorView.FindViewById(Android.Resource.Id.Content);
In Raw Android it'd look something like:
View parent = ((Activity)mContext).getWindow().getDecorView().findViewById(android.R.id.content)
Activity is a Context, so if you actually pass your Activity to a helper class, you can just:
void someMethodInHelperClass(Context c) {
if(c instanceof Activity) {
((Activity)c).findViewById(R.id.someviewid);
}
}
Of course it will be much easier if you change your method to:
void someMethodInHelperClass(Activity c) {

Why is Context "becoming" null on Application class?

Problem using Application
I'm rewriting an app (first 'version' had little-to-nothing in terms of analysis and it ended up piling a bunch of problems I wanted to get rid of) and I'm bumping my head against a problem that never showed up in the first version.
Thing is: I have a Class for geographical data. It just supplies String arrays that I can tuck into spinners adapters. Since I used a values xml file, the class needs access to Context to get the proper resources.
Since I use this geographical data in several points of the app, I thought I could create a Class to extend Application and, in onCreate, instantiate the Geography Class, I thought it would be more efficient to load it just once and use it as many times as I wanted. This worked on my first version:
This is MyApplication class
private static Context context;
public void onCreate(){
super.onCreate();
MyApplication.context = getApplicationContext();
geografiaEspana = GeographyClass.getInstance(context);
}
public static GeographyClass getGeografiaEspana() {
if(ctx==null){
Log.w("TAPABOOK", "Tapabook.context nulo");
}
if (geografiaEspana==null){
Log.w("TAPABOOK", "Tapabook.geografiaEspana nula, instanciando");
geografiaEspana = GeographyClass.getInstance(ctx);
}
Log.i("TAPABOOK", "Tapabook.geografiaEspana instanciada");
return geografiaEspana;
}
And this is my GeographyClass
private static GeographyClass instance = null;
public static GeographySpain getInstance(Context context){
if(instance== null){
instance = new GeographySpain(context);
}
return instance;
}
public GeographySpain(Context context){
Resources res = context.getResources();
// load resources data
}
This worked, as I said, ok in my first version. However, in my new version I'm getting a NullPointerException on this line "Resources res = context.getResources();" I've checked and it turns out that the context I'm supplying it's null... And I don't get to understand why or what I'm doing wrong
Ok, I solved it (I'd swear I already commented on this, but since it's gone...).
Thing is, I'm not used to use Application classes and I had forgotten to declare MyApplication in the Manifest file. Noob mistake. As soon as I declared it, the app ran OK

What's the difference between the various methods to get an Android Context?

In various bits of Android code I've seen:
public class MyActivity extends Activity {
public void method() {
mContext = this; // since Activity extends Context
mContext = getApplicationContext();
mContext = getBaseContext();
}
}
However I can't find any decent explanation of which is preferable, and under what circumstances which should be used.
Pointers to documentation on this, and guidance about what might break if the wrong one is chosen, would be much appreciated.
I agree that documentation is sparse when it comes to Contexts in Android, but you can piece together a few facts from various sources.
This blog post on the official Google Android developers blog was written mostly to help address memory leaks, but provides some good information about contexts as well:
In a regular Android application, you
usually have two kinds of Context,
Activity and Application.
Reading the article a little bit further tells about the difference between the two and when you might want to consider using the application Context (Activity.getApplicationContext()) rather than using the Activity context this). Basically the Application context is associated with the Application and will always be the same throughout the life cycle of your app, where as the Activity context is associated with the activity and could possibly be destroyed many times as the activity is destroyed during screen orientation changes and such.
I couldn't find really anything about when to use getBaseContext() other than a post from Dianne Hackborn, one of the Google engineers working on the Android SDK:
Don't use getBaseContext(), just use
the Context you have.
That was from a post on the android-developers newsgroup, you may want to consider asking your question there as well, because a handful of the people working on Android actual monitor that newsgroup and answer questions.
So overall it seems preferable to use the global application context when possible.
Here's what I've found regarding the use of context:
1) . Within an Activity itself, use this for inflating layouts and menus, register context menus, instantiating widgets, start other activities, create new Intent within an Activity, instantiating preferences, or other methods available in an Activity.
Inflate layout:
View mView = this.getLayoutInflater().inflate(R.layout.myLayout, myViewGroup);
Inflate menu:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
this.getMenuInflater().inflate(R.menu.mymenu, menu);
return true;
}
Register context menu:
this.registerForContextMenu(myView);
Instantiate widget:
TextView myTextView = (TextView) this.findViewById(R.id.myTextView);
Start an Activity:
Intent mIntent = new Intent(this, MyActivity.class);
this.startActivity(mIntent);
Instantiate preferences:
SharedPreferences mSharedPreferences = this.getPreferenceManager().getSharedPreferences();
2) . For application-wide class, use getApplicationContext() as this context exist for the lifespan of the application.
Retrieve the name of the current Android package:
public class MyApplication extends Application {
public static String getPackageName() {
String packageName = null;
try {
PackageInfo mPackageInfo = getApplicationContext().getPackageManager().getPackageInfo(getApplicationContext().getPackageName(), 0);
packageName = mPackageInfo.packageName;
} catch (NameNotFoundException e) {
// Log error here.
}
return packageName;
}
}
Bind an application-wide class:
Intent mIntent = new Intent(this, MyPersistent.class);
MyServiceConnection mServiceConnection = new MyServiceConnection();
if (mServiceConnection != null) {
getApplicationContext().bindService(mIntent, mServiceConnection, Context.BIND_AUTO_CREATE);
}
3) . For Listeners and other type of Android classes (e.g. ContentObserver), use a Context substitution like:
mContext = this; // Example 1
mContext = context; // Example 2
where this or context is the context of a class (Activity, etc).
Activity context substitution:
public class MyActivity extends Activity {
private Context mContext;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mContext = this;
}
}
Listener context substitution:
public class MyLocationListener implements LocationListener {
private Context mContext;
public MyLocationListener(Context context) {
mContext = context;
}
}
ContentObserver context substitution:
public class MyContentObserver extends ContentObserver {
private Context mContext;
public MyContentObserver(Handler handler, Context context) {
super(handler);
mContext = context;
}
}
4) . For BroadcastReceiver (including inlined/embedded receiver), use the receiver's own context.
External BroadcastReceiver:
public class MyBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (action.equals(Intent.ACTION_SCREEN_OFF)) {
sendReceiverAction(context, true);
}
private static void sendReceiverAction(Context context, boolean state) {
Intent mIntent = new Intent(context.getClass().getName() + "." + context.getString(R.string.receiver_action));
mIntent.putExtra("extra", state);
context.sendBroadcast(mIntent, null);
}
}
}
Inlined/Embedded BroadcastReceiver:
public class MyActivity extends Activity {
private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
final boolean connected = intent.getBooleanExtra(context.getString(R.string.connected), false);
if (connected) {
// Do something.
}
}
};
}
5) . For Services, use the service's own context.
public class MyService extends Service {
private BroadcastReceiver mBroadcastReceiver;
#Override
public void onCreate() {
super.onCreate();
registerReceiver();
}
private void registerReceiver() {
IntentFilter mIntentFilter = new IntentFilter();
mIntentFilter.addAction(Intent.ACTION_SCREEN_OFF);
this.mBroadcastReceiver = new MyBroadcastReceiver();
this.registerReceiver(this.mBroadcastReceiver, mIntentFilter);
}
}
6) . For Toasts, generally use getApplicationContext(), but where possible, use the context passed from an Activity, Service, etc.
Use context of the application:
Toast mToast = Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG);
mToast.show();
Use context passed from a source:
public static void showLongToast(Context context, String message) {
if (context != null && message != null) {
Toast mToast = Toast.makeText(context, message, Toast.LENGTH_LONG);
mToast.show();
}
}
And last, don't use getBaseContext() as advised by Android's framework developers.
UPDATE: Add examples of Context usage.
I read this thread a few days ago, asking myself the same question. My decision after reading this was simple: always use applicationContext.
However, I encountered a problem with this, I spent a few hours to find it, and a few seconds to solve it... (changing one word...)
I am using a LayoutInflater to inflate a view containing a Spinner.
So here are two possibilities:
1)
LayoutInflater layoutInflater = LayoutInflater.from(this.getApplicationContext());
2)
LayoutInflater layoutInflater = LayoutInflater.from(this.getBaseContext());
Then, I am doing something like this:
// managing views part
View view = ContactViewer.mLayoutInflater.inflate(R.layout.aViewContainingASpinner, theParentView, false);
Spinner spinner = (Spinner) view.findViewById(R.id.theSpinnerId);
String[] myStringArray = new String[] {"sweet","love"};
// managing adapter part
// The context used here don't have any importance -- both work.
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this.getApplicationContext(), myStringArray, android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter);
theParentView.addView(view);
What I noticed: If you instantiated your linearLayout with the applicationContext, then when you click on the spinner in your activity, you will have an uncaught exception, coming from the dalvik virtual machine (not from your code, that's why I have spent a lot of time to find where was my mistake...).
If you use the baseContext, then that's all right, the context menu will open and you will be able to choose among your choices.
So here is my conclusion: I suppose (I have not tested it further) than the baseContext is required when dealing with contextMenu in your Activity...
The test has been done coding with API 8, and tested on an HTC Desire, android 2.3.3.
I hope my comment have not bored you so far, and wish you all the best. Happy coding ;-)
First, I agree that we should use appcontext whenever possible. then "this" in activity. i've never had a need for basecontext.
In my tests, in most cases they can be interchanged. In most cases, the reason you want to get a hold of a context is to access files, preferences, database etc. These data is eventually reflected as files in your app's private data folder (/data/data/). No matter which context you use, they'll be mapped to the same folder/files so you are OK.
That's what I observed. Maybe there are cases you should distinguish them.
In some cases you may use Activity context over application context when running something in a thread. When thread completes execution and you need to return the result back to the caller activity, you need that context with a handler.
((YourActivity) context).yourCallbackMethod(yourResultFromThread, ...);
In simple words
getApplicationContext() as the method name suggest will make your app aware of application wide details which you can access from anywhere in the app. So you can make use of this in service binding, broadcast registration etc. Application context will be alive till the app exits.
getActivity() or this will make your app aware of the current screen which is visible also the app level details provided by application context. So whatever you want to know about the current screen like Window ActionBar Fragementmanger and so are available with this context. Basically and Activity extend Context. This context will alive till the current component(activity) is alive
The confusion stems from the fact that there are numerous ways to
access Context, with (on the surface) no discernible differences.
Below are four of the most common ways you may be able to access
Context in an Activity.
getContext()
getBaseContext()
getApplicationContext()
getActionBar().getThemedContext() //new
What is a Context?
I personally like to think of Context as the state of your application at any given time. The application Context represents a global or base configuration of your application and an Activity or Service can build upon it and represents a configuration instance of your Application or a transitive state for it.
If you look at the source for android.content.Context, you see that Context is an abstract class and the comments on the class are as follows:
Interface to global information about an application environment. This is an abstract class whose implementation is provided by the Android system. It
allows access to application-specific resources and classes, as well as up-calls for application-level operations such as launching activities, broadcasting and receiving intents, etc.
What I take away from this is that Context provides a common implementation to access application level as well as system level resources. Application level resources may be accessing things like String resources [getResources()] or assets [getAssets()] and system-level resource is anything that you access with Context.getSystemService().
As a matter of fact, take a look at the comments on the methods and they seem to reinforce this notion:
getSystemService(): Return the handle to a system-level service by name. The class of the returned object varies by the requested name.
getResources(): Return a Resources instance for your application’s package.
getAssets(): Return a Resources instance for your application’s package.
It may be worth pointing out that in the Context abstract class, all of the above methods are abstract! Only one instance of getSystemService(Class) has an implementation and that invokes an abstract method. This means, the implementation for these should be provided mostly by the implementing classes, which include:
ContextWrapper
Application
Activity
Service
IntentService
Looking at the API documentation, the hierarchy of the classes looks like this:
Context
| — ContextWrapper
|— — Application
| — — ContextThemeWrapper
|— — — — Activity
| — — Service
|— — — IntentService
Since we know that Context itself is not providing any insight, we move down the tree and take a look at the ContextWrapper and realize that there isn't much there either. Since Application extends ContextWrapper, there isn't much to look at over there either since it doesn't override the implementation provided by ContextWrapper. This means that the implementation for Context is provided by the OS and is hidden from the API. You can take a look at the concrete implementation for Context by looking at the source for the ContextImpl class.
I've only used this and getBaseContext when toasting from an onClick (very green noob to both Java and android). I use this when my clicker is directly in the activity and have to use getBaseContext in an anonymous inner clicker. I'm guessing that is pretty much the trick with getBaseContext, it is perhaps returning the context of the activity in which the inner class is hiding.

Categories

Resources