Access application context in a storage class in Android - android

I have an app on Android 4.0. It uses the PreferenceManager class to -- among other things -- let the user specify how many decimal places of a number to show.
mPreferences = PreferenceManager.getDefaultSharedPreferences(this);
Generally I have no problem getting the app context in order to access the Preference Manager. My problem is that I have a class (let's call it Record) that isn't subclassing anything that has the app context; it's just a storage class, but it does have a field "NumDecPlaces". Right now, when I instantiate the class from within my app I just pass in the user's #dec places preference. It would be nice if Record could access the Preference manager directly. I suppose I could always instantiate Record with a pointer to the context from which it was created, but that's a lot to remember ;-)
So right now Record subclasses nothing. Any recommendations on what I can do to it to allow it to see the app context?
Thanks!

You could pass the Context object in the constructor. So whenever you try to use that class it will ask you pass a Context object and then use that to get SharedPreferences
For eg.
public Record(Context context)
{
mContext = context;
mPreferences = PreferenceManager.getDefaultSharedPreferences(mContext)
}

You can also extend a class with Application, which will be global to the whole application and you can set the context in that class as a member variable and that context will be global to the whole application
Eg. class A extends Application{......}

You can do #Apoorv's suggestion or you can create another class that specifically stores the application context.
public class ContextResolver {
private static Context context;
public static void setContext(Context context) {
if (context == null) {
throw new IllegalArgumentException("Context must not be null");
} else if (context instanceof android.app.Activity) {
context = androidContext.getApplicationContext();
} else if (context instanceof android.content.Context) {
context = androidContext;
}
}
public Context getContext() {
return context;
}
}
Now you need to call setContext() in the first activity that will be launched once.
public class MyFirstActivity extends Activity {
public void onCreate() {
ContextResolver.setContext(this);
}
}
Now you can retrieve the Context from any part of your code. So in your Record class you can just do this:
mPreferences = PreferenceManager.getDefaultSharedPreferences(ContextResolver.getContext());

Related

Android Studio context returning null

I have a class that's inputting some data into SharedPreferences.
private static Context context;
context = MainActivity.getContext();
sp = (SharedPreferences) context.getSharedPreferences("currentData", Context.MODE_PRIVATE).edit();
SharedPreferences.Editor editor = sp.edit();
editor.putString("name", placeName);
editor.apply()
I set the context using a method in my MainActivity class:
public static Context getContext(){
return context;
}
However I keep getting a null object reference. Tried multiple solutions from stack overflow and can't overcome the issue.
Why is context returning null?
This is because MainActivity.getContext() is null try passing the context from MainActivity to your class.
public Context context;
public YourClass(Context context) {
this.context= context;
}
In MainActivity init it like this:-
YourClass yours = new YourClass(MainActivity.this);
And also avoid using static contexts it might cause memory leaks !!
Context is an abstract class whose implementation is provided by the
Android system
Context is provided to any Activity by the android system during runtime (Activity indirectly extends Context). You are trying to get Context from MainActivity class via static method, which will not work and will always return null:
context = MainActivity.getContext();
You should always get Context from an instance of Activity, not the class itself. You can do this easily by passing an instance of your current Activity to the constructor of your class. Then, you call getContext() on an INSTANCE of that Activity, not the Activity class itself.
Also, wanted to mention that your code is mostly anti-pattern. You should never store Context in static variables. I'd recommend you read more about Activity lifecycle in android and Context - these are fundamental knowledge.
You can get context statically throughout the application
please try below code:
In the Android Manifest file, declare the following.
<application android:name="com.xyz.MyApplication">
</application>
Use this class
public class MyApplication extends Application {
private static Context context;
public void onCreate() {
super.onCreate();
MyApplication.context = getApplicationContext();
}
public static Context getAppContext() {
return MyApplication.context;
}
}
Now you can call MyApplication.getAppContext() to get your application context statically.
You are getting the context from a static method in the class, that mean that method is called before the class is actually initialized. If there is no actual instance of the activity or if the OS haven't provide with context to the activity, then is null. The Activity has access to the contexto but after the Android underlining management initialized it, the class won't have the context by it self because it is there, if you notice Activities are never instantiated using the constructor because Android does it for you.
If you want to use a static method to having a nice syntax then the static method should be inside the class that use the shared preferences and should be passed from the activity, during any method of the Activity life cycle or when the user interacts with the ui (those listeners are set on the Activity life cycle).
class MyPreferences {
static void save(String toSave, Contex context) {
//TODO your operation here
}
}
And your activity:
public class MainActivity extends AppCompatActivity {
//Below is pseudo code, be careful on doing this precisely in the activity
#Override
onCreate() {
//TODO call super and setContentView
MyPreferences.save("foo", this);
}
}
It seems your problem is you are trying to make the other class to use the Activity, but in Android is the Activity that uses other classes

Singleton with context in library (aar)

I have a library (aar) that needs a context application because it is using some API methods where a context is needed (WifiManager for example).
I saw there and in many other topics that the common way to achieve this is to pass the Context as a parameter to the object of my lib that needs it.
My problem came when reading this article. The lib is to be used by external clients, so I want to avoid all null pointer exception at all cost (you know the rule: if it CAN happen, it WILL happen at some point).
Let's say I have a main entry point in my library, and this class is a Singleton and saves the context (in ctor or via a setter). I would like this class to "host" the Context and behave a little like the Application class: it will provide the context to the other classes of my library.
How can I access this singleton class from the "children" classes or other classes following the principles described in nfrolov's article ?
Let's see some (pseudo) code, with the classes MainSingleton, NetworkManager (singleton too) and DataProvider.
DataProvider can be a member of MainSingleton and doesn't need context, but NetworkManager needs the context to use WIFI_SERVICE and registerReceiver method.
However, DataProvider needs info from NetworkManager, either via registering a listener to it, or getting the data from MainSingleton (that which be used like an event bus to coordinate things between children classes, like we can do with Activities and multiple Fragments).
Case 1
public class MainSingleton
{
private static MainSingleton instance = new MainSingleton();
private static Context context = App.getAppContext(); // where the frog do I get that from ?
...
}
Problem : as this is the main entry point, I don't have access to "App" in here, so it should be passed as a parameter somewhere, as a setter. But then the context is initialized to null ?
Case 2
public class MainSingleton {
private static MainSingleton instance = null;
private Context context;
private MainSingleton(Context context) {
this.context = context;
}
public synchronized static MainSingleton getInstance(Context context) {
if (instance == null) {
instance = new MainSingleton(context.getApplicationContext());
}
return instance;
}
}
Problem: Every "child" instance that need to call the MainSingleton class will need a context too.
Edit
After reading this post: I will most probably consider that my MainEntryPoint is never unloaded when the client application embedding my aar is running, pass the Context as a parameter in an init method and keep that static.
public class ConsumerManager {
private static final ConsumerManager CONSUMER_MANAGER = new ConsumerManager();
private Context context;
public ConsumerManager() {
}
public static ConsumerManager getConsumerManager() {
return CONSUMER_MANAGER;
}
public synchronized void initialize(Context context) {
this.context= context;
}
public boolean isNetworkAvailable() {
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
return activeNetworkInfo != null && activeNetworkInfo.isConnectedOrConnecting();
}
}
First you need to call this from activity.
ConsumerManager.getConsumerManager.initialize(this);
To Check network availability from anywhere you just need to call
ConsumerManager.getConsumerManager.isNetworkAvailable();
[EDITED] Do not place Android context classes in static fields (static reference to ConsumerManager which has field activity pointing to Context); this is a memory leak (and also breaks Instant Run)

Is that possible to get the current context from the non-activity class

I am quite new to Android. In my project, I need to get the context of the current activity which is running, from the Non-activity class.
You can create Context as local variable in non activity class and set this variable from activity from calling constructor like
public class NonActivity {
private Context context;
public NonActivity(Context context) {
this.context = context;
}
}
and create instance of that class from your activity like
NonActivity instance = new NonActivity(CurrentActivity.this);
Edit 1 :: To Check Context Is From Which Activity
Check in NonActivity class if it is from the activity where you want the request from like following
Activity activity = (Activity) context;
if(activity.getClass().getSimpleName().equals(YourActivity.getClass().getSimpleName())) {
// it is from the class you want.
} else {
// not from class
}
hope it'll work.

How to reference the current or main activity from another class

I often find myself needing to access methods that require referencing some activity. For example, to use getWindowManager, I need to access some Activity. But often my code for using these methods is in some other class that has no reference to an activity. Up until now, I've either stored a reference to the main activity or passed the context of some activity to the class. Is there some better way to do this?
If you already have a valid context, just use this:
Activity activity = (Activity) context;
Passing context is better way for refrence Activity.
You can pass Context to another class.
IN Activity ::
AnotherClass Obj = new AnotherClass(this);
IN Another Class
class AnotherClass{
public AnotherClass(Context Context){
}
}
You can implement the necessary methods in your activity and implement a Handler. Then, simply pass a handler instance to your classes, where you can obtain a message for handler and send it to target.
You can make you application instance a singleton, and use it when you need a Context
An example is in this question:
Android Application as Singleton
This way, when you need a Context, you can get it with
Context context = MyApplication.getInstance()
This might not be the cleanest solution, but it has worked well for me so far
I found a way to get the Activity to a non-activity class that I have not seen discussed in forums. This was after numerous failed attempts at using getApplicationContext() and of passing the context in as a parameter to constructors, none of which gave Activity. I saw that my adapters were casting the incoming context to Activity so I made the same cast to my non-activity class constructors:
public class HandleDropdown extends Application{
...
public Activity activity;
...
public HandleDropdown() {
super();
}
public HandleDropdown(Activity context) {
this.activity = context;
this.context = context;
}
public void DropList(View v,Activity context) {
this.activity = context;
this.context = context;
...
}
After doing this cast conversion of Context to Activity I could use this.activity wherever I needed an Activity context.
I'm new to android so my suggestion may look guffy but what if you'll just create a reference to your activity as private property and assign that in OnCreate method? You can even create your CustomActivity with OnCreate like that and derive all your activities from your CustomActivity, not the generic Activity provided by android.
class blah extends Activity{
private Activity activityReference;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
activityReference = this;
}
}
after that you could use that the way you want, i.e. in
Intent i = new Intent(activityReference, SomeOtherActivity.class)
etc
There are many ways for Activities communication.
you can use:
the startActivityForResult method
a system of broadcast message and receiver (you can broadcast an event from the actual activity, and register a receiver in the target activity. Remember that the target activity must be previously initialized and non finished)
as you say, store a reference of the target activity wherever you need.
We built a framework for this. We have a BaseActivity class that inherits from Activity and it overrides all the lifecycle methods and has some static (class) variables that keep track of the activity stack. If anything wants to know what the current activity is, it just calls a static method in BaseActivity that returns the activity on top of our privately-managed stack.
It is kinda hacky, but it works. I'm not sure I would recommend it though.
Handle the Intent in the class you want to do these methods, and send your information to it in a Bundle like so:
Intent i = new Intent("android.intent.action.MAIN");
i.setComponent(new ComponentName("com.my.pkg","com.my.pkg.myActivity"));
Bundle data = new Bundle();
i.putExtras(data);
startActivityForResult(i);
Then use an OnActivityResultListener to grab the new data.
I solved this by making a singleton class has an instance of the class below as a member.
public class InterActivityReferrer <T> {
HashMap<Integer, T> map;
ArrayList<Integer> reserve;
public InterActivityReferrer() {
map = new HashMap<>();
reserve = new ArrayList<>();
}
public synchronized int attach(T obj) {
int id;
if (reserve.isEmpty()) {
id = reserve.size();
}
else {
id = reserve.remove(reserve.size() - 1);
}
map.put(id, obj);
return id;
}
public synchronized T get(int id) {
return map.get(id);
}
public synchronized T detach(int id) {
T obj = map.remove(id);
if (obj != null) reserve.add(id);
return obj;
}
}
This class can get a T object and return a unique integer assigned to the object by attach(). Assigned integers will not collide with each other unless HashMap fails. Each assigned integer will be freed when its corresponding object is detached by detach(). Freed integers will be reused when a new object is attached.
And from a singleton class:
public class SomeSingleton {
...
private InterActivityReferrer<Activity> referrer = new InterActivityReferrer<>();
...
public InterActivityReferrer<Activity> getReferrer() {return referrer;}
}
And from an activity that needs to be referred:
...
int activityID = SomeSingleton.getInstance().getReferrer().attach(this);
...
Now with this, a unique integer corresponding to this activity instance is returned. And an integer can be delivered into another starting activity by using Intent and putExtra().
...
Intent i = new Intent(this, AnotherActivity.class);
i.putExtra("thisActivityID", activityID);
startActivityForResult(i, SOME_INTEGER);
...
And from the another activity:
...
id refereeID = getIntent().getIntExtra("thisActivityID", -1);
Activity referredActivity = SomeSingleton.getInstance().getReferrer().get(refereeID);
...
And finally the activity can be referred. And InterActivityReferrer can be used for any other class.
I hope this helps.
public static Activity getLaunchActivity()
{
final Class<?> activityThreadClass = Class.forName("android.app.ActivityThread");
final Method methodApp = activityThreadClass.getMethod("currentApplication");
App = (Application) methodApp.invoke(null, (Object[]) null);
Intent launcherIntent = App.getPackageManager().getLaunchIntentForPackage(App.getPackageName());
launchActivityInfo = launcherIntent.resolveActivityInfo(App.getPackageManager(), 0);
Class<?> clazz;
try
{
clazz = Class.forName(launchActivityInfo.name);
if(clazz != null)
return Activity.class.cast(clazz.newInstance());
}
catch (Exception e)
{}
return null;
}
Just a guess since I haven't done this but it might work.
1) Get your applicationContext by making your Android Application class a Singleton.
2) Get your ActivityManager class from the context.
3) Get a list of RunningTaskInfos using getRunningTasks() on the ActivityManager.
4) Get the first RunningTaskInfo element from the list which should be the most recent task launched.
5) Call topActivity on that RunningTaskInfo which should return you the top activity on the activity stack for that task.
Now, this seems like a LOT more work than any of the other methods mentioned here, but you can probably encapsulate this in a static class and just call it whenever. It seems like it might be the only way to get the top activity on the stack without adding references to the activities.

Best practice to pass Context to non-activity classes?

So, my first major application is almost coded and I'm doing optimizations on my code. The app works fine, but I'm not sure about my way of passing the context to other classes. I don't want to do it the wrong way. I stumbled upon articles and questions here in Stackoverflow about contexts and which is the right way to pass it to non-activity classes. I read the documentation as well, but being a Finn makes complicated tech speak even harder to understand.
So, a simple question. Is my way of passing my main activity's context to other (helper) classes correct? If not, where can I read more about better practice on these situations.
For example:
MainActivity.java
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle sis){
super(sis);
new Helper(MyActivity.this).makeMyAppAwesome();
}
}
Helper.java
public class Helper {
Context context;
Helper(Context ctx){
this.context = ctx;
}
public void makeMyAppAwesome(){
makeBaconAndEggsWithMeltedCheese(context);
}
}
Is this OK? It would be nice if someone could provide an easy to read article with examples on this subject.
You can do that using ContextWrapper, as described here.
For example:
public class MyContextWrapper extends ContextWrapper {
public MyContextWrapper(Context base) {
super(base);
}
public void makeMyAppAwesome(){
makeBaconAndEggsWithMeltedCheese(this);
}
}
And call the non activity class like this from an Activity
new MyContextWrapper(this);
It is usually in your best interest to just pass the current context at the moment it is needed. Storing it in a member variable will likely lead to leaked memory, and start causing issues as you build out more Activities and Services in your app.
public void iNeedContext(Context context) {...
Also, in any class that has context, I'd recommend making a member variable for readability and searchability, rather than directly passing or (ClassName.)this. For example in MainActivity.java:
Context mContext = MainActivity.this;
Activity mActivity = MainActivity.this;
I have passed context like this which solved my problem:
public class Utils extends ContextWrapper {
private final Context context;
public Utils(Context context) {
super(context);
this.context = context;
}
public void mymethod(){}
}
super(context); with ContextWrapper helped to make getBaseContext() and getApplicationContext() valid and this.context = context; captured context in variable which I can use wherever needed in methods.
Maybe alternatively you can just opt for using a constructor with this.context = context; and replace all occurrences of getApplicationContext() and getBaseContext().
Well, an even better way is to pass context directly to the method if using only few from a class for avoiding memory leaks.
You could also create a static instance reference to your MainActivity initialized in the onCreate() method
public class MainActivity extends AppCompatActivity {
public static MainActivity mMainActivity;
#Override
private onCreate(Bundle savedInstanceState){
//...
mMainActivity = this;
}
}
and call the context like this:
MainActivity.mMainActivity;
or write a method getInstanceOf() if it's clearer and/or you prefer using an accessor
MainActivity.getInstanceOf();
This strategy might provide you with some flexibility if you decide later that you would like to call an instance method contained in your main activity like so:
MainActivity.mMainActivity.myInstanceMethod();
Just a suggestion. Criticism is welcome and encouraged.

Categories

Resources