From MyActivity, call to:
MyClass.getInstance();
MyClass.doStuff();
...
#EBean(scope = EBean.Scope.Singleton)
public class MyClass {
#Bean
MyManager manager;
public static void doStuff(){
manager.show();
// null pointer exception for the manager why ? how to access it ?
}
public static MyClass getInstance() {
if (_instance == null) {
_instance = new MyClass();
}
return _instance;
}
}
...
#EBean(scope = EBean.Scope.Singleton)
public class MyManager {
public void show(){ }
}
Android annotations access singleton class object into other class static method. Note : AA version 3.3.1
I am afraid you are using AA #EBean incorrectly. Did you read the documentation?
You do not have to write a getInstance() method yourself, AA will generate the appropriate method, do the injections in it, and automatically call it when injecting the bean into other components. You got a NullPointerException because you created the bean with your own getInstance() method, so no AA injections were performed. But actually you are getting a compile error in doStuff(), because you are accessing an instance field in a static method... So i assume the manager field is static, right? You should not use static fields/methods in singletons, the concept of the singleton is one instance is existing only, so using static fields/methods is redundant and also confusing.
You can fix the problem by either:
Creating an instance of MyClass by calling MyClass_.getInstance(context) manually, then use it
Inject a MyClass instance into another component with the #Bean annotation and use it from there
Related
I have a class called myConstants and in it i list all my constants so when i need them I just reference MyConstants.MYCONSTANT. However, i would like to implement something like this for methods. i am repeating a lot of code, for instance, i have a formatCalendarString(Calendar c) method in 3 activities. seems redundant and unecessary. but i cant make them static because i get static calling non-static errors and the only other way i can think is to make a MyConstant object then call public functions off that object, like this...
MyConstants myConstants = new MyConstants();
myConstants.formatCalendarString(Calendar.getInstance());
is there some way i can just call the formatCalendarString() inside MyConstants class without generating an object?
You can use singleton pattern to cache instances. Keeping methods in something like parent activity does not make any sense (as primary role of activity is user interaction).
Example:
public class MyConstants {
private static MyConstants ourInstance;
private MyConstants() {
//private constructor to limit direct instantiation
}
public synchronized static MyConstants getInstance() {
//if null then only create instance
if (ourInstance ==null) {
ourInstance = new MyConstants();
}
//otherwise return cached instance
return ourInstance;
}
}
You just need a private constructor and public static method that would only generate instance if it is null.
Then, call MyConstants.getInstance().whateverMethod(). It will create only single instance.
However when using singleton, please keep memory leaks in mind. Do not pass activity context directly inside singletons.
If you want to have all methods in activities, you can put then in abstract class BaseActivity, which extends Activity, and then make your activities extends BaseActivity. However, if these methods doesn't correspond to something about activity, I suggest some Singleton or Util class
I agree with Pier Giorgio Misley. It's also good to add a private constructor, because you don't obviously want to instantiate an object.
Can't you just use a parent class? That way you can just inherit the methods and manage in one source. Then you don't have to use static functions then.
Edit: Like Tomasz Czura said, just extend the Class.
public class ParentClass {
public void commonMethod(){
}
}
public class OtherClass extends ParentClass{
}
You can use the Static keyword.
Static methods can be referenced from outside without istantiating the new object.
Just create a class:
public class MyClassContainingMethods{
public static String MyStaticMethod(){
return "I am static!";
}
}
Now call it like
String res = MyClassContainingStaticMethods.MyStaticMethod();
Hope this helps
NOTE
You CAN call non-static from static by doing something like this:
public static void First_function(Context context)
{
SMS sms = new SMS();
sms.Second_function(context);
}
public void Second_function(Context context)
{
Toast.makeText(context,"Hello",1).show(); // This i anable to display and cause crash
}
Example taken from here, you will obiouvsly have to fit it into your needs
I am trying to access application resources, (string resources to be specific) from a Singleton class. Being Singleton, this class cannot hold any reference to Context objects (to prevent memory leak). While I was looking for other implementations on the net, I came across this two implementation:
Create a static context in Application class and use it across the app.
Pass context as a parameter to the method that requires it.
I don't want to use the fist one as it also uses a static reference to Context object. I understand that it's ok to have it statically in the Application class of android, but still it looks like a hack.
The second implementation is useless since i don't have any instance of context which I can pass to the someOtherMethod of the singleton.
So I came up with following implementation where I make my Singleton abstract to override its context requiring methods (for ex. getString(int resId) in the code below) when I initialize the singleton instance.
I am curious to know if this can lead to any memory leaks now?
Where am I confused with this approach:
--> The reference to context in the Overridden getString is final. I am not sure if that can cause a memory leak or not.
public abstract class SingletonClass{
.
.
.
private static SingletonClass sInstance;
private SingletonClass(Context paramContext) {
// constructor code
}
public static SingletonClass getInstance(final Context context) {
if (sInstance == null) {
sInstance = new SingletonClass(context){
#Override
public String getString(int resId) {
return context.getString(resId);
}
};
}
return sInstance;
}
public abstract String getString(int resId);
.
.
.
private void someOtherMethod(){
//uses above getString()
}
}
Your approach does have a memory leak. The first context passed into getInstance will never be garbage collected, since your anonymous class holds a reference to it. (and there is a static reference to the anonymous class). e.g., if you call getInstance(Activity), that activity will remain in memory until the process is killed!
Fortunately there is a pretty easy fix to get rid of the memory leak. You can safely hold onto the application context (context.getApplicationContext), which is basically a singleton context for lifetime of the app.
public static SingletonClass getInstance(Context c) {
if (sInstance == null) {
sInstance = new SingletonClass(c.getApplicationContext());
}
return sInstance;
}
You can depend on activity lifecycle, and require activities to pass reference to your singleton object in onResume method, and clean it in onPause.
protected void onResume() {
super.onResume();
Singleton.getInstance().onResume(this);
}
protected void onPause() {
super.onResume();
Singleton.getInstance().onPause();
}
Also, you can refresh the instance of Context and hold it in WeakReference:
class Singleton {
private WeakReference<Context> mContext;
private boolean hasContext() {
return mContext != null && mContext.get() != null;
}
public static Singleton getInstance(Context c) {
//do your singleton lazy
if (!sInstance.hasInstance()) {
sInstance.mContext = new WeakReference<>(c);
}
return sInstance;
}
}
Second case could hold a reference to finishing activity, so i don't suggest it.
I am stuck in a problem. I am creating a helper class that needs to be Singleton. And that class has a global context variable. I am not able to do this since context is available only from onCreate and this Singleton instance is created much before since it is static.
Can someone help me on how to solve this issue. Context is needed for the Singleton instance finally.
public class Helper {
private static Helper sHelper = new Helper() ;
private Helper () {} ;
public static Helper getInstance() {
return sHelper;
}
public boolean doSomething() {
mContext.getContentResolver;
return isDone;
}
}
You can set the context to be you ApplicationContext.
You can create an Application class and implement something like:
yourSingletonClass.getInstance().setContext(this);
This call should be in you application class under the onCreate method.
For more information try this docs:
Android - Application class
You just need to pass the following context to your helper class.
getApplicationContext()
You need pass the context trougth your construct helper class:
getApplicationContext()
I have followed this link and successfully made singleton class in Android.
http://www.devahead.com/blog/2011/06/extending-the-android-application-class-and-dealing-with-singleton/
Problem is that i want a single object. like i have Activity A and Activity B. In Activity A I access the object from Singleton class. I use the object and made some changes to it.
When I move to Activity B and access the object from Singleton Class it gave me the initialized object and does not keep the changes which i have made in Activity A.
Is there any other way to save the changing?
Please help me Experts.
This is MainActivity
public class MainActivity extends Activity {
protected MyApplication app;
private OnClickListener btn2=new OnClickListener() {
#Override
public void onClick(View arg0) {
Intent intent=new Intent(MainActivity.this,NextActivity.class);
startActivity(intent);
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Get the application instance
app = (MyApplication)getApplication();
// Call a custom application method
app.customAppMethod();
// Call a custom method in MySingleton
Singleton.getInstance().customSingletonMethod();
Singleton.getInstance();
// Read the value of a variable in MySingleton
String singletonVar = Singleton.customVar;
Log.d("Test",singletonVar);
singletonVar="World";
Log.d("Test",singletonVar);
Button btn=(Button)findViewById(R.id.button1);
btn.setOnClickListener(btn2);
}
}
This is NextActivity
public class NextActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_next);
String singletonVar = Singleton.customVar;
Log.d("Test",singletonVar);
}
}
Singleton Class
public class Singleton
{
private static Singleton instance;
public static String customVar="Hello";
public static void initInstance()
{
if (instance == null)
{
// Create the instance
instance = new Singleton();
}
}
public static Singleton getInstance()
{
// Return the instance
return instance;
}
private Singleton()
{
// Constructor hidden because this is a singleton
}
public void customSingletonMethod()
{
// Custom method
}
}
and MyApplication
public class MyApplication extends Application
{
#Override
public void onCreate()
{
super.onCreate();
// Initialize the singletons so their instances
// are bound to the application process.
initSingletons();
}
protected void initSingletons()
{
// Initialize the instance of MySingleton
Singleton.initInstance();
}
public void customAppMethod()
{
// Custom application method
}
}
When i run this code, i get Hello which i have initialized in Singleton then World which i gave it in MainActivity and again shows Hello in NextActivity in logcat.
I want it to show world again in NextActivity.
Please help me to correct this.
Tip: To create singleton class In Android Studio, right click in your project and open menu:
New -> Java Class -> Choose Singleton from dropdown menu
EDIT :
The implementation of a Singleton in Android is not "safe" (see here) and you should use a library dedicated to this kind of pattern like Dagger or other DI library to manage the lifecycle and the injection.
Could you post an example from your code ?
Take a look at this gist : https://gist.github.com/Akayh/5566992
it works but it was done very quickly :
MyActivity : set the singleton for the first time + initialize mString attribute ("Hello") in private constructor and show the value ("Hello")
Set new value to mString : "Singleton"
Launch activityB and show the mString value. "Singleton" appears...
It is simple, as a java, Android also supporting singleton. -
Singleton is a part of Gang of Four design pattern and it is categorized under creational design patterns.
-> Static member : This contains the instance of the singleton class.
-> Private constructor : This will prevent anybody else to instantiate the Singleton class.
-> Static public method : This provides the global point of access to the Singleton object and returns the instance to the client calling class.
create private instance
create private constructor
use getInstance() of Singleton class
public class Logger{
private static Logger objLogger;
private Logger(){
//ToDo here
}
public static Logger getInstance()
{
if (objLogger == null)
{
objLogger = new Logger();
}
return objLogger;
}
}
while use singleton -
Logger.getInstance();
answer suggested by rakesh is great but still with some discription
Singleton in Android is the same as Singleton in Java:
The Singleton design pattern addresses all of these concerns. With the Singleton design pattern you can:
1) Ensure that only one instance of a class is created
2) Provide a global point of access to the object
3) Allow multiple instances in the future without affecting a
singleton class's clients
A basic Singleton class example:
public class MySingleton
{
private static MySingleton _instance;
private MySingleton()
{
}
public static MySingleton getInstance()
{
if (_instance == null)
{
_instance = new MySingleton();
}
return _instance;
}
}
As #Lazy stated in this answer, you can create a singleton from a template in Android Studio. It is worth noting that there is no need to check if the instance is null because the static ourInstance variable is initialized first. As a result, the singleton class implementation created by Android Studio is as simple as following code:
public class MySingleton {
private static MySingleton ourInstance = new MySingleton();
public static MySingleton getInstance() {
return ourInstance;
}
private MySingleton() {
}
}
You are copying singleton's customVar into a singletonVar variable and changing that variable does not affect the original value in singleton.
// This does not update singleton variable
// It just assigns value of your local variable
Log.d("Test",singletonVar);
singletonVar="World";
Log.d("Test",singletonVar);
// This actually assigns value of variable in singleton
Singleton.customVar = singletonVar;
I put my version of Singleton below:
public class SingletonDemo {
private static SingletonDemo instance = null;
private static Context context;
/**
* To initialize the class. It must be called before call the method getInstance()
* #param ctx The Context used
*/
public static void initialize(Context ctx) {
context = ctx;
}
/**
* Check if the class has been initialized
* #return true if the class has been initialized
* false Otherwise
*/
public static boolean hasBeenInitialized() {
return context != null;
}
/**
* The private constructor. Here you can use the context to initialize your variables.
*/
private SingletonDemo() {
// Use context to initialize the variables.
}
/**
* The main method used to get the instance
*/
public static synchronized SingletonDemo getInstance() {
if (context == null) {
throw new IllegalArgumentException("Impossible to get the instance. This class must be initialized before");
}
if (instance == null) {
instance = new SingletonDemo();
}
return instance;
}
#Override
protected Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException("Clone is not allowed.");
}
}
Note that the method initialize could be called in the main class(Splash) and the method getInstance could be called from other classes. This will fix the problem when the caller class requires the singleton but it does not have the context.
Finally the method hasBeenInitialized is uses to check if the class has been initialized. This will avoid that different instances have different contexts.
The most clean and modern way to use singletons in Android is just to use the Dependency Injection framework called Dagger 2. Here you have an explanation of possible scopes you can use. Singleton is one of these scopes. Dependency Injection is not that easy but you shall invest a bit of your time to understand it. It also makes testing easier.
In an Android app, is there anything wrong with the following approach:
public class MyApp extends android.app.Application {
private static MyApp instance;
public MyApp() {
instance = this;
}
public static Context getContext() {
return instance;
}
}
and pass it everywhere (e.g. SQLiteOpenHelper) where context is required (and not leaking of course)?
There are a couple of potential problems with this approach, though in a lot of circumstances (such as your example) it will work well.
In particular you should be careful when dealing with anything that deals with the GUI that requires a Context. For example, if you pass the application Context into the LayoutInflater you will get an Exception. Generally speaking, your approach is excellent: it's good practice to use an Activity's Context within that Activity, and the Application Context when passing a context beyond the scope of an Activity to avoid memory leaks.
Also, as an alternative to your pattern you can use the shortcut of calling getApplicationContext() on a Context object (such as an Activity) to get the Application Context.
In my experience this approach shouldn't be necessary. If you need the context for anything you can usually get it via a call to View.getContext() and using the Context obtained there you can call Context.getApplicationContext() to get the Application context. If you are trying to get the Application context this from an Activity you can always call Activity.getApplication() which should be able to be passed as the Context needed for a call to SQLiteOpenHelper().
Overall there doesn't seem to be a problem with your approach for this situation, but when dealing with Context just make sure you are not leaking memory anywhere as described on the official Google Android Developers blog.
Some people have asked: how can the singleton return a null pointer?
I'm answering that question. (I cannot answer in a comment because I need to post code.)
It may return null in between two events: (1) the class is loaded, and (2) the object of this class is created. Here's an example:
class X {
static X xinstance;
static Y yinstance = Y.yinstance;
X() {xinstance=this;}
}
class Y {
static X xinstance = X.xinstance;
static Y yinstance;
Y() {yinstance=this;}
}
public class A {
public static void main(String[] p) {
X x = new X();
Y y = new Y();
System.out.println("x:"+X.xinstance+" y:"+Y.yinstance);
System.out.println("x:"+Y.xinstance+" y:"+X.yinstance);
}
}
Let's run the code:
$ javac A.java
$ java A
x:X#a63599 y:Y#9036e
x:null y:null
The second line shows that Y.xinstance and X.yinstance are null; they are null because the variables X.xinstance ans Y.yinstance were read when they were null.
Can this be fixed? Yes,
class X {
static Y y = Y.getInstance();
static X theinstance;
static X getInstance() {if(theinstance==null) {theinstance = new X();} return theinstance;}
}
class Y {
static X x = X.getInstance();
static Y theinstance;
static Y getInstance() {if(theinstance==null) {theinstance = new Y();} return theinstance;}
}
public class A {
public static void main(String[] p) {
System.out.println("x:"+X.getInstance()+" y:"+Y.getInstance());
System.out.println("x:"+Y.x+" y:"+X.y);
}
}
and this code shows no anomaly:
$ javac A.java
$ java A
x:X#1c059f6 y:Y#152506e
x:X#1c059f6 y:Y#152506e
BUT this is not an option for the Android Application object: the programmer does not control the time when it is created.
Once again: the difference between the first example and the second one is that the second example creates an instance if the static pointer is null. But a programmer cannot create the Android application object before the system decides to do it.
UPDATE
One more puzzling example where initialized static fields happen to be null.
Main.java:
enum MyEnum {
FIRST,SECOND;
private static String prefix="<", suffix=">";
String myName;
MyEnum() {
myName = makeMyName();
}
String makeMyName() {
return prefix + name() + suffix;
}
String getMyName() {
return myName;
}
}
public class Main {
public static void main(String args[]) {
System.out.println("first: "+MyEnum.FIRST+" second: "+MyEnum.SECOND);
System.out.println("first: "+MyEnum.FIRST.makeMyName()+" second: "+MyEnum.SECOND.makeMyName());
System.out.println("first: "+MyEnum.FIRST.getMyName()+" second: "+MyEnum.SECOND.getMyName());
}
}
And you get:
$ javac Main.java
$ java Main
first: FIRST second: SECOND
first: <FIRST> second: <SECOND>
first: nullFIRSTnull second: nullSECONDnull
Note that you cannot move the static variable declaration one line upper, the code will not compile.
Application Class:
import android.app.Application;
import android.content.Context;
public class MyApplication extends Application {
private static Context mContext;
public void onCreate() {
super.onCreate();
mContext = getApplicationContext();
}
public static Context getAppContext() {
return mContext;
}
}
Declare the Application in the AndroidManifest:
<application android:name=".MyApplication"
...
/>
Usage:
MyApplication.getAppContext()
You are trying to create a wrapper to get Application Context and there is a possibility that it might return "null" pointer.
As per my understanding, I guess its better approach to call- any of the 2
Context.getApplicationContext() or Activity.getApplication().
It is a good approach. I use it myself as well. I would only suggest to override onCreate to set the singleton instead of using a constructor.
And since you mentioned SQLiteOpenHelper: In onCreate () you can open the database as well.
Personally I think the documentation got it wrong in saying that There is normally no need to subclass Application. I think the opposite is true: You should always subclass Application.
I would use Application Context to get a System Service in the constructor. This eases testing & benefits from composition
public class MyActivity extends Activity {
private final NotificationManager notificationManager;
public MyActivity() {
this(MyApp.getContext().getSystemService(NOTIFICATION_SERVICE));
}
public MyActivity(NotificationManager notificationManager) {
this.notificationManager = notificationManager;
}
// onCreate etc
}
Test class would then use the overloaded constructor.
Android would use the default constructor.
I like it, but I would suggest a singleton instead:
package com.mobidrone;
import android.app.Application;
import android.content.Context;
public class ApplicationContext extends Application
{
private static ApplicationContext instance = null;
private ApplicationContext()
{
instance = this;
}
public static Context getInstance()
{
if (null == instance)
{
instance = new ApplicationContext();
}
return instance;
}
}
I'm using the same approach, I suggest to write the singleton a little better:
public static MyApp getInstance() {
if (instance == null) {
synchronized (MyApp.class) {
if (instance == null) {
instance = new MyApp ();
}
}
}
return instance;
}
but I'm not using everywhere, I use getContext() and getApplicationContext() where I can do it!
I know the original question was posted 13 years ago, and this is the Kotlin version of getting context everywhere.
class MyApplication : Application() {
companion object {
#JvmStatic
private var instance: MyApplication? = null
#JvmStatic
public final fun getContext(): Context? {
return instance
}
}
override fun onCreate() {
instance = this
super.onCreate()
}
}